【问题标题】:Rails / Creating a Blog: Validation for comments (belong to a post) does not workRails / 创建博客:评论(属于帖子)的验证不起作用
【发布时间】:2025-12-27 16:40:16
【问题描述】:

我正在尝试构建一个简单的博客,其中一篇文章有​​许多 cmets,并且这些 cmets 显示在 posts#show 页面上。

我有两个我无法弄清楚的错误:

  1. 对我的 cmets 的验证不起作用。注释的名称和内容应该存在。每当我尝试提交“空”评论时,我都会收到一条错误消息:“NoMethodError in CommentsController#create: undefined method `empty?'对于零:NilClass”。我怀疑在我的 cmets_controller.rb 中我必须在我的创建操作中呈现不同的页面(代码见下文)?
  2. 每当我创建新帖子时,总会有一个属于空评论的空“删除”链接(没有人创建。它是自动创建的?)。这个“删除”链接链接到http://localhost:3000/posts/[post_id]/comments(请注意,在“/cmets”之后没有像“/comment/3/”这样的comment_id)

routes.rb:

resources :posts do
  resources :comments
end

app/models/post.rb

class Post < ActiveRecord::Base
  has_many :comments, dependent: :destroy
end

app/models/comment.rb

class Comment < ActiveRecord::Base
  validates :name, presence: true
  validates :content, presence: true

  belongs_to :post
end

app/controllers/cmets_controller.rb

class CommentsController < ApplicationController
  before_action :set_post

  def create
    @comment = @post.comments.build(comment_params)

    if @comment.save
      flash[:success] = "Comment saved!"
      redirect_to post_path(@post)
    else
      flash[:alert] = "Something went wrong!"
      render root_path                        # I suspect here is an error?
    end
  end

  def destroy
    @comment = @post.comments.find(params[:id])
    @comment.destroy

    flash[:success] = "Comment deleted"
    redirect_to post_path(@post)
  end

  private

    def comment_params 
      params.require(:comment).permit(:name, :email, :content)
    end

    def set_post
      @post = Post.find(params[:post_id])
    end
end

app/views/posts/show.html.erb

这是我创建新帖子时出现“删除”链接的问题。这个“删除”链接属于一个空的并且奇怪地自动创建的评论?

<% unless @post.comments.empty? %>          # I suspect here is an error?
  <% @post.comments.each do |comment| %>
    <p><%= comment.name %></p>
    <p><%= comment.content %></p>
    <p><%= link_to "Delete",   [comment.post, comment], 
                                method: :delete, 
                                data: { confirm: "Are you sure?" } %></p>
  <% end %>
<% end %>

app/views/posts/new.html.erb

<%= form_for(@post) do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= @post.errors.count %> Fehler:</h2>

      <ul>
      <% @post.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="image-box">
    <p><%= f.file_field :image%></p>
  </div>
    <div class="title-box">
      <p><%= f.label :title, "Titel" %></p>
      <p><%= f.text_field :title, class: "title-field"%></p>
    </div>
     <div class="content-box">
      <p><%= f.label :content, "Inhalt" %></p>
      <p><%= f.text_area :content, class: "content-field"%></p>
    </div>
    <p><%= f.submit %></p>
<% end %>

【问题讨论】:

  • 对于您的第一个问题,调查为什么 @post.comments 为零会很有趣。我会在这里使用binding.pry 进行调试,看看@post 的价值是什么。对于您的第二个问题,我也会尝试查看 comment 的值是多少
  • 第二个问题:当我创建一个新帖子并在rails控制台中输入>Post.last.cmets.nil? => 错误。所以自动有一个“幽灵”评论还是正常的?这对我来说很奇怪。然后我输入 >Post.last.cmets.last.nil? => 真的。所以我的“幽灵”评论没有价值:)?例如,我无法键入
  • 分享新表单的代码
  • 试试Post.last.comments看看里面有什么,它会给你更好的洞察力,你可以使用blank?而不是nil?,因为cmets会返回[]而一个空数组会不考虑nil
  • Post.last.comments 给我 'SELECT "cmets".* FROM "cmets" WHERE "cmets"."post_id" = ? [["post_id", 46]] => #<:associations::collectionproxy>'

标签: ruby-on-rails ruby validation ruby-on-rails-4


【解决方案1】:

我在这里看到的问题是评论没有保存在数据库中,这就是它没有id的原因,这就是你得到这个html的原因:

<a data-confirm="Are you sure?" rel="nofollow" data-method="delete" href="/posts/51/comments">delete</a>

id 不见了。

如果我是你,我只会在渲染视图时检查评论是否存在,这样你就只会向用户显示现有的 cmets:

<% if comment.persisted? %>
  [...]

【讨论】:

  • 这是否意味着每当我创建新帖子时总是有一个“未保存”评论?我已经尝试了您的解决方案,但仍然出现鬼鬼祟祟的“no-id-comment”,啊!
  • 会再次更正我的答案(今天累了吗?),我的意思是comment.persisted?
  • 是的,非常感谢,删除链接不见了 :)(抱歉,如果这是您的印象,我并不想听起来粗鲁。那不是我的本意)。跨度>
  • 别担心 :)。
【解决方案2】:

实际上你并没有通过post_id 来创建方法,这就是为什么它不保存对帖子的评论。

将 post_id 添加到您的 post#new 表单中作为隐藏字段,例如:

<%= form_for(@post) do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= @post.errors.count %> Fehler:</h2>

      <ul>
      <% @post.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="image-box">
    <p><%= f.file_field :image%></p>
  </div>
    <div class="title-box">
      <p><%= f.label :title, "Titel" %></p>
      <p><%= f.text_field :title, class: "title-field"%></p>
      <%= hidden_field_tag :post_id, @post.id %>
    </div>
     <div class="content-box">
      <p><%= f.label :content, "Inhalt" %></p>
      <p><%= f.text_area :content, class: "content-field"%></p>
    </div>
    <p><%= f.submit %></p>
<% end %>

这有望解决您的问题。

或者您可以在 CommentsController 强参数中允许 post_id 并发送 post_id 以及评论新表单以创建方法和创建将如下所示:

def create
    @comment = Comment.new(comment_params)
    if @comment.save
      flash[:success] = "Comment saved!"
      redirect_to post_path(@post)
    else
      flash[:alert] = "Something went wrong!"
      render root_path             
    end
end

def comment_params 
      params.require(:comment).permit(:name, :email, :content, :post_id)
end

【讨论】:

  • 谢谢,我已经尝试过您的解决方案,将 render root_path 更改为 render "posts/show",现在至少我的自定义 Flash 消息“出了点问题”出现了。您是否偶然知道一种方法可以显示 Rails 验证错误(例如:“内容不能为空白”)?第二个问题,即我创建帖子时仍然存在“删除评论”链接,仍然存在。
【解决方案3】:

与其在控制器中使用 @post 作为主要对象来创建评论,我实际上会这样做:

@comment = Comment.new(comment_params)
@comment.post = @post

if @comment.save
  [...]

【讨论】:

  • 谢谢,我已经尝试过了,但它给了我一个 undefined method build 错误。使用@comment = Comment.create(comment_params),它的工作方式与我的代码类似,尽管我的两个问题仍然存在:(
  • 抱歉,我的意思是写new 而不是build。我相应地编辑了我的答案。
  • 谢谢,我已经使用 Muhammads 解决方案尝试了您的解决方案,并将 render root_path 更改为 render "posts/show",现在至少我的自定义 Flash 消息“出了点问题”出现了。您是否偶然知道一种方法可以显示 Rails 验证错误(例如:“内容不能为空白”)?第二个问题,我创建帖子时仍然存在幽灵“删除评论”链接,仍然存在
  • 是的,您需要添加一些代码来将flash 哈希的内容显示到您的视图中(查看此 Rails 指南部分:guides.rubyonrails.org/…)。关于第二个问题,link_to 助手的返回值是多少?它生成什么html?
  • 这是我创建新帖子(不是评论)时生成的 html:&lt;a data-confirm="Are you sure?" rel="nofollow" data-method="delete" href="/posts/51/comments"&gt;delete&lt;/a&gt;。除此之外,还有两个空的&lt;p&gt; 标签,通常属于这个“幽灵”评论的“名称”和“内容”字段。