0

has_many 関連付けを持つ 2 つのモデルがあります。ただし、「多数」のうち、プライマリは 1 つだけです。これを設計する 1 つの方法を次に示します。

アプローチ #1

class Person < ActiveRecord:Base
  has_many :address

  def find_primary
    self.address.where('is_primary = ?', "true").first
  end
end

class Address < ActiveRecord:Base
  belongs_to :person
  attr_protected :is_primary

  def make_primary
    self.person.address.each { |a| a.update_attribute(:is_primary, false) }
    self.update_attribute(:is_primary,true)
  end

  def is_primary?
    self.is_primary
  end
end

make_primaryその人の住所の数がO(n)であるのが好きではありません。また、マルチスレッド環境 (つまりパッセンジャーですよね?) でも問題になる可能性があります。make_primaryたぶん、アプローチ#2でよりうまく機能する最適化があるでしょうか?

また、複数のアドレスをプライマリにすることができる、見つけにくいバグが簡単に発生する可能性があります。

アプローチ #2

class Person < ActiveRecord:Base
  has_many :address
  belongs_to :primary_address, :class_name => 'Address', :foreign_key => :primary_address_id
end

class Address < ActiveRecord:Base
  belongs_to :person
  has_one :person_as_primary, :class_name => 'Person', :foreign_key => :primary_address_id

  def make_primary
    self.person.primary_address = self
    self.save!
  end
end

マルチスレッドと O(n) の問題を回避することは別として、このアプローチはfind_primary単にself.primary_address.

ただし、ここで懸念されるのは、その保証がないことです。

[person, nil].include?(person.primary_address.person_as_primary)

ここに私の質問があります:

1)私が言及しなかった追加の利点/欠点はありますか?

2) 他にどのようなアプローチを検討する必要がありますか? 特に、上記の問題のいずれも発生しないものはありますか?

4

1 に答える 1

0

ソリューションを一意のインデックスの形でデータベースにプッシュします。これにより、一度に 1 つだけがプライマリになることが保証されます。同時実行性が問題にならなかった場合は、Rails レベルで一意性制約を使用できますが、同時実行性がアプリにとって懸念事項のようです。

于 2013-04-22T17:56:20.277 に答える