Rails 4中的Mongoid 1-N关系(一对多)

时间:2014-05-07 00:29:52

标签: ruby-on-rails ruby mongodb ruby-on-rails-4 mongoid

我正在尝试使用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

3 个答案:

答案 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.erbCommentsController#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关系问题无关。

    Mongoid :: Errors :: DocumentNotFound。此错误是由于不正确地使用Blog.find方法引起的。当您传递Blog.find个多个ID时,它将返回一个包含给定ID的博客数组。您使用params[:id]params[:blog_id]调用了查找。鉴于您在CommentsControllerparams[:id]可能包含comment对象的ID,换句话说,具有给定ID的blog对象不存在。根据Mongoid的文档here,如果任何id不匹配,find方法将默认引发错误,因此Mongoid::Errors::DocumentNotFound错误。

如果您尝试在set_comment方法中加载评论,那么正确的代码将是

@comment = Comment.find(params[:id])
  • 未定义的方法model_name for Mongoid :: Criteria:Class。看看你的回购,这同样是由于不正确地使用Mongoid的可查询DSL引起的。

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