Rubyで次のDB移行を想定します。
create_table:question_votes do | t | t.integer:user_id t.integer:question_id t.integer:vote t。タイムスタンプ 終了
さらに、DBの行に一意の(user_id、question_id)ペアが含まれていると仮定します。それを達成するためにモデルに入れる適切なダストは何ですか?
validates_uniqueness_of:user_id、:question_id
validates_uniqueness_of :user_id, :scope => [:question_id]
別の列(またはそれ以上)を含める必要がある場合は、それをスコープに追加することもできます。例:
validates_uniqueness_of :user_id, :scope => [:question_id, :some_third_column]
Mysqlを使用している場合は、一意のインデックスを使用してデータベースで実行できます。それは次のようなものです:
add_index :question_votes, [:question_id, :user_id], :unique => true
これにより、question_id/user_idの2倍にされた組み合わせを保存しようとすると例外が発生するため、どの例外をキャッチして処理するかを実験して把握する必要があります。
RailsGuides から。 validates
も機能します:
class QuestionVote < ActiveRecord::Base
validates :user_id, :uniqueness => { :scope => :question_id }
end
Railsは一意性の検証が行われると100%信頼性が高くならないため、両方を使用するのが最善の方法です。
以下を使用できます。
validates :user_id, uniqueness: { scope: :question_id }
安全面で100%になるには、この検証をデータベース(MySQL ex)に追加します
add_index :question_votes, [:user_id, :question_id], unique: true
そして、あなたはコントローラを使って以下を処理することができます:
rescue ActiveRecord::RecordNotUnique
これで、100%安全になり、重複した値がなくなります:)
独自の検証メソッドを作成する場合を除いて、validates_uniqueness_of
で実行できる最善の方法は次のとおりです。
validates_uniqueness_of :user_id, :scope => "question_id"
これにより、挿入しようとしているレコードと同じquestion_idを持つすべての行内でuser_idが一意であることを確認します。
しかし、それはあなたが望むものではありません。
:user_id
と:question_id
の組み合わせがデータベース全体で一意になるように探していると思います。
その場合、次の2つのことを行う必要があります。
新しいレコードを作成するときは、検証の時点では親モデルのid
がまだ存在しないため、機能しません。
これでうまくいくはずです。
class B < ActiveRecord::Base
has_many :ab
has_many :a, :through => :ab
end
class AB < ActiveRecord::Base
belongs_to :b
belongs_to :a
end
class A < ActiveRecord::Base
has_many :ab
has_many :b, :through => :ab
after_validation :validate_uniqueness_b
private
def validate_uniqueness_b
b_ids = ab.map(&:b_id)
unless b_ids.uniq.length.eql? b_ids.length
errors.add(:db, message: "no repeat b's")
end
end
end
上記のコードでは、すべてのb_id
パラメータのコレクションの次に、一意の値と取得されたb_idの間の長さが等しいかどうかを比較します。
等しい場合は、繰り返しがないことを意味しますb_id
。
注:データベースの列に一意を追加することを忘れないでください。