在config / routes.rb中:
resources :posts do
resources :comments
end
resources :pictures do
resources :comments
end
我想允许更多的事情被评论。
我目前正在使用mongoid(mongomapper并不像我想的那样与Rails 3兼容),而注释是一个嵌入式资源(mongoid还不能处理多态关系资源),这意味着我需要父资源才能找到评论。
是否有任何优雅的方法可以解决以下一些问题:
在我的控制器中,我需要在找到评论之前找到父母:
if params[:post_id]
parent = Post.find(params[:post_id]
else if params[:picture_id]
parent = Picture.find(params[:picture_id]
end
如果我开始添加更多可以评论的内容,那将会变得混乱。
同样url_for([comment.parent, comment])
不起作用,所以我将不得不在我的Comment
模型中定义一些内容,但我认为我还需要在Comment
模型以及可能的编辑和新路线定义。
随着我的进一步发展,我可能会遇到更多问题。
我无法想象我是第一个尝试解决这个问题的人,是否有任何解决方案可以使其更易于管理?
答案 0 :(得分:4)
我必须在我的应用程序中做类似的事情。我拿出了我想出的东西并稍微改了一下,但我还没有测试过,所以请小心使用。它并不漂亮,但它比我能想到的任何其他东西都要好。
在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
在comment.rb中:
embedded_in :commentable, :inverse_of => :comments
def to_param
[commentable.class.to_s.downcase.pluralize, commentable.id, 'comments', id].join '/'
end
在comments_controller.rb中的before过滤器中:
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)
好的,丑陋的。现在,您可以为所需的任何模型添加注释,只需执行以下操作:
edit_comment_path @comment
url_for @comment
redirect_to @comment
等等。
编辑:我没有在我自己的应用程序中实现任何其他路径,因为我需要的只是编辑和更新,但我想他们看起来像:
controller :comments do
get '*path/edit' => :edit, :as => :edit_comment
get '*path' => :show, :as => :comment
put '*path' => :update
delete '*path' => :destroy
end
其他行动将更加棘手。您可能需要执行以下操作:
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
然后使用params [:parent_type]和params [:parent_id]访问控制器中的父模型。您还需要将正确的参数传递给url助手:
comments_path('pictures', 7)
答案 1 :(得分:2)
Ryan Bates在Railscasts #154中介绍了多态关联,但该示例适用于Rails 2和Active Record。我设法让他的例子使用Rails 3和Mongoid进行一些更改。
在Post and Picture模型中,添加以下行:
embeds_many :comments, :as => :commentable
根据Mongoid associations documentation,所有embedded_in
个关联都是多态的。使用Mongoid时,您不需要Railscast中提到的commentable_id
和commentable_type
列,因为注释是可注释的子项。在Comment模型中,添加以下行:
embedded_in :commentable, :inverse_of => :comment
在config / routes.rb中设置路由,如下所示:
resources posts do
resources comments
end
resources pictures do
resources comments
end
将以下方法作为private
方法添加到评论控制器中。这与Ryan的方法相同:
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
在您需要查找注释的每个注释控制器操作中,首先调用find_commentable方法以获取父级。找到父级后,您可以通过ID搜索评论的评论来查找评论。例如,在编辑操作中,查找注释的代码如下所示:
@commentable = find_commentable
@comment = @commentable.comments.find(params[:id])
为了减少在每个动作开始时调用find_commentable的重复次数,你可以将一个前置过滤器放在控制器的顶部,如下所示:
class CommentsController < ApplicationController
before_filter :find_commentable
...
然后将find_commentable方法中的返回调用更改为:
return @commentable = $1.classify.constantize.find(value)
使用此方法时我没有遇到任何问题,但如果您遇到任何问题,请指出它们。
答案 2 :(得分:0)
借鉴Uriptical的答案,我发现这些关系有效,但命名路线仍然没有。
我在rails 3上仍然很新,但我找到了一个使用eval的简单解决方案。
例如,在我的项目中,多态父项(在我的应用程序中表示为mongoid对象产品和类别)使用find_comentable的修改定义为@imagable,正在编辑的子项称为@image。
product_image_path(@imagable, @image)
之类的网址
GET => products/:product_id/images/
可以替换为:
send("#{@imagable.class.name.downcase}_image_url", @imagable, image )
这适用于所有命名路径。例如:
link_to 'Edit', send("edit_#{@imagable.class.name.downcase}_image_path", @imagable, image )
link_to 'Destroy', send("#{@imagable.class.name.downcase}_image_url", @imagable, image), :confirm => 'Are you sure?', :method => :delete
这样做的缺点是,无论你有重定向,它都会在你的视图和控制器中发送。
通过路线有更优雅的解决方案吗?
* 将eval替换为发送