rails migraciones llaves foraneas conectar con ruby-on-rails ruby-on-rails-3.1 rails-migrations rails-models rails-postgresql

ruby-on-rails - migraciones - llaves foraneas ruby on rails



¿Cómo agregar secuencias a una migración y usarlas en un modelo? (4)

Creo que la respuesta de los roboles no es correcta.

Intenté implementar esto en mi aplicación (exactamente el mismo env: RoR + PostgreSQL), y descubrí que cuando se save en RoR con el objeto que tiene atributos vacíos, intenta realizar un INSERT en la base de datos mencionando que todos los VALORES se establecerá en NULL. El problema es la forma en que PostgreSQL maneja los NULL: en este caso, se creará la nueva fila pero con todos los valores vacíos, es decir, se omitirá el valor predeterminado. Si save solo escribió en los atributos de la instrucción INSERT rellenados en RoR, esto funcionaría bien.

En otras palabras, y centrándose solo en el atributo type y customer_no mencionado anteriormente, esta es la forma en que PostgreSQL se comporta:

SITUACIÓN 1:

INSERT INTO accounts_customers (type, customer_no) VALUES (NULL, NULL);

(Así es como funciona el save Rails)

Resultado: una nueva fila con el type vacío y el customer_no vacío_no

SITUACIÓN 2:

INSERT INTO accounts_customers (type) VALUES (NULL);

Resultado: una nueva fila con el type vacío y customer_no rellenados con NEXTVAL de la secuencia

Tengo un hilo sobre esto, échale un vistazo a:

Ruby on Rails + PostgreSQL: uso de secuencias personalizadas

Quiero tener un Modelo de " Customer " con una clave principal normal y otra columna para almacenar un "Número de Cliente" personalizado. Además, quiero que la base de datos maneje los números de cliente predeterminados. Creo que definir una secuencia es la mejor manera de hacerlo. Yo uso PostgreSQL. Echa un vistazo a mi migración:

class CreateAccountsCustomers < ActiveRecord::Migration def up say "Creating sequenze for customer number starting at 1002" execute ''CREATE SEQUENCE customer_no_seq START 1002;'' create_table :accounts_customers do |t| t.string :type t.integer :customer_no, :unique => true t.integer :salutation, :limit => 1 t.string :cp_name_1 t.string :cp_name_2 t.string :cp_name_3 t.string :cp_name_4 t.string :name_first, :limit => 55 t.string :name_last, :limit => 55 t.timestamps end say "Adding NEXTVAL(''customer_no_seq'') to column cust_id" execute "ALTER TABLE accounts_customers ALTER COLUMN customer_no SET DEFAULT NEXTVAL(''customer_no_seq'');" end def down drop_table :accounts_customers execute ''DROP SEQUENCE IF EXISTS customer_no_seq;'' end end

Si conoces un mejor enfoque "similar a rieles" para agregar secuencias, sería increíble que me lo hicieras saber.

Ahora, si hago algo como

cust = Accounts::Customer.new cust.save

el campo customer_no no se rellena previamente con el siguiente valor de la secuencia (debe ser 1002).

¿Conoces una buena forma de integrar secuencias? ¿O hay un buen plugin? ¡Saludos a todas las respuestas!


Me enfrenté a un problema similar, pero también puse :null => false en el salto de campo que se rellenará automáticamente con nextval.

Bueno, en mi caso, AR aún intentaba insertar NULL si no se proporcionó ningún atributo en la solicitud, y esto dio lugar a una excepción por infracción de restricción no nula.

Aquí está mi solución. Acabo de eliminar esta clave de atributo de @attributes y @changed_attributes y, en este caso, postgres coloca correctamente la secuencia esperada nextval.

He puesto esto en el modelo:

before_save do if (@attributes["customer_no"].nil? || @attributes["customer_no"].to_i == 0) @attributes.delete("customer_no") @changed_attributes.delete("customer_no") end end

Rieles 3.2 / Postgres 9.1


No tengo sugerencias para una forma más ''directa'' de manejar secuencias personalizadas, pero puedo decirle por qué el campo customer_no parece no estar poblado después de guardar.

Cuando ActiveRecord guarda un nuevo registro, la instrucción SQL solo devolverá el ID del nuevo registro, no todos sus campos, puede ver dónde ocurre esto en la fuente de los rieles actuales aquí https://github.com/rails/rails/blob/cf013a62686b5156336d57d57cb12e9e17b5d462/activerecord/lib/active_record/persistence.rb#L313

Para ver el valor, deberá volver a cargar el objeto ...

cust = Accounts::Customer.new cust.save cust.reload

Si siempre desea hacer esto, considere agregar un gancho after_create a su clase de modelo ...

class Accounts::Customer < ActiveRecord::Base after_create :reload end


Si estás usando PostgreSQL, echa un vistazo a la gema que escribí, pg_sequencer:

https://github.com/code42/pg_sequencer

Proporciona un DSL para crear, eliminar y modificar secuencias en las migraciones de ActiveRecord.