简体   繁体   English

以单一形式使用has_many_through和accepts_nested_attributes_for

[英]Using has_many_through and accepts_nested_attributes_for in a single form

There are times when Rails makes you laugh with joy, and when it makes you cry with despair. 有时候,Rails让您高兴地大笑,而有时却让您绝望地哭泣。 This is one of the latter … Having struggled with this on a more complex app I am building, I have built a simple app that isolates the problem I am having. 这是后者中的一个。。。在为我正在构建的更复杂的应用程序上苦苦挣扎之后,我构建了一个简单的应用程序来隔离我遇到的问题。 In summary - a post has a comment and tags. 总结-帖子中有评论和标签。 A tag can belong to more than one post, and a post can have more than one tag. 一个标签可以属于多个帖子,而一个帖子可以具有多个标签。 I want a nested form that allows me to do this in one swoop. 我想要一个嵌套表格,让我可以一口气做到这一点。 I am using check boxes because they are needed in the more complex app. 我正在使用复选框,因为在更复杂的应用程序中需要使用它们。

comment.rb comment.rb

class Comment < ApplicationRecord
    belongs_to :post
end

post.rb post.rb

class Post < ApplicationRecord
    has_many :comments
    has_many :post_tags
    has_many :tags, through: :post_tags
    accepts_nested_attributes_for :comments
    accepts_nested_attributes_for :tags,  update_only: true
end

post_tag.rb post_tag.rb

class PostTag < ApplicationRecord
    belongs_to :post
    belongs_to :tag
end

_form.html.erb _form.html.erb

<%= form_with(model: post, local: true) do |form| %>
    <% if post.errors.any? %>
      <div id="error_explanation">
        <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

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

  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>


  <h2>Comments</h2>
  <%= form.fields_for :comments do |fc| %>
    <%= fc.label :body %>
    <%= fc.text_field :body %>
    <br />
  <% end %>

  <h2>Tags</h2>
  <%= form.fields_for :tags do |ft| %>
    <%= ft.collection_check_boxes(:tag, Tag.all, :id, :tag) do |cb| %>
      <%= cb.label %>
      <%= cb.check_box %>
  <% end %>
    <br />
  <%  end %>


  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

posts_controller.rb posts_controller.rb

Standard scaffold - except for this 标准脚手架-除此之外

def new
    @post = Post.new
    @post.comments.build
    @post.tags.build
end


# Never trust parameters from the scary internet, only allow the white list through.
def post_params
    params.require(:post).permit(:title, comments_attributes: [:body, :id], tags_attributes: [{:tag=>[]}, :id])
end

This is the HTML generated by the collection_check_boxes 这是collection_check_boxes生成的HTML

<input type="hidden" name="post[tags_attributes][0][tag][]" value="" />
    <label for="post_tags_attributes_0_tag_1">tag 1</label>
    <input type="checkbox" value="1" name="post[tags_attributes][0][tag][]" id="post_tags_attributes_0_tag_1" />

    <label for="post_tags_attributes_0_tag_2">tag 2</label>
    <input type="checkbox" value="2" name="post[tags_attributes][0][tag][]" id="post_tags_attributes_0_tag_2" />

    <label for="post_tags_attributes_0_tag_3">tag 3</label>
    <input type="checkbox" value="3" name="post[tags_attributes][0][tag][]" id="post_tags_attributes_0_tag_3" />

    <label for="post_tags_attributes_0_tag_4">tag 4</label>
    <input type="checkbox" value="4" name="post[tags_attributes][0][tag][]" id="post_tags_attributes_0_tag_4" />
<br />
<input type="hidden" value="3" name="post[tags_attributes][0][id]" id="post_tags_attributes_0_id" />

This is what is passed 这就是通过

Parameters: {"utf8"=>"✓", "authenticity_token"=>"0eFWbwi3J6gHnyys6+V/aVymheWE37RWtqq0xm46/umASeyTqj6hTqmTrL4DdvV48yFmMgOtiiYorswTtyCbyw==", 
"post"=>{"title"=>"test post", "comments_attributes"=>{"0"=>{"body"=>"test comment", "id"=>"1"}}, 
"tags_attributes"=>{"0"=>{"tag"=>["", "1", "4"], "id"=>"3"}}}, "commit"=>"Update Post", "id"=>"1"}

The issue lies with the tags_attribute. 问题在于tags_attribute。 When the update runs it updates tag entry 3 with the name “["", "1", "4"]” rather than updating the table. 当更新运行时,它将使用名称“ [”,“ 1”,“ 4”]”更新标签条目3,而不是更新表。 I don't know why it is picking up an id of "3". 我不知道为什么要选择id为“ 3”。 You kind of expect Rails to do everything automagically. 您可能希望Rails能够自动完成所有工作。 When it works it is sweeeeeet. 当它起作用时,它是甜食。 When it doesn't, it is so frustrating. 如果没有,那就太令人沮丧了。 Any advice on where I am going wrong? 关于我要去哪里的任何建议? My suspicion lies with either the collection_check_boxes or the params.require. 我的怀疑在于collection_check_boxes或params.require。

Thanks so much. 非常感谢。

TL;DR: TL; DR:

  • Nested attributes are not needed in your case (so feel free to remove them) 在您的情况下不需要嵌套属性(请随时删除它们)

_form.html.erb: _form.html.erb:

<%= form_with(model: post, local: true) do |form| %>
  <!-- ... -->
  <!-- ... -->
  <%= form.collection_check_boxes(:tag_ids, Tag.all, :id, :tag) do |cb| %>
    <%= cb.label %>
    <%= cb.check_box %>
  <% end %>
<% end %>

posts_controller.rb: posts_controller.rb:

# ...
# ...
def post_params
  params.require(:post).permit(
    :title,
    comments_attributes: [:body, :id],
    tag_ids: []
  )
end

Explanation: 说明:

Whenever I think about how to properly set up a form (even if with nested attributes), I usually do it in rails console first. 每当我考虑如何正确设置表单(即使具有嵌套属性)时,通常通常首先在rails console So check out the cool trick below, and you'll immediately get what I mean :) 因此,请查看以下有趣的技巧,您会立即理解我的意思:)

# rails console
post = Post.first

# hmm I wonder what should we put inside the .update() below, for us to be able to set the associated tags?
post.update(...)

# ok, should be easy enough, let's try below?
post.update(tags: [Tag.find(1), Tag.find(3)])

# cool, above works right?, except... that we cannot use it because we are simulating `params` values,
# ... and `params` values do not have record Objects! but only primitives such as `String` and `Integer`

# hmm... so... why not use the primary keys, right? Let's try below
post.update(tag_ids: [1, 3])

cool, finally it worked! 酷,终于成功了! :) basically, then now we just need to somehow translate tag_ids: [1, 3] above, into the form as input fields of which then we should expect to have input fields' name like below (note that TL;DR above already should look like this) :)基本上,那么现在我们只需要以某种方式将tag_ids: [1, 3]转换为表单的输入字段,那么我们应该期望输入字段的name如下所示(请注意,上面的TL; DR应该已经看起来像这样)

<input type='checkbox' name='post[tag_ids][]' value='1' checked>
<input type='checkbox' name='post[tag_ids][]' value='2'>
<input type='checkbox' name='post[tag_ids][]' value='3' checked>
<input type='checkbox' name='post[tag_ids][]' value='4'>
<input type='checkbox' name='post[tag_ids][]' value='9'>
<!-- OTHER REMAINING TAG IDS HERE. ETC... -->

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过validates_uniqness接受has_many_through的hass_nested_attributes_ - accepts_nested_attributes_for has_many_through with validates_uniqness has_many:through和accepts_nested_attributes_用于复制记录 - has_many :through and accepts_nested_attributes_for duplicating records accepted_nested_attributes_for with has_many =&gt;:通过选项 - accepts_nested_attributes_for with has_many => :through Options Rails,accepts_nested_attributes_for has_many:通过构建 - Rails, accepts_nested_attributes_for has_many: through with build Rails 3具有has_many的accepts_nested_attributes_for:through关系 - Rails 3 accepts_nested_attributes_for with has_many :through relationships 使用accepts_nested_attributes_for(b / t和has_many)以单一形式创建单独的模型 - Creating separate models in single form with accepts_nested_attributes_for (b/t & has_many) 通过以下方式使用has_many:,accepts_nested_attributes_for和fields_for - Working with has_many through:, accepts_nested_attributes_for, and fields_for Rails accepts_nested_attributes_for通过以下方式不保存has_many上的关联 - Rails accepts_nested_attributes_for not saving association on has_many through Rails 4通过关系通过has_many接受hass_nested_attributes_for::_destroy无法正常工作 - Rails 4 accepts_nested_attributes_for for has_many through relationship: :_destroy is not working accepts_nested_attributes_for has_many:通过创建和删除联接模型对象,具体取决于其他模型 - accepts_nested_attributes_for has_many :through Create and delete join model objects, depending on other model
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM