4

親の親を持つネストされた属性のRailsでの範囲指定された一意性の検証に問題があります。

バックグラウンド

私は3つのモデルを持つRails 4アプリケーションを持っています:

#app/models/account.rb
class Account < ActiveRecord::Base
  has_many :contacts, dependent: :destroy
end

#app/models/contact.rb
class Contact < ActiveRecord::Base
  belongs_to :account
  has_many :email_addresses, dependent: :destroy, validate: :true, inverse_of: :contact
  accepts_nested_attributes_for :email_addresses,allow_destroy: true
  validates :email_addresses, presence: true
end

#app/models/email_address.rb
class EmailAddress  < ActiveRecord::Base
  belongs_to :contact, inverse_of: :email_addresses

  validates :label, presence: true
  validates :contact, presence: true
  validates :email, uniqueness: true, presence: true
  validates_email_format_of :email
end

問題

スコープを作成して、モデル EmailAddressの属性:email がアカウント レベルで一意であることを確認します(アカウントは Contact の親であり、それ自体が EmailAddress の親です)。

http://guides.rubyonrails.org/active_record_validations.htmlで提案されているように、私は試しました:

 class EmailAddress  < ActiveRecord::Base
  belongs_to :contact, inverse_of: :email_addresses

  validates :label, presence: true
  validates :contact, presence: true
  validates :email, presence: true, uniqueness: { scope: :account, 
                    message: "This contact email is already taken" }
  validates_email_format_of :email
 end

これにより、「列 email_addresses.account が存在しません」というエラーが発生します。どうすればよいですか?

助けてくれてありがとう!

4

2 に答える 2

12

パフォーマンスの点でより良いオプションを以下に説明します。テスト済みで、問題なく動作します。

なんで?

多数の電子メールが関係している場合、電子メールのマッピングは多くのリソースを消費する可能性があるため、データベースで直接スコープを実行することをお勧めします。

どのように?

EmailAddress モデルで account_id をキャッシュし、検証前のメソッドを実行します。

1) 移行を作成します。

change_table :email_addresses do |t|
  t.references :account, index: true
end
add_index :email_addresses, [:account_id, :email], unique: true

2) 移行する

3) EmailAddress モデルを更新する

#app/models/email_address.rb

class EmailAddress < ActiveRecord::Base
  belongs_to :contact, inverse_of: :email_addresses
  belongs_to :account

  validates :label, presence: true
  validates :contact, presence: true
  validates_email_format_of :email
  validates_uniqueness_of :email, allow_blank: false, scope: :account

  before_validation do
    self.account = contact.account if contact
  end

end
于 2014-06-27T07:27:13.203 に答える