Does anybody have any tips for managing polymorphic nested resources in Rails 3?

前端 未结 3 1854
别那么骄傲
别那么骄傲 2021-02-09 08:30

In config/routes.rb:

resources :posts do
  resources :comments
end

resources :pictures do
  resources :comments
end

I would like to allow for

3条回答
  •  独厮守ぢ
    2021-02-09 08:46

    Ryan Bates covered polymorphic associations in Railscasts #154, but the example was for Rails 2 and Active Record. I managed to get his example working using Rails 3 and Mongoid by making a few changes.

    In the Post and Picture models, add the following line:

    embeds_many :comments, :as => :commentable
    

    According to the Mongoid associations documentation, all embedded_in associations are polymorphic. You don't need the commentable_id and commentable_type columns mentioned in the Railscast when using Mongoid, because the comment is a child of the commentable. In the Comment model, add the following line:

    embedded_in :commentable, :inverse_of => :comment
    

    Setup the routes in config/routes.rb like this:

    resources posts do
      resources comments
    end
    
    resources pictures do
      resources comments
    end
    

    Add the following method to your comments controller as a private method. This is identical to Ryan's method:

    def find_commentable  
      params.each do |name, value|  
        if name =~ /(.+)_id$/  
          return $1.classify.constantize.find(value)  
        end  
      end  
      nil  
    end
    

    In each of your comments controller actions where you need to find the comment, call the find_commentable method first to get the parent. Once the parent has been found, you can find the comment by ID, by searching through the commentable's comments. For example, in the edit action the code to find the comment would look like this:

    @commentable = find_commentable  
    @comment = @commentable.comments.find(params[:id])
    

    To reduce the repetition of calling find_commentable at the start of every action, you could put a before filter at the top of the controller like this:

    class CommentsController < ApplicationController
      before_filter :find_commentable
      ...
    

    And then change the return call in the find_commentable method to:

    return @commentable = $1.classify.constantize.find(value)
    

    I haven't encountered any problems using this method, but if you come across any issues please point them out.

提交回复
热议问题