2012-06-17 19 views
75

que cree un nuevo registro de este modo:rieles Identificación automática de la asignación que ya existe

truck = Truck.create(:name=>name, :user_id=>2)

Mi base de datos tiene actualmente varios miles de entidades para el carro, pero asigna los identificadores de varios de ellos, en una camino que dejó algunos id disponibles. Entonces, lo que está sucediendo es que Rails crea un elemento con id = 150 y funciona bien. Pero entonces se trata de crear un elemento y asignarlo id = 151, pero ese id puede existir ya, por lo que estoy viendo este error:

ActiveRecord::RecordNotUnique (PG::Error: ERROR: duplicate key value violates unique constraint "companies_pkey" DETAIL: Key (id)=(151) already exists.

Y la próxima vez que ejecute la acción, lo hará simplemente asigne la identificación 152, que funcionará bien si ese valor no está ya tomado. ¿Cómo puedo obtener los rieles para verificar si ya existe una ID antes de asignarla?

Gracias!

EDITAR

La identificación del camión es lo que se está duplicada. El usuario ya existe y es una constante en este caso. En realidad, es un problema heredado con el que tengo que lidiar. Una opción es volver a crear la tabla en let rails auto assign every id esta vez. Estoy empezando a pensar que esta puede ser la mejor opción porque tengo algunos otros problemas, pero la migración para hacer esto sería muy complicada porque Truck es una clave foránea en muchas otras tablas. ¿Habría una manera simple de hacer que los rieles crearan una nueva tabla con los mismos datos que ya estaban almacenados en Camión, con identificaciones asignadas automáticamente y manteniendo todas las relaciones existentes?

+0

¿Por qué no dejas que los rieles asignen el ID automáticamente? Eso eliminaría cualquier peligro de duplicación. ¿O se trata de un problema de datos heredado en el que debe conservar ID anteriores? Solo quiero entender un poco el caso empresarial, ya que no es lo mismo cuando se crea un objeto nuevo. – MBHNYC

+0

@MBHNYC Creo que D-Nice está asignando un user_id al crear la compañía, y no identifica como estás pensando (y lo hice por un momento también). – Anil

+0

Ooo buena captura Anil - tienes toda la razón. @ D-Nice, ¿quizás agregue su migración para esta tabla a su publicación en caso de que haya algo extraño? Tentando para editar ese user_id para eliminar la confusión. – MBHNYC

Respuesta

75

Rails probablemente esté utilizando la secuencia PostgreSQL incorporada. La idea de una secuencia es que solo se usa una vez.

La solución más sencilla consiste en determinar la secuencia en la columna company.id al valor más alto de la tabla con una consulta como esta:

SELECT setval('company_id_seq', (SELECT max(id) FROM company)); 

supongo que seguirán a su nombre de la secuencia "company_id_seq", mesa nombre "compañía" y nombre de columna "id" ... reemplácelos por los correctos. Puede obtener el nombre de la secuencia con SELECT pg_get_serial_sequence('tablename', 'columname'); o consultar la definición de la tabla con \d tablename.

Una solución alternativa es anular el método save() en su clase de compañía para establecer manualmente el ID de la compañía para nuevas filas antes de guardar.

+0

Supongo que lo que haría es tener inicio de autoasignación con lo que actualmente es el valor más alto + 1? –

+0

Eso es correcto, lo siento, no lo expliqué más a fondo. –

+0

Creo que esta es la mejor respuesta a mi pregunta, sin embargo, por razones no relacionadas, tendré que encontrar una manera de utilizar la estrategia que describí en mi OP edición –

3

Me parece un problema de base de datos y no un problema de Rails. ¿Es posible que su base de datos tenga una semilla de identidad incorrecta en su columna id? Para probar intente hacer un par de insertos directamente en su base de datos y ver si existe el mismo comportamiento.

+3

¿Por qué el voto a favor? Este es el comportamiento exacto que ocurre si establece su secuencia de incremento en algo que es más bajo que otros valores existentes y, por lo tanto, ocasionalmente golpea colisiones cuando inserta datos. El cartel ya dijo que hay datos existentes que corresponden a este caso. – mynameiscoffey

+0

Puedo insertar bien. Después de obtener este error, puedo ejecutar la misma acción nuevamente y hacer que funcione, si aún no se ha tomado la siguiente identificación en la secuencia. –

+0

parece que esta era mi situación - me encontré con el problema, pero el siguiente registro que inserté funcionó bien, por lo que debe haber conseguido la semilla en el lugar correcto. –

181

Hice esto que resolvió el problema para mí.

ActiveRecord::Base.connection.tables.each do |t| 
    ActiveRecord::Base.connection.reset_pk_sequence!(t) 
end 

Encontré reset_pk_sequence! de este hilo. http://www.ruby-forum.com/topic/64428

+4

Gracias, la mejor solución. Después de la transferencia de la base de datos tuve el mismo problema. –

+54

O el equivalente de una línea (para propósitos de copiar/pegar de consola de rieles): 'ActiveRecord :: Base.connection.tables.each {| t | ActiveRecord :: Base.connection.reset_pk_sequence! (T)} ' – Raf

+4

se debe aceptar answer !! oneone –

24

Basado en @Apie answer.

Usted puede hacer una tarea y ejecutar cuando se necesita con:

rake database:correction_seq_id 

Se crea tareas como esto:

rails g task database correction_seq_id 

Y en el archivo generado (lib/tasks/database.rake) pone:

namespace :database do 
    desc "Correction of sequences id" 
    task correction_seq_id: :environment do 
     ActiveRecord::Base.connection.tables.each do |t| 
      ActiveRecord::Base.connection.reset_pk_sequence!(t) 
     end 
    end 
end 
+3

La mejor solución, gracias. – monteirobrena

Cuestiones relacionadas