少し調べてみると、この解決策が最も簡単なようです。まず、Role
モデルで、検証する代わりにuser_id
、検証しuser
ます。
validates :user, :presence => true
次に、モデルで、通話User
に追加:inverse_of => :user
します。has_many
has_many :roles, :inverse_of => :user
その後、期待どおりに機能します。
irb(main):001:0> @user = User.new
=> #<User id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> @user.roles << Role.new(:name => "blah")
=> [#<Role id: nil, user_id: nil, name: "blah", created_at: nil, updated_at: nil>]
irb(main):003:0> @user.roles[0].user
=> #<User id: nil, created_at: nil, updated_at: nil>
irb(main):004:0> @user.save
(0.1ms) begin transaction
SQL (3.3ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Fri, 04 Jan 2013 02:29:33 UTC +00:00], ["updated_at", Fri, 04 Jan 2013 02:29:33 UTC +00:00]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
SQL (0.2ms) INSERT INTO "roles" ("created_at", "name", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["created_at", Fri, 04 Jan 2013 02:29:34 UTC +00:00], ["name", "blah"], ["updated_at", Fri, 04 Jan 2013 02:29:34 UTC +00:00], ["user_id", 3]]
(1.9ms) commit transaction
=> true
irb(main):005:0> @user.roles.first
=> #<Role id: 4, user_id: 3, name: "blah", created_at: "2013-01-04 02:29:34", updated_at: "2013-01-04 02:29:34">
ただし、これでも2つのSQLトランザクションが生成されることに注意してください。1つはユーザーを保存するためのもので、もう1つは役割を保存するためのものです。どうすればそれを回避できるかわかりません。
参照:Railsとの関連付けに属するの存在をどのように検証できますか?