through references rails many has_one has_and_belongs_to_many has foreign create belongs ruby-on-rails has-and-belongs-to-many unique-constraint

ruby-on-rails - many - rails model references



HABTM-restricción de singularidad (4)

Tengo dos modelos con una relación HABTM: usuario y rol.

  • usuario - has_and_belongs_to_many: roles
  • rol - corresponde_a: usuario

Quiero agregar una restricción de unicidad en la unión (tabla users_roles) que dice que user_id y role_id deben ser únicos. En Rieles, se vería como:

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

Por supuesto, en Rails, generalmente no tenemos un modelo para representar la relación de unión en una asociación HABTM.

Entonces mi pregunta es ¿dónde está el mejor lugar para agregar la restricción?


Creo que usar: uniq => true aseguraría que no obtendrás objetos duplicados. Pero, si desea verificar si existe un duplicado antes de escribir un segundo en su db, probablemente usaría find_or_create_by_name_and_description (...).

(Por supuesto, el nombre y la descripción son sus valores de columna)


En Rails 5 querrás usar distinct lugar de uniq

También, intente esto para asegurar la singularidad

has_and_belongs_to_many :foos, -> { distinct } do def << (value) super value rescue ActiveRecord::RecordNotUnique end end


Puedes agregar singularidad para unirte a la tabla

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

consulte En una tabla de combinación, ¿cuál es la mejor solución para la ausencia de Rails de una clave compuesta?

Tu base de datos generará una excepción, que debes manejar.
No conozco ninguna validación de rieles lista para usar para este caso, pero puede agregar su propia validación de esta manera:

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

Simplemente soltaría silenciosamente la llamada a la base de datos y reportaría el éxito.

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

ActiveRecord :: Rollback se captura internamente pero no se vuelve a subir.

Editar

No use la parte donde estoy agregando validación personalizada . Funciona un poco pero hay mejores alternativas.

Use la opción :uniq en asociación como @Spyros sugirió en otra respuesta:

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

(este fragmento de código es de Rails Guides v.3). Lea en Rails Guides v 3.2.13 busque 4.4.2.19: uniq

Rails Guide v.4 específicamente advierte contra el uso de include? para comprobar la singularidad debido a las posibles condiciones de la raza.

La parte sobre la adición de un índice para unirse a la tabla permanece.


yo prefiero

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

otras opciones de referencia here