(タイトルがルー語っぽくなりました)
はじめに
以下の様なhas_many throughな関係があるとします
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
validates :user_id, presence: true
validates :group_id, presence: true
end
class Group < ActiveRecord::Base
has_many :memberships
accepts_nested_attributes_for :memberships, allow_destroy: true
has_many :users, through: :memberships
end
Userが複数のGroupに所属できるモデルの関連です
Groupの作成時に所属Userを選択できるようにaccepts_nested_attributes_for :memberships
を設定しました
formは以下のようにnested_formを使ってfields_forを作ります
= nested_form_for @group do |f|
= f.fields_for :memberships do |nf|
= nf.hidden_field :id
= nf.collection_select :user_id, User.all, :id, :name
= nf.link_to_remove 'Remove'
= f.link_to_add 'Add User', :memberships
= f.text_field :name
= f.submit
こうしておくとGroupのformからUserを複数選択してGroup作成と同時に所属Userも登録できる__はず__なんですが…
関連先でvalidationエラーする
なんとMembershipにvalidates :group_id, presence: true
が設定されているため、Groupの作成時にMembership上にgroup_idが必要です、というエラーが発生してしまいます。。。
Membership group は必須項目です
いや、知ってますが……
inverse_ofとvalidationを関連の名前にする
以下のようにするとidが存在しなくても、オブジェクト同士の関係があればvalidationエラーにならないことがわかりました
class Group
+ has_many :memberships, inverse_of: :group
- has_many :memberships
end
class Membership
+ validates :group, presence: true
- validates :group_id, presence: true
end
inverse_ofを使用するとbelongs_to側からsave前でも関連先が確認できるようにあるみたいです、その上でgroup_idではなく関連の名前でvalidationを書いておくとちゃんとpresence: trueを確認できるようになるので通るみたいです。