5

次の(サニタイズされた)モデルがあります。

 class Person < ActiveRecord::Base

      attr_accessible :name, :first_name, :last_name, :age, :job_title, :salary, :ssn, :prison_convictions, :addresses_attributes

      has_many :addresses, inverse_of: :person

      accepts_nested_attributes_for :addresses, allow_destroy: true

 end



 class Address < ActiveRecord::Base

      attr_accessible :zip_code, :street,:house_number,
 :unique_per_person_government_id

      belongs_to :person, inverse_of: :addresses

      validates_uniqueness_of :unique_per_person_government_id, scope: :person_id
 end

問題は次のとおりです。

Person Joe Shmoe が現在自分に関連付けられている 2 つのアドレスを持っているとします。

666 Foo Street, 12345 の一意の ID: 「ABCDEFG」および 777 Lucky Avenue, 54321 の一意の ID: 「GFEDCBA」</p>

そして、次の投稿がフォームから来たとしましょう:

 {:addresses_attributes =>
 { [0] => {:unique_per_person_government_id => “ABCDEFG”, :street=> “Foo Street”, :house_number => 666, :zip_code=>12345, _destroy => 1}
 [1] => {:unique_per_person_government_id => “ABCDEFG”, :street=>”Bar Street”, :house_number => 888, :zip_code => 12345, _destroy => 0}
 }

この動作は、2 番目の (つまり、新しい) レコードが最初に一意性について検証され、検証に失敗するように見えます。

marked_for_destruction?私が望む動作は、それ以上の検証を行う前に、すべての要素を非常に単純に削除することです。

このようにライフサイクルを再配線するにはどうすればよいですか? これを達成するためのより良い方法はありますか?

ありがとう!

4

1 に答える 1

0

私はこれを次のように解決しました:

class Person < ActiveRecord::Base
  attr_accessible :name, :first_name, :last_name, :age, :job_title, :salary, :ssn, :prison_convictions, :addresses_attributes

  has_many :addresses, inverse_of: :person

  accepts_nested_attributes_for :addresses, allow_destroy: true

  def validate_addresses
    codes = {}
    addresses.each do |a|
      if codes.key?(a.unique_per_person_government_id) and not a.marked_for_destruction?
        codes[a.unique_per_person_government_id] = codes[a.unique_per_person_government_id]+1
        if codes[a.unique_per_person_government_id] > 1
          return false
        end
      elsif not codes.key?(a.unique_per_person_government_id) and a.marked_for_destruction?
        codes[a.code] = 0
      elsif not codes.key?(a.unique_per_person_government_id) and not a.marked_for_destruction?
        codes[dacode] = 1
      end
    end
    return true
  end
end


class Address < ActiveRecord::Base
  before_save :validate_addresses

  attr_accessible :zip_code, :street,:house_number, :unique_per_person_government_id

  belongs_to :person, inverse_of: :addresses

  validates_uniqueness_of :unique_per_person_government_id, scope: :person_id, unless: :skip_validation?

  def skip_validation?
    person.addresses.each do |a|
      if unique_per_person_government_id == a.code and id != a.id
        return false unless a.marked_for_destruction?
      elsif id == a.id and a.marked_for_destruction?
        return false
      end
    end
    return true
  end
end

したがって、一意性を強制し、無効なアドレスを持つ人が保存するのを防ぎますが、破棄のマークが付けられたアイテムは無視します. 誰かが同様の問題を抱えていて、より優れた/アルゴリズム的にシンプル/読みやすい解決策を持っていて、それを共有したい場合、それは素晴らしいことです:D

于 2013-01-27T09:51:47.970 に答える