【问题标题】:form_with produces first record as nilform_with 产生第一条记录为 nil
【发布时间】:2018-12-24 22:21:21
【问题描述】:

评论控制器

class CommentsController < ApplicationController
  before_action :load_commentable
  before_action :checked_logged_in, only: [ :create]

  def new
    @comment = @commentabl.comments.new
  end

  def create
    @comment = @commentable.comments.new(comment_params) 
    @comment.user_id = current_user.id
    @comment.commenter = current_user.username


    if @comment.blank? || @comment.save
      flash[:success] = "Commented was created"
       ActionCable.server.broadcast 'comment_channel',
        commenter: current_user.username,
        comment: @comment.content
      redirect_to @commentable
    else       
       flash[:danger]  = render_to_string(:partial => 'shared/error_form_messaging',
                                          :locals => {obj: @comment}, 
                                          format: :html)
       redirect_to @commentable   
    end
  end
private

  def comment_params
      params.require(:comment).permit(:content, :commenter, :user_id)
  end
  def load_commentable
    resource, id = request.path.split('/')[1,2]
    @commentable = resource.singularize.classify.constantize.find(id)
  end

  def checked_logged_in
    unless logged_in?
      flash[:danger] = 'please log in to be able to comment'
      redirect_to login_path
    end
  end

end

我的评论表单:

<%= form_with  model:[commentable, commentable.comments.new], :html => {class: "form-horizontal", role:"form"} , local: true do |form| %>

<div class="form-group">
    <div class="control-label col-sm-2">
         <%= form.label :content, 'Comment' %>
    </div>
    <div class="col-sm-8">
         <%= form.text_field :content , class: 'form-control', placeholder: "enter your comment here", autofocus: true %>
    </div>
</div>
<div class="form-group">
    <div class="col-sm-offset-2 col-sm-10">
        <%= form.submit 'Comment' , class: ' btn btn-primary' %> 
    </div>
</div>              
<% end %>   

表单在show.html.erb中调用

<h2 class="text-center">
    Title: <%= @article.title %>
</h2>
<div class="well col-xs-8 col-xs-offset-2">
    <div id="user-info-showpage" align="center">
        Created by: <%= render 'shared/user-info', obj: @article.user %>    
    </div>    
    <h4 class="text-center">
        <strong>Description:</strong>         
    </h4>
    <hr />
    <%= simple_format(@article.description) %>
    <% if @article.categories.any? %>
        <p>Categories: <%= render @article.categories %></p>      
     <% end %>
        <div class="article-actions">  
            <% if logged_in? && (current_user == @article.user || current_user.admin?) %>
                 <%= link_to "Delete", article_path(@article), method: :delete, 
                 data: {confirm: "Are you sure you want to delete the article?"}, 
                 class: 'btn btn-xs btn-danger' %>
                 <%= link_to "Edit", edit_article_path(@article), class: 'btn btn-xs btn-success'%>
            <%end%> 
            <%= link_to "View All Articles", articles_path  , class: 'btn btn-xs btn-primary'%> 
        </div> 
</div> 
<% if logged_in? %>
    <div class="col-xs-8 col-xs-offset-2">
        <%#= render partial: 'comments/form', :locals => {commentable:   @article} %>   
    </div>
<%end%> 

<div class="col-xs-8 col-xs-offset-2"> 
     <div id="comments"></div>
     <%= @article.comments.inspect %>
        <% @article.comments.each do |c| %>     
            <div class="well">           
                    <%= c.content %>   by 
                    <%= c.commenter %>           
            </div>
        <%end%>

     <div id="comments"></div>
</div>

我的结果是

如果需要更多信息,请询问我,以便我提供

注意:我不确定这个空记录是由于 commentable.cmets 为 nil 还是我错过了什么

我在show page评论了render form,现在空记录不见了,所以我的问题一定与form_with有关

【问题讨论】:

  • 您能出示您的show.html.erb 代码吗?顺便说一句,commentable.comments.new 应该是commentable.comments.build
  • 感谢您的回复。我用构建测试并得到相同的结果。我发布了显示页面的整个代码。 是新的构建别名吗?所以它们应该是相同的,不是吗?
  • 为什么需要在表单中输入&lt;%= @article.comments.inspect %&gt;?不想看到的可以删除#&lt;ActiveRecord...
  • 用于调试目的。当我解决问题时,我会删除它。
  • @KickButtowski 你能分享控制器的代码吗

标签: ruby-on-rails ruby ruby-on-rails-5


【解决方案1】:

据我了解,你

预期:

  • 在您的articles#show 页面中不显示空的by _________ &lt;div&gt; HTML,因为comment 仍在构建(仍在内存中),尚未保存(尚未在数据库中)。

解决方案 1:

app/views/articles/show.html.erb

...
<div class="col-xs-8 col-xs-offset-2"> 
  <div id="comments"></div>
    <% @article.comments.each do |c| %>
      <!-- ADD THIS LINE -->
      <% if c.persisted? %>
        <div class="well">           
          <%= c.content %>   by 
          <%= c.commenter %>           
        </div>
      <% end %>
    <%end%>
  <div id="comments"></div>
</div>
...

解决方案 2(更好但仍然是一种解决方法):

app/views/cmets/_form.html.erb

<%= form_with  model:[commentable, Comment.new(commentable: commentable)], :html => {class: "form-horizontal", role:"form"} , local: true do |form| %>

解释:

  • 页面显示空的by _________&lt;div&gt; 的原因是因为您在调用.each 之前“构建”了一个新的comment。因为它们共享相同的内存空间,build 基本上也将其添加到内存中的数组中。请参阅以下内容:

    # rails console
    article = Article.create!
    comment1 = Comment.create!(commentable: article)
    # from here, comment1 is then saved already in the DB
    
    # now let's see what happens when you use "build" or "new"
    # They have differences, it seem: for details: https://stackoverflow.com/questions/1253426/what-is-the-difference-between-build-and-new-on-rails/1253462
    
    # redefine (to simulate your @article = Article.find(params[:id])
    article = Article.find(article.id)
    comment2 = article.comments.build
    
    puts article.comments.count
    # SQL: Select count(*) FROM ...
    # => 1
    
    puts article.comments.size
    # => 2
    
    # notice how `count` and `size` are different. `count` value is "DB-based" while `size` is "memory-based". This is because `count` is an `ActiveRecord` method while `size` is a delegated `Array` method.
    
    # now let's simulate your actual problem in the view, where you were looping...
    article.comments.each do |comment|
      puts comment
    end
    # => <Comment id: 1>
    # => <Comment id: nil>
    
    # notice that you got 2 comments:
    #  one is that which is already persisted in DB
    #  and the other is the "built" one
    
    # the behaviour above is to be expected because `.each` is a delegated `Array` method 
    # which is agnostic to where its items come from (DB or not)
    

这就是为什么在您的页面中,“已构建”评论显示在页面中的原因,因为您正在调用

&lt;%= render partial: 'comments/form', :locals =&gt; {commentable: @article} %&gt; ...调用commentable.comments.build

之前&lt;% "article.comments.each do |c| %&gt;

如果这还不够清楚,请尝试放置

&lt;%= render partial: 'comments/form', :locals =&gt; {commentable: @article} %&gt;

...调用commentable.comments.build

之后&lt;% "article.comments.each do |c| %&gt; ... &lt;% end %&gt; ... 并且 by _________ &lt;div&gt; 应该已经不会出现了。

【讨论】:

  • 如果评论没有保存在数据库中,为什么还会显示?
  • @KickButtowski 如果您注意到我上面的解释代码,它会被显示,因为您“构建”了一个评论,该评论在您的 .each 循环中呈现到视图中。使用comments.build 会将Comment 的实例构建到数组中(内存中)。这是设计使然。你可以把 build 想象成这样:article.comments &lt;&lt; Comment.new(除了它还在内存中)
猜你喜欢
  • 1970-01-01
  • 2018-02-27
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 2014-06-17
相关资源
最近更新 更多