我正在尝试使用Mongoid在Rails 4中的两个实体之间建立1-N(一对多)关系。到目前为止,我已经创建了一个简单的应用程序' Blog' &安培; '注释' (每个博客都包含多个评论)。
我使用has_many
属性来定义关系。这是我到目前为止所得到的......
class Blog
include Mongoid::Document
include Mongoid::Timestamps
has_many :comments, validate: false
field :title, type: String
field :content, type: String
end
class Comment
include Mongoid::Document
include Mongoid::Timestamps
belongs_to :blog
field :title, type: String
field :content, type: String
end
这是我的Blog#Show视图文件的外观 https://github.com/som-poddar/Mongo_One_Many/blob/master/app/views/blogs/show.html.erb
几次尝试后,我总是最终......Showing /Users/spoddar/work/Mongo_One_Many/app/views/comments/_form.html.erb where line #1 raised:
undefined method `comments_path' for #<#<Class:0x007f9f1d08e5f8>:0x007f9f1f9b6458>
有人可以帮帮我吗? 完整源代码https://github.com/som-poddar/Mongo_One_Many
我的路线......
Prefix Verb URI Pattern Controller#Action
blog_comments GET /blogs/:blog_id/comments(.:format) comments#index
POST /blogs/:blog_id/comments(.:format) comments#create
new_blog_comment GET /blogs/:blog_id/comments/new(.:format) comments#new
edit_blog_comment GET /blogs/:blog_id/comments/:id/edit(.:format) comments#edit
blog_comment GET /blogs/:blog_id/comments/:id(.:format) comments#show
PATCH /blogs/:blog_id/comments/:id(.:format) comments#update
PUT /blogs/:blog_id/comments/:id(.:format) comments#update
DELETE /blogs/:blog_id/comments/:id(.:format) comments#destroy
blogs GET /blogs(.:format) blogs#index
POST /blogs(.:format) blogs#create
new_blog GET /blogs/new(.:format) blogs#new
edit_blog GET /blogs/:id/edit(.:format) blogs#edit
blog GET /blogs/:id(.:format) blogs#show
PATCH /blogs/:id(.:format) blogs#update
PUT /blogs/:id(.:format) blogs#update
DELETE /blogs/:id(.:format) blogs#destroy
答案 0 :(得分:2)
问题出在您的comments/_form.html.erb
页面,特别是此行:form_for (@comment) do |f|
。
如果查看路由文件,comments#create
操作将映射到以下路由:/blogs/:blog_id/comments(.:format)
。但是form_for(@comment)
会生成指向以下路线的链接:/comments
。这就是提高错误的原因。
要解决此问题,您需要让rails了解您的评论资源是否嵌套在博客资源下。换句话说,您必须传递form_for
博客对象的数组以及评论对象,并且rails magic将生成正确的路线。
因此,请将您的代码更改为以下内容:
<%= form_for([@blog, @comment]) do |f| %>
# stuff here
<% end %>
为了使此解决方案有效,comments/_form.html.erb
表单必须能够访问@blog
实例变量。这意味着,如果您在render 'form'
页面中调用comments/new.html.erb
,CommentsController#new
除了@blog
实例变量外,还必须设置@comment
实例变量。因此,您的CommentsController#new
操作必须如下所示:
def new
@blog = Blog.find(params[:blog_id])
@comment = @blog.comments.build
end
同样,您的创建操作也应该加载博客模型,类似于:
def create
@blog = Blog.find(params[:blog_id])
@comment = @blog.comments.build
@comment.update_attributes(params[:comment])
respond_with(@comment)
end
有关嵌套资源的更多信息,请参阅this。
您当前的错误与原始嵌套路由/ 1-N关系问题无关。
Blog.find
方法引起的。当您传递Blog.find
个多个ID时,它将返回一个包含给定ID的博客数组。您使用params[:id]
和params[:blog_id]
调用了查找。鉴于您在CommentsController
,params[:id]
可能包含comment
对象的ID,换句话说,具有给定ID的blog
对象不存在。根据Mongoid的文档here,如果任何id不匹配,find方法将默认引发错误,因此Mongoid::Errors::DocumentNotFound
错误。
如果您尝试在set_comment
方法中加载评论,那么正确的代码将是
@comment = Comment.find(params[:id])
CommentsController#set_comment
再次出错。
def set_comment
@blog = Blog.find(params[:blog_id])
@comment = @blog.comments.where(:_id => params[:id])
end
这一次,您正在加载博客。但是,@blog.comments.where(:_id => params[:id])
将返回id与给定param匹配的注释集合。在您的特定情况下,它将返回单个元素的集合,但@comment的类是Mongoid::Criteria
而不是Comment
,正如您可能想要的那样。一种解决方案可能是将该行更改为:
@comment = @blog.comments.where(:_id => params[:id]).first
这行代码将返回注释集合的第一个元素,如果不存在此类注释,则返回nil
。
另一种解决方案是通过find
方法加载该评论:
@comment = @blog.comments.find(params[:id])
或等效地:
@comment = Comment.find(params[:id])
您应该阅读上面链接的Mongoid查询文档,如果有任何不清楚的内容,以及rails activerecord查询指南here。
答案 1 :(得分:0)
你检查了路线吗?
我认为你在这种情况下的路线是:blogs_comments_path,而不仅仅是comments_path。
检查这个运行$ bundle exec rake -T
为了更好地解释,你的路线档案: https://github.com/som-poddar/Mongo_One_Many/blob/master/config/routes.rb#L2
您正在使用嵌套关系,这就是您的路线略有不同的原因。 这里有一个例子:http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing
答案 2 :(得分:0)
我见过你的config/routes.rb
由于您在博客控制器下将评论控制器定义为嵌套资源,因此应将此路径称为blog_comments_path