17

ユーザーとロールという HABTM 関係を持つ 2 つのモデルがあります。

  • ユーザー - has_and_belongs_to_many :roles
  • 役割 - 所属先:ユーザー

結合 (users_roles テーブル) に、user_id と role_id が一意でなければならないという一意性制約を追加したいと考えています。Rails では、次のようになります。

validates_uniqueness_of :user, :scope => [:role]

もちろん、Rails では通常、HABTM アソシエーションで結合関係を表すモデルはありません。

だから私の質問は、制約を追加するのに最適な場所はどこですか?

4

4 に答える 4

38

結合テーブルに一意性を追加できます

add_index :users_roles, [ :user_id, :role_id ], :unique => true, :name => 'by_user_and_role'

結合テーブルでは、Rails に複合キーがない場合の最善の回避策は何ですか? を参照してください。

その場合、データベースで例外が発生するため、処理する必要があります。
この場合にレール検証を使用する準備ができているかどうかはわかりませんが、次のように独自の検証を追加できます。

class User < ActiveRecord::Base
has_and_belongs_to_many :roles, :before_add => :validates_role

データベース呼び出しを黙ってドロップし、成功を報告します。

def validates_role(role)
  raise ActiveRecord::Rollback if self.roles.include? role
end

ActiveRecord::Rollback は内部的にキャプチャされますが、再発生しません。

編集

カスタム検証を追加している部分は使用しないでください。それはちょっと動作しますが、より良い代替手段があります。

:uniq@Spyros が別の回答で提案したように、関連付けのオプションを使用します。

class Parts < ActiveRecord::Base
  has_and_belongs_to_many :assemblies, :uniq => true, :read_only => true
end  

(このコード スニペットは Rails Guides v.3 のものです)。Rails Guides v 3.2.13を読んで、4.4.2.19 を探してください:uniq

include?Rails Guide v.4 では、競合状態の可能性があるため、一意性のチェックに 使用しないように特に警告しています。

結合テーブルへのインデックスの追加に関する部分は残ります。

于 2011-02-14T13:22:11.147 に答える
11

Rails 5distinctでは、代わりにuniq

また、一意性を確保するためにこれを試してください

has_and_belongs_to_many :foos, -> { distinct } do
  def << (value)
    super value rescue ActiveRecord::RecordNotUnique
  end
end
于 2016-09-22T00:29:49.313 に答える
5

:uniq => true を使用すると、オブジェクトが重複しないことが保証されると思います。ただし、データベースに 2 番目の重複を書き込む前に重複が存在するかどうかを確認したい場合は、おそらく find_or_create_by_name_and_description(...) を使用します。

(もちろん、名前と説明は列の値です)

于 2011-02-14T03:57:11.847 に答える
5

私は好む

class User < ActiveRecord::Base
  has_and_belongs_to_many :roles, -> { uniq }
end

その他のオプション参照はこちら

于 2014-05-26T05:11:31.240 に答える