2012-07-27 7 views
9

Supongamos que tengo una asociación ActiveRecord como:¿Cuándo debería validar la presencia de un objeto de asociación ActiveRecord frente a su id?

class City < ActiveRecord::Base 
    belongs_to :state 
end 

Una ciudad sin un estado debe ser válida. Parece que ambos son posibles validaciones:

validates :state, presence: true 
# OR 
validates :state_id, presence: true 

yo supongo que son idénticos, ya que:

  • belongs_to crea métodos state y state=
  • state= establece el state_id

Sin embargo, acabo de corregir una especificación anómala al cambiarla a c diablos para la identificación en lugar del objeto.

¿Estas dos formas de validación son aceptables? Si es así, ¿cuándo usarías uno u otro?

+0

¿Podemos ver sus especificaciones originales y fijas? – deefour

Respuesta

12

validates :state usará la relación de ciudad a estado (el belongs_to) junto con la clave externa mientras que validates :state_id solo usará la columna state_id y verá si tiene algún valor.

Mi método preferido es validar state (la relación) ya que esto requiere la presencia de la clave y la relación.

La validación de state_id funcionará, ya que se asegurará de que exista una identificación de estado, sin embargo, no verificará la validez del código, es decir, que un estado 'existe' realmente para cualquier clave de estado dada en City.

Básicamente, si las claves foráneas (para state_id) utilizadas en City existen como registros reales en estado, el efecto es el mismo. La diferencia se mostraría si tuviera un código de estado inválido en estado.

+0

¿Esto hace que las pruebas sean más difíciles, ya que cada 'Ciudad' válida también debe tener el ID de un 'Estado' válido? Parece molesto tener que crear un 'Estado' siempre que quiera crear una' Ciudad' – oregontrail256

1

¿Qué pasa si usted hizo algo así como

s = State.new 
c = City.new 
c.state = s 
c.valid? 

No he probado esto, pero supongo que si usted está comprobando la presencia de c.state_id, se encuentra, a pesar de c tiene un estado (porque la ID no se ha generado todavía, porque el estado aún no se ha guardado).

Es decir, si lo que le importa es la presencia del estado, debe validar la presencia del estado.

1

Personalmente, prefiero permitir que el modelo sea más robusto y acepte cualquiera o. Entonces, en su situación particular, City podría aceptar un objeto State o un state_id, pero debe enviar uno de ellos.

class City < ActiveRecord::Base 
    attr_accessible :state, :state_id 

    validates :state, presence: true, if: proc{|c| c.state_id.blank? } 
    validates :state_id, presence: true, if: proc{|c| c.state.blank? } 

    belongs_to :state 
end 

Editar: quitado la doble negación en la declaración de validación.Originalmente tenía unless: proc{|c| !c.state_id.blank? }

+0

Me gusta su enfoque. Nitpick: no hay necesidad de '¡a menos que esté en blanco? '; o bien 'si está en blanco?' o 'a menos que esté presente?' funcionaría. –

+0

Eso es muy cierto, iba a poner 'presente?' Ya que es simplemente el inverso de '! Blank?', Pero prefiero la legibilidad de '! Blank'. Pero hacer 'si está en blanco?' También funciona sin el doble negativo: P –

0

Según Rails 4 Way by Obie Fernandez:

Cuando usted está tratando de asegurarse de que una asociación está presente, pasan su atributo clave externa , no la variable propia asociación

validates :region_id, :presence => true 
validate :region_exists 

def region_exists 
    errors.add(:region_id, "does not exist") unless Region.exists?(region_id) 
end 

El libro no explica por qué debería usar esto en comparación con

validates :region, :presence => true 

Pero sé que estos tipos saben lo que hacen.

+0

Esto es similar a 'validate: region, presence: true' excepto que también impone una verificación de que la asociación existe a través de la base de datos. Parece un poco extraño hacerlo de esta manera, porque no ofrece ninguna validación del objeto en memoria. En experiencia, es más fácil simplemente validar el objeto y agregar una restricción de clave externa para garantizar que las claves sean siempre válidas. –

+0

Como dije, estos muchachos saben sus cosas :). Buen punto sin embargo. – wbeange

+1

Quizás sea por razones de rendimiento, ya que valida: región carga región de DB cada vez que se valida un objeto, mientras que valida: region_id no lo hará. – remo

Cuestiones relacionadas