【问题标题】:Mongoid 1-N relationship (one to many) in Rails 4Rails 4中的Mongoid 1-N关系(一对多)
【发布时间】:2014-05-07 00:29:51
【问题描述】:

我正在尝试使用 Mongoid 在 Rails 4 中的两个实体之间建立 1-N(一对多)关系。到目前为止,我已经创建了一个带有“博客”和“评论”的简单应用程序(每个博客包含多个 cmets)。

我使用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

【问题讨论】:

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


    【解决方案1】:

    问题出在您的comments/_form.html.erb 页面中,特别是这一行:form_for (@comment) do |f|

    如果您查看路由文件,comments#create 操作将映射到以下路由:/blogs/:blog_id/comments(.:format)。但是form_for(@comment) 将生成一个指向以下路由的链接:/comments。这就是引发错误的原因。

    要解决此问题,您需要让 rails 知道您的 cmets 资源嵌套在 blogs 资源下。换句话说,你必须传递form_for 一个包含你的博客对象以及你的评论对象的数组,rails 魔法会生成正确的路由。

    所以把你的代码改成下面这样:

    <%= form_for([@blog, @comment]) do |f| %>
      # stuff here
    <% end %>
    

    为了使此解决方案起作用,comments/_form.html.erb 表单必须有权访问 @blog 实例变量。这意味着如果您在comments/new.html.erb 页面中调用render 'form',则CommentsController#new 必须在@comment 实例变量之外设置@blog 实例变量。因此,您的 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 在 CommentsController#edit 中。此错误是由于不正确地使用Blog.find 方法引起的。当您传递 Blog.find 多个 id 时,它将返回具有给定 id 的博客数组。你用params[:id]params[:blog_id] 调用了find。假设您在CommentsController 中,params[:id] 可能包含comment 对象的 id,换句话说,具有给定 id 的blog 对象不存在。根据 Mongoid 的文档here,如果任何 id 不匹配,find 方法默认会引发错误,因此会出现Mongoid::Errors::DocumentNotFound 错误。

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

    @comment = Comment.find(params[:id])
    
    • 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 =&gt; params[:id]) 将返回一个 id 与给定参数匹配的 cmets 集合。在您的特定情况下,它将返回单个元素的集合,但是 @comment 的类是 Mongoid::Criteria 而不是 Comment,正如您可能想要的那样。一种解决方案可能是将该行更改为:

    @comment = @blog.comments.where(:_id => params[:id]).first
    

    这行代码将返回 cmets 集合的第一个元素,如果不存在这样的注释,则返回 nil

    另一种解决方案是也通过find 方法加载该评论:

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

    或等效:

    @comment = Comment.find(params[:id])
    

    如果有任何不清楚的地方,您可能应该阅读上面链接的 Mongoid 查询文档,以及 rails activerecord 查询指南here

    【讨论】:

    【解决方案2】:

    你检查过你的路线吗?

    我认为在这种情况下您的路线是:blogs_cmets_path,而不仅仅是 cmets_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

    【讨论】:

    • 我修好了路线。现在我有新的问题。请看我上面的评论。
    【解决方案3】:

    我看到了你的config/routes.rb

    由于您将 评论控制器 定义为 博客控制器 下的嵌套资源,因此路径应称为 blog_comments_path

    【讨论】:

    • 如果您查看 Github 存储库中的最新更改,路由的前缀是正确的。但是,我无法在“博客”文档中“嵌入”“评论:名称”和“评论:标题”。此外,创建“新”评论的代码抛出异常
    • 当我尝试“编辑”博客评论时,我看到“问题:找不到带有 ID 的类博客的文档”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 1970-01-01
    • 2013-03-11
    • 1970-01-01
    • 2012-03-27
    相关资源
    最近更新 更多