Techioz Blog

Rails アクティブ レコード オブジェクトが理由もなく作成される

概要

Rails 7 を使用しています。Post、Venue、VenuePost モデルがあります。それらは次のようになります。

class Post < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
  accepts_nested_attributes_for :venue_posts
end

class Venue < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
end

class VenuePost < ApplicationRecord
  belongs_to :post
  belongs_to :venue
end

これで、Posts#new アクションは次のようになります。

def new
  @post = Post.new
  Venue.all.each do |v|
    vp = @post.venue_posts.build(venue: v)
    v.venue_posts << vp
  end
end

問題は、作成アクションを呼び出さなくても、投稿がデータベースに保存され続け、インデックス ページに表示されることです。それはなぜでしょうか。また、新しい投稿を作成するときに会場ごとに 1 つの VenuePost をインスタンス化し、それをフォームで編集して保存できるという、現在と同じ動作を維持しながらそれを防ぐにはどうすればよいでしょうか。

読んでくれてありがとう

参考のために編集します:

強力なパラメータ:

def post_params
  params.require(:post).permit(:title, :content, venue_posts_attributes: [:id, :title, :content])
end

ネストされたフォーム:

<%= form.fields_for :venue_posts do |vpf| %>
  <div>
      <strong>Venue:</strong>
      <%# vpf.object.venue.name %>
      <%= vpf.label :title, style: "display: block" %>
      <%= vpf.text_field :title %>
      <%= vpf.label :content, style: "display: block" %>
      <%= vpf.text_area :content %>
  </div>
<% end %>

Post のメソッドを作成します。

def create
  @post = Post.new(post_params)

  respond_to do |format|
    if @post.save
      format.html { redirect_to post_url(@post), notice: "Post was successfully created." }
      format.json { render :show, status: :created, location: @post }
    else
      format.html { render :new, status: :unprocessable_entity }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end

現在の新しい投稿方法:

def new
  @post = Post.new
  Venue.all.each do |v|
    @post.venue_posts.new(venue: v)
  end
end

解決策

<< によりレコードが保存されると思います。これは少なくともドキュメントで暗示されています。

会場ごとに投稿をインスタンス化する代わりに、次の調整を行うことができるはずです。

class Post < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
  has_many :venues, through: :venue_posts
end

class Venue < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
  has_many :posts, through: :venue_posts
end

そしてコントローラーアクションでは

def new
  Venue.all.each {|v| v.posts.build}
end