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

前端 未结 3 1864
别那么骄傲
别那么骄傲 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

    I had to do something similar in an app of mine. I took what I came up with and changed it around a bit, but I haven't tested it, so use with care. It's not pretty, but it's better than anything else I was able to think of.

    In routes.rb:

    resources :posts, :pictures
    
    controller :comments do
      get '*path/edit' => :edit, :as => :edit_comment
      get '*path'      => :show, :as => :comment
      # etc. The order of these is important. If #show came first, it would direct /edit to #show and simply tack on '/edit' to the path param.
    end
    

    In comment.rb:

    embedded_in :commentable, :inverse_of => :comments
    
    def to_param
      [commentable.class.to_s.downcase.pluralize, commentable.id, 'comments', id].join '/'
    end
    

    In a before filter in comments_controller.rb:

    parent_type, parent_id, scrap, id = params[:path].split '/'
    
    # Security: Make sure people can't just pass in whatever models they feel like
    raise "Uh-oh!" unless %w(posts pictures).include? parent_type
    
    @parent = parent_type.singularize.capitalize.constantize.find(parent_id)
    @comment = @parent.comments.find(id)
    

    Ok, ugliness over. Now you can add comments to whatever models you want, and simply do:

    edit_comment_path @comment
    url_for @comment
    redirect_to @comment
    

    And so on.

    Edit: I didn't implement any other paths in my own app, because all I needed was edit and update, but I'd imagine they'd look something like:

    controller :comments do
      get    '*path/edit' => :edit, :as => :edit_comment
      get    '*path'      => :show, :as => :comment
      put    '*path'      => :update
      delete '*path'      => :destroy
    end
    

    The other actions will be trickier. You'll probably need to do something like:

      get  ':parent_type/:parent_id/comments'     => :index, :as => :comments
      post ':parent_type/:parent_id/comments'     => :create
      get  ':parent_type/:parent_id/comments/new' => :new,   :as => :new_comment
    

    You'd then access the parent model in the controller using params[:parent_type] and params[:parent_id]. You'd also need to pass the proper parameters to the url helpers:

    comments_path('pictures', 7)
    

提交回复
热议问题