Necesito agregar una nueva columna entera a una tabla existente en mi aplicación Rails. La columna solo puede tener los valores 1, 2 y 3, por lo que me gustaría agregar una restricción de verificación a la tabla/columna. ¿Cómo especifico esta restricción dentro de una migración de Rails? la migración¿Cómo agrego una restricción de verificación en una migración de Rails?
Respuesta
Carriles no proporciona ninguna manera de añadir restricciones, pero todavía se puede hacerlo a través de la migración, pero al pasar SQL real para ejecutar()
Crear archivo de migración:
ruby script/generate Migration AddConstraint
Ahora, en el archivo de migración:
class AddConstraint < ActiveRecord::Migration
def self.up
execute "ALTER TABLE table_name ADD CONSTRAINT check_constraint_name CHECK (check_column_name IN (1, 2, 3))"
end
def self.down
execute "ALTER TABLE table_name DROP CONSTRAINT check_constraint_name"
end
end
Acabo de trabajar para obtener una restricción PostgreSQL CHECK para que funcione.
La solución de Nilesh no es del todo completa; el archivo db/schema.rb no incluirá la restricción, por lo que las pruebas y las implementaciones que usen db: setup no tendrán la restricción. Según http://guides.rubyonrails.org/migrations.html#types-of-schema-dumps
Mientras que en una migración puede ejecutar sentencias SQL personalizadas, el dumper esquema no puede reconstituir las declaraciones de la base de datos. Si está utilizando características como esta, entonces debe establecer el formato de esquema en: sql.
es decir, en config/application.rb conjunto
config.active_record.schema_format = :sql
Desafortunadamente, si usted está utilizando PostgreSQL se puede obtener un error al cargar el volcado resultante, véase la discusión en ERROR: must be owner of language plpgsql. No quería ir por la ruta de configuración de PostgreSQL en esa discusión; Además, en cualquier caso, me gusta tener un archivo legible db/schema.rb. Eso descartó el SQL personalizado en el archivo de migración para mí.
La joya https://github.com/vprokopchuk256/mv-core sugerida por Valera parece prometedora, pero solo admite un conjunto limitado de restricciones (y recibí un error cuando traté de usarlo, aunque puede deberse a incompatibilidades con otras gemas que incluyo) .
La solución (pirateo) que fui es hacer que el código del modelo inserte la restricción. Puesto que es tipode como una validación, que es donde lo pongo:
class MyModel < ActiveRecord::Base
validates :my_constraint
def my_constraint
unless MyModel.connection.execute("SELECT * FROM information_schema.check_constraints WHERE constraint_name = 'my_constraint'").any?
MyModel.connection.execute("ALTER TABLE my_models ADD CONSTRAINT my_constraint CHECK (...the SQL expression goes here ...)")
end
end
Por supuesto, esto seleccionar un extra antes de cada validación; si eso es un problema, una solución sería ponerlo en un parche "después de conectar" tal como se explica en How to run specific script after connected to oracle using rails? (No puede simplemente almacenar en caché el resultado de la selección, porque la adición de validación/restricción ocurre dentro de una transacción que podría revertido, por lo que debe verificarlo cada vez.)
Esta es una idea interesante, pero no escalable. Como dices, hace una selección adicional antes de cada validación. Si termina con muchas limitaciones, esto se convertirá en un dolor de cabeza de rendimiento a medida que escala. Creo que la publicación a la que vinculó sobre el lanzamiento de scripts después de la conexión db inicial podría ser una mejor manera de hacerlo. Sin embargo, una vez dicho esto, se podría argumentar que tratar de resolver el problema de restricciones no se debe hacer dentro de Rails, pero fuera de él, Rails está destinado a ser independiente de la base de datos. Ver: http://stackoverflow.com/questions/2589509/does-rails-need-database-level-constraints – rmcsharry
Puede hacerlo con Migration Validators gem.Ver detalles aquí: https://github.com/vprokopchuk256/mv-core
Con esa gema podrás definir la validación de la inclusión en el nivel db:
def change
change_table :table_name do |t|
t.integer :column_name, inclusion: [1, 2, 3]
end
end
Por otra parte usted es capaz de definir la forma en que la validación se debe definir e incluso mensaje de error que debe se mostrará:
def change
change_table :posts do |t|
t.integer :priority,
inclusion: { in: [1, 2, 3],
as: :trigger,
message: "can't be anything else than 1, 2, or 3" }
end
end
incluso se puede subir de nivel que la validación de la migración derecho de su modelo:
class Post < ActiveRecord::Base
enforce_migration_validations
end
y después de validación define en la migración será también definido como la validación ActiveModel en su modelo:
Post.new(priority: 3).valid?
=> true
Post.new(priority: 4).valid?
=> false
Post.new(priority: 4).errors.full_messages
=> ["Priority can't be anything else than 1, 2, or 3"]
Puede utilizar Sequel
joya https://github.com/jeremyevans/sequel
Sequel.migration do
change do
create_table(:artists) do
primary_key :id
String :name
constraint(:name_min_length){char_length(name) > 2}
end
end
end
Acabo de publicar una joya para esto: active_record-postgres-constraints. A medida que el README no describe, se puede usar con un archivo db/schema.rb, y añade soporte para los siguientes métodos de migraciones:
create_table TABLE_NAME do |t|
# Add columns
t.check_constraint conditions
# conditions can be a String, Array or Hash
end
add_check_constraint TABLE_NAME, conditions
remove_check_constraint TABLE_NAME, CONSTRAINT_NAME
Tenga en cuenta que en este momento, sólo se postgres es compatible.
- 1. ¿Cómo agrego una restricción de verificación a una tabla?
- 2. ¿Es posible expresar una restricción de verificación?
- 3. Rails Globalize3 gem: ¿Cómo agrego un campo adicional a la tabla de traducción mediante una migración?
- 4. Recuperación de una migración fallida de Rails
- 5. ¿Cómo ejecuto una migración sin iniciar una transacción en Rails?
- 6. Usar fecha en una restricción de verificación, Oracle
- 7. En una migración de Rails (MySQL), ¿puede especificar qué posición debería tener una nueva columna?
- 8. Una migración para agregar una restricción única a una combinación de columnas
- 9. Rake solo una migración
- 10. Obtener el SQL de una migración de Rails
- 11. SQL Server: ¿Cómo agrego una restricción a una tabla existente pero solo si la restricción no existe?
- 12. Compatibilidad con restricción de clave externa en Rails
- 13. ¿Cómo tengo una restricción de verificación que se refiere a otra tabla?
- 14. ¿Cómo agrego una clave externa a una tabla SQLite existente?
- 15. Agregar una columna a una tabla existente en una migración de Rails
- 16. NSCharacterSet: ¿Cómo agrego "_" a la restricción de texto alfanumérico CharacterSet?
- 17. ¿Cómo agrego error ModelState a una lista
- 18. ¿Cómo crear una restricción de verificación entre dos columnas en SQL?
- 19. Rails 3: suelte una tabla usando la migración
- 20. ¿Cómo verifico el tipo de base de datos en una migración de Rails?
- 21. Agregar columna Id en una migración
- 22. SQL Sub consultas en la restricción de verificación
- 23. ¿Cómo podría clonar una tabla de base de datos a través de la migración de Rails?
- 24. ¿Cómo detener la migración de Rails 3.1 para que no se ejecute en una transacción?
- 25. ¿Cómo elimino una restricción de exclusividad de una tabla MySQL?
- 26. ¿Cómo agrego APK en una compilación AOSP?
- 27. Rails 3.2: Invocando \ down de otra migración
- 28. Claves foráneas con ActiveRecord de Rails :: ¿Migración?
- 29. Marca de verificación en una casilla de verificación
- 30. ¿Qué hace una migración de datos del Sur en comparación con una migración de esquema?
También tenga en cuenta que si agrega una restricción, tendrá que establecer 'config.active_record.schema_format =: sql' en' config/application.rb' ya que ["' db/schema.rb' no puede expresar la base de datos elementos específicos como desencadenantes, procedimientos almacenados o restricciones de verificación. "] (http://edgeguides.rubyonrails.org/active_record_migrations.html#types-of-schema-dumps). –
Ahora hay una gema que admite el almacenamiento de restricciones en 'db/schema.rb': [active_record-postgres-constraints] (https://github.com/on-site/active_record-postgres-constraints). Ver mi respuesta para más detalles. Por ahora, solo se admite postgres. –