Rails 3.1: Полиморфная ассоциация @commentable - как это сделать правильно? - PullRequest
2 голосов
/ 14 ноября 2011

У меня проблемы с полиморфной ассоциацией в Rails. У меня есть приложение, где должна быть возможность комментировать разные модели, например Posts, Images, Projects

Прямо сейчас у меня есть только сообщения, чтобы комментировать. На стартовой странице есть индексное представление последних сообщений, и у каждого сообщения есть небольшая форма комментария, чтобы комментировать через Ajax, очень похоже на Facebook.

Мои модели выглядят так:

class Post < ActiveRecord::Base
  belongs_to :post_category
  belongs_to :user

  has_many :comments, :as => :commentable  

  validates_presence_of :user_id
  validates_presence_of :post_category_id
  validates_presence_of :title
  validates_presence_of :body

end

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :commentable, :polymorphic => true
end

Теперь в моем контроллере комментариев я добавил следующий метод (я думаю, что я взял его из Railscasts или что-то в этом роде), который, как я предполагаю, пытается динамически определить @commentable при создании комментария. Но это всегда возвращает ошибку undefined method comments 'для nil: NilClass`

   # find commentable (parent) item
   def find_commentable
      params.each do |name, value|
        if name =~ /(.+)_id$/
           return $1.classify.constantize.find(value) unless name == 'user_id'
        end
      end
      nil
   end

  def create
    @commentable = find_commentable 
    @comment = @commentable.comments.build(params[:comment])
    if @comment.save
      redirect_to @comment, :notice => 'Comment was successfully created.'
      redirect_to :id => nil 
    else
      render :action => "new"
    end
  end

Две вещи, которые я пробовал в своей части, были:

  1. оставляя комментируемую информацию вне формы

    = form_for [@commentable, Comment.new],: remote => true do | f | # new_comment.add_comment = f.hidden_field: user_id,: value => current_user.id = f.text_field: content,: size => 55,: value => 'оставить комментарий ...',: class => 'comment_form' = f.submit "отправить"

и 2. передача commentable_id и commentable_type

= form_for [@commentable, Comment.new], :remote => true do |f|
    #new_comment.add_comment
        = f.hidden_field :user_id, :value => current_user.id
        = f.hidden_field :commentable_id, :value => post_id
        = f.hidden_field :commentable_type, :value => 'Post'
        = f.text_field :content, :size => 55,  :value => 'leave a comment...', :onfocus => 'this.select()', :class => 'comment_form'
        = f.submit "send" 

оба без везения. Любая помощь будет высоко оценен. весь код контроллера комментариев находится в этой сущности: https://gist.github.com/1334286

Ответы [ 2 ]

2 голосов
/ 14 ноября 2011

Кажется, что комментарий не назначен правильно в контроллере комментариев. Это может иметь несколько причин. Вот настройка, которая должна работать для вас:

В контроллере сообщений, например Акция «Шоу»:

@post = Post.find(params[:id])

В постах / показе вид комментариев:

= form_for [@post, @post.comments.new], :remote => true do |f|

Вы должны иметь возможность использовать свой контроллер комментариев как есть, но вы должны изменить render, например, на. redirect_to :back в действии create, поскольку контроллер комментариев, скорее всего, не будет иметь "нового" представления самостоятельно (это зависит от комментируемого)

Кроме того, убедитесь, что у вас есть вложенные маршруты для всех ресурсов, которые могут выступать в качестве комментариев, например:

resources :posts do
  resources :comments do
end

resources :comments do
  resources :comments # subomments
end

ОБНОВЛЕНО для отражения информации в комментариях

0 голосов
/ 18 ноября 2012

Не используйте @commentable в представлении пост-шоу, поскольку оно определено только в контроллере комментариев.

Сделайте это вместо:

_comment.html.erb: (частичный комментарий в представлении пост-шоу)

  <%= form_for ([comments, @vote]), remote: true do |f| %>

сообщений / posts_controller.rb:

  <%= form_for ([@post, @vote]), remote: true do |f| %>
...