run rails migrations foreign column belong association ruby-on-rails database foreign-keys referential-integrity

ruby on rails - migrations - ¿Por qué las migraciones de Rails definen claves externas en la aplicación pero no en la base de datos?



ruby on rails run migrations (5)

Si defino un modelo de Customer y Order en el que un Customer "tiene muchas" Orders y la Order "pertenece" al Customer , en Rails hablamos sobre el Order tiene una clave externa para el Customer través de customer_id pero no queremos decir que esto se aplica en la base de datos.

Como Rails no define esto como una restricción de nivel de base de datos, existe el riesgo de que se viole la integridad de sus datos, tal vez fuera de la aplicación (o dentro si recibe solicitudes simultáneas), a menos que aplique la restricción en la base de datos manualmente.

¿Por qué Rails no define la clave externa en el nivel de la base de datos o hay alguna manera de hacer que Rails haga esto?

class Customer < ActiveRecord::Base has_many :orders end class Order < ActiveRecord::Base belongs_to :customer end ActiveRecord::Schema.define(:version => 1) do create_table "customers", :force => true do |t| t.string "name" end create_table "orders", :force => true do |t| t.string "item_name" t.integer "customer_id" end end


Crea una columna customer_id (obviamente). Sin embargo, en su mayor parte, Rails cree en imponer restricciones y validaciones en el nivel de la aplicación , en lugar del nivel de la base de datos; es por eso que las columnas, por defecto, en Rails pueden contener valores NULL , incluso si tiene validates_presence_of o algo así. La visión de los desarrolladores de Rails es que tales restricciones deberían ser manejadas por la aplicación, no la base de datos.


Después de haber trabajado con este tema por un tiempo, no creo que sea parte de la filosofía central de Rails que las claves externas no se apliquen por la base de datos.

Las validaciones y verificaciones del nivel de la aplicación están ahí para proporcionar verificaciones fáciles, rápidas y legibles para el ser humano (mensajes de error de pensamiento) que funcionan en el 99.99% del tiempo. Si su aplicación requiere más que eso, debe usar restricciones de nivel de base de datos.

Creo que esta "filosofía" evolucionó debido a los marcos de prueba originales utilizados: las claves externas demostraron ser una molestia gigantesca cuando se usan accesorios. Es como cuando un "error" se convierte en una "característica" porque nadie lo soluciona. (Si estoy recordando mal la historia, alguien me corrige).

Como mínimo, existe un movimiento creciente dentro de la comunidad de Rails para imponer la integridad con la base de datos. Mira esta publicación del blog del mes pasado. Incluso se vincula a algunos complementos que ayudan a proporcionar soporte para el manejo de errores (y otra publicación de blog que enlaza con más complementos). Haga algunas búsquedas de Google más; También he visto otros complementos que agregan compatibilidad con migraciones para crear claves externas.

Ahora, lo que es parte de la filosofía central de Rails es: no te preocupes por cosas a menos que realmente lo necesites. Para muchas aplicaciones web, probablemente sea correcto si un pequeño (probablemente muy pequeño) porcentaje de registros contiene datos no válidos. Es posible que las páginas que pueden verse afectadas solo se vean muy raramente, o el error ya se puede manejar correctamente. O tal vez sea más económico (como en efectivo duro y frío) manejar los problemas a mano durante los próximos 6 meses a medida que la aplicación crezca, que gastar la planificación de recursos de desarrollo para cada contingencia ahora. Básicamente, si sus casos de uso no lo hacen parecer importante, y realmente solo puede ser causado por una condición de carrera que puede ocurrir 1/10000000 solicitudes ... bueno, ¿vale la pena?

Así que mi predicción es que las herramientas surgirán para manejar mejor toda la situación por defecto, y eventualmente estas se fusionarán en Rails 3. Mientras tanto, si tu aplicación realmente lo necesita, agrégalas. Causará un leve dolor de cabeza en las pruebas, pero no se puede pasar nada con los burles y los talones. Y si tu aplicación realmente no la necesita ... bueno, ya estás bien. :)


Después de muchas décadas en la industria, creo firmemente que un buen diseño de base de datos salvará una aplicación de muchos problemas, especialmente cuando se someten a mejoras. Si se sabe que una restricción en particular mantendrá la integridad de la base de datos incluso después de un error de programación (estoy seguro de que no soy el único en hacerlo), se debe aplicar a la base de datos si es posible. Por lo tanto, recomendaría a las personas que usen claves externas cuando sea posible. También consideraría usar pruebas para proporcionar integridad de datos. Porque todos sabemos acerca de la ley de Murphy.


Rails tiene algunas convenciones de que la aplicación de la integridad de los datos debe hacerse en la aplicación, no en la base de datos.

Por ejemplo, Rails incluso admite algunos diseños de bases de datos que no pueden usar claves externas , como Asociaciones polimórficas.

Básicamente, las convenciones de Rails han tratado la base de datos como un dispositivo de almacenamiento de datos estático, no como un RDBMS activo. Rails 2.0 finalmente admite algunas características más realistas de las bases de datos SQL. No es sorprendente que el resultado sea que desarrollar con Rails se volverá más complejo de lo que era en la versión 1.0.


Un error que comete mucha gente es confundir las migraciones con el modelo. Las migraciones simplemente modifican la base de datos y no tienen nada que ver con los modelos que ha definido. Como resultado de esta confusión, muchos plugins de clave foránea intentan combinar el modelo con las migraciones y hacer demasiadas cosas mágicas.

Para las migraciones, usaría http://github.com/matthuhiggins/foreigner/tree/master . No debería necesitar cambiar sus modelos para obtener claves externas para trabajar con Rails.