【问题标题】:Rails 3 - Building a nested resource within another nested resource (articles -> comments -> votes)Rails 3 - 在另一个嵌套资源中构建嵌套资源(文章 -> 评论 -> 投票)
【发布时间】:2012-05-28 22:49:05
【问题描述】:

在我的应用中存在关联问题,我无法解决。 我的应用很简单:有一个文章模型;每篇文章都有_many cmets,每个cmets都有_many票,在我的例子中是'upvotes'。
为了解释我的设计方式,我做了一个 cmets 脚手架,编辑了评论模型和路由到嵌套资源,一切正常。现在,我基本上对“upvotes”再次执行了相同的过程,并再次编辑了模型和路线,以使其成为评论嵌套资源中的嵌套资源。但这在以下几点失败了:

NoMethodError in Articles#show
Showing .../app/views/upvotes/_form.html.erb where line #1 raised:
undefined method `upvotes' for nil:NilClass

我的 _form.html.erb 文件如下所示:

<%= form_for([@comment, @comment.upvotes.build]) do |f| %>
<%= f.hidden_field "comment_id", :value => :comment_id %>
<%= image_submit_tag "buttons/upvote.png" %>
<% end %>

为什么在这种情况下'upvotes'未定义,而在这里:

<%= form_for([@article, @article.comments.build]) do |form| %>
rest of code

一切正常吗?我复制了相同的机制,但使用 @comment.upvotes 它不起作用。

我的upvotes_controller:

class UpvotesController < ApplicationController

  def new
    @upvote = Upvote.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @upvote }
    end    
  end

  def create
  @article = Article.find(params[:id])
  @comment = @article.comments.find(params[:id])
    @upvote = @comment.upvotes.build(params[:upvote])
    respond_to do |format|
      if @upvote.save
        format.html { redirect_to(@article, :notice => 'Voted successfully.') }
        format.xml  { render :xml => @article, :status => :created, :location => @article }
      else
        format.html { redirect_to(@article, :notice => 
        'Vote failed.')}
            format.xml  { render :xml => @upvote.errors, :status => :unprocessable_entity }
      end
    end
  end

end

我很抱歉这么多代码..,我的文章控制器:(摘录)

def show
    @upvote = Upvote.new(params[:vote])
    @article = Article.find(params[:id])
    @comments = @article.comments.paginate(page: params[:page])


    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @article }
    end
  end

还有我的 3 个模型:

  class Article < ActiveRecord::Base
    attr_accessible :body, :title

    has_many :comments
  end

  class Comment < ActiveRecord::Base
    attr_accessible :content

    belongs_to :user
    belongs_to :article
    has_many :upvotes
  end

  class Upvote < ActiveRecord::Base
    attr_accessible :article_id, :comment_id, :user_id

    belongs_to :comment, counter_cache: true
  end

支持迁移文件:

  class CreateUpvotes < ActiveRecord::Migration
    def change
      create_table :upvotes do |t|
        t.integer :comment_id
        t.integer :user_id

        t.timestamps
      end
    end
  end

我的路线:

  resources :articles do
      resources :comments, only: [:create, :destroy] do
        resources :upvotes, only: [:new, :create]
      end
    end

抱歉,有这么多代码。如果有人能回答这个问题,他们会非常棒! 提前谢谢!

【问题讨论】:

    标签: ruby-on-rails-3 build resources nested associations


    【解决方案1】:

    为什么在这种情况下'upvotes'未定义,而在这里:

    这是因为您正在对一个 nil 对象进行投票,该评论还不存在。

    最好的办法是查看嵌套属性:

    http://guides.rubyonrails.org/2_3_release_notes.html#nested-attributes

    http://guides.rubyonrails.org/2_3_release_notes.html#nested-object-forms

    【讨论】:

    • 感谢您的回答和链接!但是,有一个问题:为什么评论是一个 nil 对象?我以为我在 upvote_controller 中用@comment = @article.comments.find(params[:id]) 定义了它?
    • 我怀疑文章页面上有很多 cmets,comment 变量应该是本地变量,例如 @article.cmets.each do |comment|然后使用评论变量来构建您的投票表单。
    • 我认为这是正确的提示,但我无法实现这一点。我的文章show action中定义评论列表的方式是@comments = @article.comments.paginate(page: params[:page]),仅此而已。在文章显示视图中,cmets 是通过render @comments 呈现的。那么,我怎样才能给每条评论一个 id,一个认可,我的 upvotes 和 article 控制器可以在提交 upvote 表单时使用(实际上只是点击)?当然,每条评论都有一个 id 并且嵌套在一篇文章中,但是如何访问该 id 呢?
    【解决方案2】:

    您的错误消息说您尝试在nil 上调用upvotes。具体来说,它是您 /app/views/upvotes/_form.html.erb 视图中代码 @comment.upvotes.build 的一部分。

    您必须通过添加@comment(带有内容)变量来修复ArticlesController 中的show 操作。

      def show
        @upvote = Upvote.new(params[:vote])
        @article = Article.find(params[:id])
        @comments = @article.comments.paginate(page: params[:page])
    
    
        respond_to do |format|
          format.html # show.html.erb
          format.json { render json: @article }
        end
      end
    

    UpvotesControllercreate 行动中也发生了奇怪的事情。

    @article = Article.find(params[:id])
    @comment = @article.comments.find(params[:id])
    @upvote = @comment.upvotes.build(params[:upvote])
    

    首先,您使用params[:id] 获取了一个@article,然后获取了该@article 的所有cmets(通过关联),其中cmets id 与@article id 相同。请检查您的代码,它不一致且无法正常工作。

    【讨论】:

    • 非常感谢您的帮助!我同意我必须在我的articles_controller 的显示操作中定义我的@comment。但是,我没有任何想法离开如何。由于我的 hidden_​​field &lt;%= f.hidden_field "comment_id", :value =&gt; :comment_id %&gt;,我尝试了 @comment = @article.comments.find(params[:comment_id]) 但现在我收到错误“找不到没有 ID 的评论”,所以我的主要问题似乎是评论的 id 根本没有正确定义。我确实修复了 upvote 控制器中的代码。
    • 不客气!请解释一下,你想在你的ArticlesController#show 中实现什么?你想让1 article1 comment 一起显示吗?还是带有 cmets 列表的文章?
    • 应该是 1 篇带有 cmets 列表的文章。我觉得问题是由于 cmets 嵌套在文章中,comment_id 没有正确提交;据我了解,这样的提交需要同时包含已投票评论的 article.id 和 comment.id。我觉得我的投票表格需要修复&lt;%= form_for([@comment, @comment.upvotes.build]) do |f| %&gt; &lt;%= f.hidden_field "comment_id", :value =&gt; :comment_id %&gt; &lt;%= image_submit_tag "buttons/upvote.png" %&gt; &lt;% end %&gt;
    【解决方案3】:

    现在一切都已修复并且工作正常。采取了不同的方法,简单地使用 Upvote.new 而不是将其嵌套到 cmets 和建立关联中,也编辑了我的路线。实现了 Matthew Ford 的想法

    我怀疑文章页面上有很多 cmets,comment 变量应该是本地变量,例如 @article.cmets.each do |comment|然后使用评论变量来构建您的投票表格。

    感谢大家的帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 1970-01-01
      相关资源
      最近更新 更多