【问题标题】:Undefined Method in 'comments_path' using "Commentable" form_for Polymorphic association'comments_path' 中使用“Commentable”form_for 多态关联的未定义方法
【发布时间】:2015-03-03 00:48:12
【问题描述】:

我收到“未定义方法 'cmets_path' for...”的错误 在 app/views/cmets/_form.html.erb 中的这段代码(第 1 行)。

我最近尝试在我正在构建的网站上通过多态关联来实现可嵌套的 cmets;但是,我遇到了一个不允许我前进的问题。

我正在尝试在“可评论”模型(即本例中的博客)上实现嵌套 cmets,然后当单击 show 时,会显示所有嵌套 cmets,并且个人可以在博客上发表评论或回复在不离开页面的情况下评论(并因此导致嵌套的 cmets)。

我已经包含了一些其他文件来显示设置,但如果我错过了一个必要的文件,请告诉我,我会及时添加它。任何帮助深表感谢。我已经被难住了几个小时,我相信这很简单。

<%= form_for [@commentable, @comment] do |f| %>
  <%= f.hidden_field :parent_id %></br>
    <%= f.label :content, "New Comment" %></br>
    <%= f.text_area :body, :rows => 4 %></br>
    <%= f.submit "Submit Comment" %>
<% end %>

app/views/blogs/show.html.erb

<div class="content">
  <div class="large-9 columns" role="content">
    <h2>Comments</h2>
    <div id="comments">
      <%= nested_comments @comments %>
      <%= render "comments/form" %>
    </div>
  </div>
</div>

app/controllers/cmets_controller

class CommentsController < ApplicationController
      def new
        @parent_id = params.delete(:parent_id)
        @commentable = find_commentable
        @comment = Comment.new( :parent_id => @parent_id, 
                                :commentable_id => @commentable.id,
                                :commentable_type => @commentable.class.to_s)
      end

      def create
        @commentable = find_commentable
        @comment = @commentable.comments.build(params[:comment])
        if @comment.save
          flash[:notice] = "Successfully created comment."
          redirect_to @commentable
        else
          flash[:error] = "Error adding comment."
        end
      end



      private
      def find_commentable
        params.each do |name, value|
          if name =~ /(.+)_id$/
            return $1.classify.constantize.find(value)
          end
        end
        nil
      end

      def comment_params
        params.require(:comment).permit(:parent_id, :body, :commentable_type, :commentable_id)
      end
    end

app/controller/blogs_controller.rb

class BlogsController < ApplicationController
  before_filter :authenticate, :except => [ :index, :show ]
  before_action :set_blog, only: [:show, :edit, :update, :destroy]
  include MyModules::Commentable

  # GET /blogs
  # GET /blogs.json
  def index
    @blogs = Blog.all.order('created_at DESC')

    respond_to do |format|
      format.html 
      format.json
      format.atom
    end
  end

  # GET /blogs/1
  # GET /blogs/1.json
  def show
    @blog = Blog.find(params[:id])
  end

  # GET /blogs/new
  def new
    @blog = Blog.new
  end

  # GET /blogs/1/edit
  def edit
    @blog = Blog.find(params[:id])
  end

  # POST /blogs
  # POST /blogs.json
  def create
    @blog = Blog.new(blog_params)

    respond_to do |format|
      if @blog.save
        flash[:success] = "Blog was sucessfuly created"
        format.html { redirect_to @blog }
        format.json { render :show, status: :created, location: @blog }
      else
        format.html { render :new }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /blogs/1
  # PATCH/PUT /blogs/1.json
  def update
    respond_to do |format|
      if @blog.update(blog_params)
        flash[:success] = "Blog was successfully updated."
        format.html { redirect_to @blog }
        format.json { render :show, status: :ok, location: @blog }
      else
        format.html { render :edit }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /blogs/1
  # DELETE /blogs/1.json
  def destroy
    @blog.destroy
    respond_to do |format|
      flash[:success] = "Blog was successfully deleted."
      format.html { redirect_to blogs_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_blog
      @blog = Blog.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def blog_params
      params.require(:blog).permit(:title, :body, :image, :image_cache, :remote_image_url)
    end

  private
  def authenticate
    authenticate_or_request_with_http_basic do |name, password|
      name == "admin" && password == "runfast"
    end
  end
end

我的路由文件看起来像这样...

Rails.application.routes.draw do
  resources :blogs do
    resources :comments
  end

  resources :applications

  resources :reviews

  resources :properties

  root to: 'blogs#index'
end

博客和评论模型...

class Blog < ActiveRecord::Base
  validates_presence_of :body, :title
  has_many :comments, :as => :commentable, :dependent => :destroy
  mount_uploader :image, ImageUploader
end

class Comment < ActiveRecord::Base
  has_ancestry
  belongs_to :commentable, :polymorphic => true
  validates_presence_of :body
end

最后是 lib/my_modules/commentable.rb 中的可注释模块

require 'active_support/concern'

module MyModules::Commentable
    extend ActiveSupport::Concern

    included do 
      before_filter :comments, :only => [:show]
    end

    def comments
      @Commentable = find_commentable
      @comments = @Commentable.comments.arrange(:order => :created_at)
      @comment = Comment.new
    end

    private

    def find_commentable
      return params[:controller].singularize.classify.constantize.find(params[:id])
    end

  end

@博客

#<Blog id: 8, title: "New Blog Post about Databases.... Again", body: "RDM, the database management system, was designed ...", created_at: "2015-03-01 22:28:07", updated_at: "2015-03-03 00:11:07", image: "IMG_2210.JPG">

@commentable

#<Blog id: 8, title: "New Blog Post about Databases.... Again", body: "RDM, the database management system, was designed ...", created_at: "2015-03-01 22:28:07", updated_at: "2015-03-03 00:11:07", image: "IMG_2210.JPG">

app/helpers/cmets_helper.rb

module CommentsHelper
  def nested_comments(comments)
    comments.map do |comment, sub_comments|
      content_tag(:div, render(comment), :class => "media")
    end.join.html_safe
  end
end

@_params 实例变量更好的错误

{"utf8"=>"✓", "authenticity_token"=>"OH2tDdI5Kp54hf5J78wXHe//Zsu+0jyeXuG27v1REqjdAec7yBdlrVPLTZKEbLZxgR2L7rGwUwz5BlGTnPcLWg==", "comment"=>{"parent_id"=>"", "body"=>"Hello!\r\n"}, "commit"=>"Submit Comment", "controller"=>"comments", "action"=>"create", "blog_id"=>"8"}

【问题讨论】:

  • 检查@commentable 是否存在。如果它是 nil 你会得到这个错误。
  • @Swards - commentable 作为实例变量存在,并且与“blog”实例变量具有完全相同的内容...实例变量“cmets”显示 {},实例变量“comment”显示“ #"
  • 如果@commentable 是博客实例,则表单中的 [@commentable, @comment] 将调用 blog_comments_path 方法。您检查了表单中的@commentable 变量? (erb 中的“raise @commentable”)
  • @Swards - 明白了。在更好的错误中,当它从完整的博客列表中单击博客时引发未定义的方法错误时,它显示以下内容..(我将在上面添加。)我不确定你的意思是检查可评论变量不过,在 erb 中的形式和提高可评论性。请解释?谢谢!
  • 由于您使用了更好的错误,请在form_for 之前添加&lt;% raise %&gt;。然后你可以检查所有的实例变量。

标签: ruby-on-rails ruby ruby-on-rails-4 polymorphic-associations


【解决方案1】:

您在此视图中遇到错误:app/views/blogs/show.html.erb

此视图的数据已在blogs#show 中准备好。所以在你看来,你应该有&lt;%= form_for [@blog, @comment] do |f| %&gt;,因为你设置了@blog,而不是@commentable

您也应该使用@comment = Comment.new。不知道你把这个放在哪里...

在您的视图中执行&lt;% raise @commentable.inspect %&gt; (app/views/blogs/show.html.erb)。如果它是 nil,那么这就是你收到错误的原因。

【讨论】:

  • 所以可评论实例变量在我的可评论模块中设置,其设置本身等于当前控制器和您尝试访问的 ID(当您单击 find_commentable 下 cmets_controller 中的创建时调用(实际上是您可以将模块添加到您希望能够评论的任何内容而不是再次编写所有代码?)。我很新,所以我问这个,而不是说。最终的问题是您可以在我的可评论模块中看到难以捉摸的大写 C。我将其更改为小写,现在我可以查看博客了。但是....
  • @ Swards - 我现在在我的 cmets_controller 的第 12 行收到一个禁止属性错误。我认为我在 def comment_params 下私有部分的控制器中正确设置了我的属性?也许我错过了创建操作所必需的一项?我已经编辑了原始帖子,以便为 params 实例变量输入更好的错误输出,如果这可以为​​您提供洞察力。再次感谢您的所有帮助,并为我缺乏知识表示歉意。
  • 您的comment_params 方法看起来不错,只是您没有使用它;)应该是@comment = @commentable.comments.build(comment_params)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多