ユーザーのプロファイルには1つのアドレスが割り当てられていますが、ユーザーは仮想「アドレス帳」に多くのアドレスを持つことができる一連のモデルを作成しようとしています. ユーザーは、自分のすべてのアドレスからデフォルトのアドレスを取得し、それをプロファイルに home_address として割り当てることができるはずです。
アドレスにはさまざまな種類があります。自宅の住所もありますが、追加のフィールドを持つ会社や銀行の住所もあります。そのため、ポリモーフィズムを使用する必要があります。
モデルを作成しました:
class Addresser < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
belongs_to :address, :polymorphic => true
attr_accessible :address_id, :address_type
end
class HomeAddress < ActiveRecord::Base
has_one :addresser, :as => :address, :inverse_of => :address
attr_accessible :name, :city, :zip, :street, :state, :country
end
class Profile < ActiveRecord::Base
has_one :home_address, :through => :addresser,
:source => :address, :source_type => 'HomeAddress',
:autosave => true
has_one :addresser, :as => :addressable, :inverse_of => :addressable,
:autosave => true
attr_accessible :name, :gender
end
すべてがほぼ正常に機能していますが、モデルを保存した後、Rails はフィールドの 1 つを更新していません。
profile_data = {
:name => 'Some User',
:gender => 'm'
}
address_data = {
:street => 'Streeting 7',
:country => 'PL',
:city => 'New Rails',
}
my_profile = Profile.new(profile_data)
=> #<Profile id: nil, name: "Some User", gender: "m", created_at: nil, updated_at: nil>
my_address = HomeAddress.new(address_data)
=> #<HomeAddress id: nil, street: "Streeting 7", city: "New Rails", country: "PL
my_profile.home_address = my_address
INSERT INTO `addressers` (`address_id`, `address_type`, `addressable_id`, `addressable_type`)
VALUES (NULL, 'HomeAddress', NULL, 'Profile')
COMMIT
=> #<HomeAddress id: nil, name: "Sir Adam Rails", street: "Streeting 7", city: "New Rails", country: "PL">
my_profile.save!
INSERT INTO `profiles` (`created_at`, `name`, `gender`, `updated_at`)
VALUES ('2012-06-23 10:07:51', 'Some User', 'm', '2012-06-23 10:07:51')
INSERT INTO `home_addresses` (`city`, `country`,`street`)
VALUES ('New Rails', 'PL', 'Streeting 7')
UPDATE `addressers` SET `addressable_id` = 1 WHERE `addressers`.`id` = 1
COMMIT
=> true
上記では、addressable_id は更新されますが、address_id は更新されません。これにより、データベース セッションを再度開いた後、制約が無効になり、使用できなくなります。
Addresser.first
SELECT `addressers`.* FROM `addressers` LIMIT 1
=> #<Addresser id: 1, address_id: nil, address_type: "HomeAddress", addressable_id: 1, addressable_type: "Profile">
address_id が nil であるため、profile.home_address が見つかりません。
addressable の address_id を手動で更新せずにこれを修正できますか?
私のアプリのアーキテクチャでは、いくつかの初期設定でオブジェクト全体を構築し、アトミック セーブを実行する必要があるため、(プロファイルを所有する) ユーザーが作成される前にアドレスを構築して保存することは、弱いオプションです。