0

私は Rails アプリ (Ruby 1.9.2 / Rails 3.0.3) に取り組んでおり、人々とそのメンバーシップをさまざまなチームに経時的に追跡しています。重複する Person オブジェクトを結合するスケーラブルな方法を考え出すのに苦労しています。「結合」とは、重複する Person オブジェクトを 1 つを除いてすべて削除し、その Person の残りのコピーを指すようにすべての参照を更新することを意味します。ここにいくつかのコードがあります:

モデル:

人物.rb

class Person < ActiveRecord::Base
  has_many :rostered_people, :dependent => :destroy
  has_many :rosters, :through => :rostered_people
  has_many :crews, :through => :rosters

    def crew(year = Time.now.year)
      all_rosters = RosteredPerson.find_all_by_person_id(id).collect {|t| t.roster_id}
      r = Roster.find_by_id_and_year(all_rosters, year)
      r and r.crew
    end
end

クルー.rb

class Crew < ActiveRecord::Base
  has_many :rosters
  has_many :people, :through => :rosters
end

Roster.rb

class Roster < ActiveRecord::Base
  has_many :rostered_people, :dependent => :destroy
  has_many :people, :through => :rostered_people
  belongs_to :crew
end

RosteredPerson.rb

class RosteredPerson < ActiveRecord::Base
  belongs_to :roster
  belongs_to :person
end

Personオブジェクトは名前と姓だけで作成できますが、(社会保障番号のようなものと考えてください) と呼ばれる真に一意のフィールドが 1 つあり、オプションでまたはアクションiqcs_numに格納できます。createupdate

したがって、createandupdateアクション内で、重複する Person オブジェクトのチェックを実装し、重複を削除してから、残りの を指すようにすべてのcrewand参照を更新したいと思います。rosterPerson

.update_all各モデルで安全に使用できますか? 特に、将来的に Person に依存するモデルを追加する可能性が高く、find_duplicate 関数を維持することを覚えておく必要がないため、これは一種の強引な方法のように思えます。

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

4

1 に答える 1

0

これに対処する「スケーラブル」な方法は、重複除外プロセスをアプリの通常の機能の一部にすることです。レコードを保存するときはいつでも、重複していないことを確認してください。これを行うには、Person モデルにコールバックを追加します。おそらく次のようなものです:

before_save :check_for_duplicate

def check_for_duplicate
  if iqcs_num
    dup = Person.find_by_iqcs_num(self.iqcs_num)
    if dup && dup.id != self.id
      # move associated objects to existing record
      dup.crews = dup.crews + self.crews

      # update existing record
      dup.update_attributes(:name => self.name, :other_field => self.other_field)

      # delete this record
      self.destroy

      # return false, so that no other callbacks get triggered
      return false
    end
  end
end

Person オブジェクトを格納するテーブルの iqcs_num 列にインデックスを付けて、レコード数が増えてもこのルックアップが効率的に行われるようにする必要があります。結局、Person レコードを更新するたびにルックアップが実行されます。 .

コールバックを最新の状態に保つことから逃れることができるかどうかはわかりません.さまざまな種類の関連オブジェクトを別の方法で移動する必要がある可能性が非常に高いです. 一方、それは 1 か所にしか存在せず、関連付けを追加するのと同じ場所 (モデル内) です。

最後に、コードが機能していることを確認するために、重複が存在しないように Person モデルに検証を追加することをお勧めします。何かのようなもの:

validates :iqcs_num, :uniqueness => true, :allow_nil => true
于 2013-01-17T16:32:31.840 に答える