実現したいこと
投稿を作成する際に関連のある投稿を選んで、その関連を管理する中間テーブルへのレコード保存も同時に行う
前提
- pop = 投稿です。意味が取りづらくて申し訳ありません。
DBスキーマ
Ruby
1## 投稿モデル(pop)2create_table "pops", force: :cascade do |t|3 t.string "title"4 t.text "body"5 t.boolean "is_old", default: false, null: false6 t.datetime "created_at", null: false7 t.datetime "updated_at", null: false8 t.integer "category_id", null: false9 t.index ["category_id"], name: "index_pops_on_category_id"10 end11## 投稿の並列関係を管理するモデル(今回問題が発生しているモデル)12create_table "parallel_relations_of_pops", force: :cascade do |t|13 t.integer "pop_id"14 t.integer "parallel_pop_id"15 t.datetime "created_at", null: false16 t.datetime "updated_at", null: false17 end18 19## 投稿の親子関係を管理するモデル20 create_table "parent_relations_of_pops", force: :cascade do |t|21 t.integer "parent_id"22 t.integer "child_id"23 t.datetime "created_at", null: false24 t.datetime "updated_at", null: false25 end
発生している問題・エラーメッセージ
投稿を保存するときに同時に並列関係を管理する中間テーブルへの保存を行いたいが、pop_idが入っていない状態で保存していることでエラーになっている。
Validation failed: Active parallel relations pop can't be blank
該当のソースコード
モデル
pop.rb
Ruby
1has_many :active_parallel_relations, class_name: "ParallelRelationsOfPop", foreign_key: "pop_id", dependent: :destroy, inverse_of: :parallelling2has_many :passive_parallel_relations, class_name: "ParallelRelationsOfPop", foreign_key: "parallel_pop_id", dependent: :destroy3has_many :parallelling_pops, through: :active_parallel_relations, source: :parallelled4has_many :parallelled_pops, through: :passive_parallel_relations, source: :parallelling5accepts_nested_attributes_for :active_parallel_relations, allow_destroy: true, reject_if: lambda { |attributes| attributes['parallel_pop_id'].blank? }
parallel_relations_of_pop.rb
Ruby
1belongs_to :parallelling, class_name: "Pop", foreign_key: "pop_id", inverse_of: :active_parallel_relations2belongs_to :parallelled, class_name: "Pop", foreign_key: "parallel_pop_id"
Controller
pops_controller.rb
Ruby
1before_action :set_pop_with_id, only: [:show, :edit, :update, :destroy, :parent_pops, :child_pops, :parallel_pops]2def new3 @pop = Pop.new4 @pop.parent_relations.build 5 @pop.active_parallel_relations.build 6 end7 8def create9 @pop = Pop.build(pop_params)10 if @pop.save!11 redirect_to pops_path 12 end13 end14 15private16 def pop_params17 params.require(:pop).permit(18 :title,19 :body,20 :is_old,21 :category_id,22 parent_relations_attributes: [:id, :parent_id, :_destroy],23 active_parallel_relations_attributes: [:id, :parallel_pop_id, :_destroy]24 )25 end26 27def set_pop_with_id28 @pop = Pop.find(params[:id])29 end
view
_form.html.erb
Ruby
1<%= form_with(model: pop) do |form| %> 2 <div><%= form.label :title, 'Title' %></div>3 <div><%= form.text_field :title %></div> 4 <div><%= form.label :body, 'Body' %></div>5 <div><%= form.text_area :body %></div> 6 <div><%= form.label :is_old, 'Make this old' %></div>7 <div><%= form.check_box :is_old %></div> 8 <div><%= form.label :category_id, 'Category' %></div>9 <div><%= form.collection_select :category_id, Category.all, :id, :name, { prompt: 'Choose' } %></div> 10 <%= form.fields_for :parent_relations do |parent| %> 11 <div><%= parent.label :parent_id, 'Parent' %></div> 12 <div><%= parent.collection_select :parent_id, Pop.where.not(id: pop.id), :id, :title, { prompt: 'Choose' } %></div>13 <% end %> 14 <%= form.fields_for :active_parallel_relations do |parallel| %>15 <div><%= parallel.label :parallel_pop_id, 'Parallel' %></div> 16 <div><%= parallel.collection_select :parallel_pop_id, Pop.where.not(id: pop.id), :id, :title, { prompt: 'Choose' } %></div>17 <% end %> 18 <div><%= form.submit %></div>19<% end %>
new.html.erb
Ruby
1<h1>Creating Pops</h1>2<%= render "form", pop: @pop, parent_relations_of_pop: @parent_relations_of_pop, parallel_relations_of_pops: @parallel_relations_of_pops %> 3<%= link_to "pops", pops_path %>
試したこと
accepts_nested_attributes_forを利用する際には、inverse_ofの設定が必要という情報が多かったので、設定していますが上手くいきません。
また、同じような仕組みで親子関係を管理するモデルを利用しているのですが、
- 投稿を作成するフォームで親にしたい投稿を選ぶ
- 投稿を作成するボタンを押す
- 投稿そのものと、親子関係を管理するテーブルへのレコード作成が同時に行われる
という感じでそちらは上手く行っています。何が違うのか全くわかりません。。
parent_relations_of_pop.rb
(親子関係を管理するモデルのモデルファイル)
Ruby
1belongs_to :parent, class_name: "Pop", foreign_key: "child_id", inverse_of: :parent_relations2belongs_to :child, class_name: "Pop", foreign_key: "parent_id"
pop.rb
Ruby
1has_many :parent_relations, class_name: "ParentRelationsOfPop", foreign_key: "child_id", dependent: :destroy, inverse_of: :parent2has_many :child_relations, class_name: "ParentRelationsOfPop", foreign_key: "parent_id", dependent: :destroy3has_many :parent_pops, through: :parent_relations, source: :child4has_many :child_pops, through: :child_relations, source: :parent5accepts_nested_attributes_for :parent_relations, allow_destroy: true, reject_if: lambda { |attributes| attributes['parent_id'].blank? }
補足情報(FW/ツールのバージョンなど)
Ruby on Rails: 7.1.2
0 コメント