ต้องมีข้อผิดพลาดเมื่อบันทึกแอตทริบิวต์ที่ซ้อนกันผ่านหลายรายการ
พยายามบันทึกเร็กคอร์ดที่ซ้อนกันผ่านการเชื่อมโยงแบบกลุ่มต่อกลุ่มใน Rails 6 แต่ได้รับข้อผิดพลาด "ต้องมีแท็ก" แท็กคือพาเรนต์ของ post_tags ซึ่งเป็นตารางอ้างอิงโยงระหว่างโพสต์และแท็ก (หลายต่อหลายแท็ก) สิ่งที่ฉันต้องการทำคือเมื่อสร้างโพสต์ใหม่ให้บันทึกเรกคอร์ด post_tag ที่เกี่ยวข้องกับแท็กที่เลือกในแบบฟอร์มโพสต์ ฉันดูโพสต์ที่เกี่ยวข้องบางส่วน: ที่นี่และที่นี่และลองใช้ inverse_of บันทึกอัตโนมัติ: จริงและไม่บังคับ: จริง แต่ดูเหมือนจะไม่ได้ผล
นี่คือสิ่งที่ฉันมี:
โมเดล
class Post < ApplicationRecord
has_many :post_tags, dependent: :destroy, inverse_of: :post, autosave: true
has_many :tags, through: :post_tags
end
class PostTag < ApplicationRecord
belongs_to :post
belongs_to :tag
end
class Tag < ApplicationRecord
has_many :post_tags, dependent: :destroy, inverse_of: :tag, autosave: true
has_many :posts, through: :post_tags
end
ตัวควบคุม
PostsController < ApplicationController
def new
@post = Post.new
@tags= Tag.all
@post.post_tags.build
end
def create
@post = Post.new(post_params)
@post.post_tags.build
if @post.save
...
end
end
private
def post_params
params.require(:post).permit(:title, :content, :user_id, post_tags_attributes: [tag_id: []])
end
end
แบบฟอร์ม
<%= f.fields_for :post_tags do |builder| %>
<%= builder.collection_check_boxes :tag_id, Tag.top_used, :id, :name, include_hidden: false %>
<% end %>
ข้อผิดพลาด
(0.4ms) ROLLBACK
↳ app/controllers/posts_controller.rb:229:in `create'
Completed 422 Unprocessable Entity in 41ms (ActiveRecord: 3.7ms | Allocations: 15178)
ActiveRecord::RecordInvalid (Validation failed: Post tags tag must exist):
คำตอบ
คุณไม่จำเป็นต้องสร้างอินสแตนซ์ "join model" อย่างชัดเจน คุณเพียงแค่ต้องผ่านอาร์เรย์กับหมาที่สร้างขึ้นโดยtag_ids=
has_many :tags, through: :post_tags
<%= form_with(model: @post) %>
...
<div class="field">
<%= f.label :tag_ids %>
<%= f.collection_check_boxes :tag_ids, @tags, :id, :name %>
</div>
...
<% end %>
คอนโทรลเลอร์ของคุณควรมีลักษณะดังนี้:
PostsController < ApplicationController
def new
@post = Post.new
@tags = Tag.all
end
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, status: :created
else
@tags = Tag.all
render :new
end
end
private
def post_params
params.require(:post)
.permit(:title, :content, :user_id, tag_ids: [])
end
end
การใช้แอตทริบิวต์ที่ซ้อนกันและfields_forเพื่อสร้างอินสแตนซ์โมเดลการเข้าร่วมนั้นจำเป็นจริงๆก็ต่อเมื่อคุณต้องการเก็บข้อมูลเพิ่มเติมในโมเดลการเข้าร่วม