2011-01-19 13 views
15

Pasado todo el día en Google, pero no puedo encontrar una respuesta. : \Rieles: tiene y pertenece a muchos (HABTM) - crear asociación sin crear otros registros

Tengo una relación HABTM entre usuarios y Core_Values.

class CoreValue < ActiveRecord::Base 
    has_and_belongs_to_many :users 

class User < ActiveRecord::Base 
    has_and_belongs_to_many :core_values 

En mi controlador, tengo que hacer dos cosas separadas:

  1. Si no existe un CoreValue, crear uno nuevo y asociarlo con un identificador de usuario dado, y
  2. Suponiendo conozco a un CoreValue particular, existe ya, crear la asociación sin crear nuevos usuarios o CoreValues ​​

para # 1, tengo que esto funcione:

User.find(current_user.id).core_values.create({:value => v, :created_by => current_user.id}) 

Esto crea un nuevo CoreValue con: value y: created_by y crea la asociación.

Para el n. ° 2, probé algunas cosas, pero no puedo crear la asociación SOLAMENTE.

Gracias por su ayuda!

Respuesta

21

Puede hacerlo en un procedimiento de dos pasos, utilizando el muy útil método find_or_create. find_or_create primero intentará encontrar un registro, y si no existe, créelo. Algo como esto debe hacer el truco:

core_value = CoreValue.find_or_create_by_value(v, :created_by => current_user.id) 
current_user.core_values << core_value 

Algunas notas:

  • La primera línea será encontrar o crear el valor v. Si no existe y se crea, establecerá el created_by en current_user.id.
  • No hay necesidad de hacer User.find(current_user.id), ya que eso devolvería el mismo objeto que current_user.
  • current_user.core_values es una matriz y puede agregar fácilmente otro valor utilizando <<.

Por razones de brevedad, la siguiente sería el mismo que el ejemplo de código anterior:

current_user.core_values << CoreValue.find_or_create_by_value(v, :created_by => current_user.id) 
+0

Gracias! No sabía que core_values ​​era una matriz, y ciertamente no sabía que agregarla crearía un INSERT. ¡Dulce! ¿Alguna manera de crear solo la asociación si el registro no existe? Buscaré los métodos de matriz, supongo. Tal vez current_user.core_values.include? – jmccartie

+0

@jmccartie Esa podría ser una forma de hacerlo, sí. Para aclarar, creo que debería añadir que 'core_values' no es * siempre * una matriz, como saben, pueden llamar a' core_values.create', que no es un método de matriz válido. Una mejor definición sería que "actúa como una matriz". – vonconrad

+0

gracias por el seguimiento. ¿incluir? no funcionará tratando de averiguar si puedo encontrar la nueva ID core_value dentro de current_user.core_values ​​... hmmmm – jmccartie

4

añadir un método en su modelo de usuario:

class User < ActiveRecord::Base 
    def assign_core_value(v) 
    core_values.find_by_name(v) || (self.core_values << 
     CoreValue.find_or_create_by_name(:name => v, :created_by => self)).last 
    end 
end 

El método assign_core_value satisface los requerimientos 1, 2 y devuelve el valor central asignado al usuario (con el nombre de pila).

Ahora usted puede hacer lo siguiente:

current_user.assign_core_value(v) 

Nota 1

lógica método es el siguiente:

1) Comprueba si el CoreValue ya está asociado con el usuario. Si es así, no se realiza ninguna acción, se devuelve el valor central.

2) Comprueba si existe CoreValue con el nombre dado. Si no, crea el CoreValue. Asocia el valor central (creado/encontrado) con el usuario.

+0

¡Gracias! Buena idea agregar esto al modelo de usuario. ¿Esto creará la asociación si ya existe? – jmccartie

+0

Actualicé mi respuesta con alguna explicación. Echar un vistazo. –

0

Active Record ya le proporciona un método. En su caso,

val = CoreValue.find_by_value(v) 
current_user.core_values << val 

También puede pasar una cantidad de objetos a los mismos de esta manera. Todas las asociaciones se crearán

Comprobar this para más información

Cuestiones relacionadas