İç içe yerleştirilmiş öznitelikleri çoktan çoğa kaydederken hata olmalıdır

Jan 21 2021

Rails 6'da çoktan çoğa ilişkilendirme yoluyla iç içe geçmiş kayıtları kaydetmeye çalışılıyor, ancak "etiket mevcut olmalıdır" hatası alınıyor. Etiket, Gönderiler ve Etiketler (çoktan çoğa) arasındaki çapraz referans tablosu olan post_tags için bir ebeveyndir. Yapmak istediğim, yeni bir gönderi oluşturulduğunda, gönderi formunda seçilen etiketlerle ilgili post_tag kayıtlarını kaydetmek. İlgili bazı gönderilere baktım: burada ve burada ve ters_of, otomatik kaydetme: doğru ve isteğe bağlı: doğru kullanmayı denedim, ancak bunlar işe yaramıyor gibi görünüyor.

İşte sahip olduğum şey:

Modeller

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

Kontrolcü

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

Form

<%= f.fields_for :post_tags do |builder| %>
    <%= builder.collection_check_boxes :tag_id, Tag.top_used, :id, :name, include_hidden: false %>
<% end %>

Hata

   (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):

Yanıtlar

1 max Jan 21 2021 at 23:36

Açıkça "birleştirme modeli" örnekleri oluşturmanız gerekmez. tag_ids=Oluşturulan ayarlayıcıya bir dizi geçirmeniz yeterlidir 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 %>

Denetleyiciniz şöyle görünmelidir:

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

Birleştirme modeli örneklerini oluşturmak için yuvalanmış öznitelikleri ve Fields_for'u kullanmak gerçekten yalnızca birleştirme modelinde ek bilgi depolamanız gerektiğinde gereklidir.