2012-10-05 15 views
29

Me gustaría definir una clave única para registros basado en 2 columnas: 'id' y 'lenguaje'Definir una clave principal única basada en 2 columnas

para permitir que el usuario envía las siguientes cadenas: id = 1 language = es el valor = blabla id valor = 1 language = fr Inglés = blabla francés

he intentado utilizar set_primary_key y también add_index pero no funcionó (add_index: palabras, [ "id", "language_id" ],: unique => true)

Tengo el siguiente modelo:

class Word < ActiveRecord::Base 
    belongs_to :dictionnary 
    belongs_to :language 

    attr_accessible :lang, :rev, :value, :dictionnary_id, :language_id 

    validates :value, :uniqueness => true 

end 

y esto

class Language < ActiveRecord::Base 
    has_many :words 

    attr_accessible :lang 
end 
+0

si la palabra pertenece a un idioma ¿por qué necesita almacenar lang con ella? Puede simplemente delegarlo en el Modelo de Idioma. Dicho esto, estarás luchando contra los rieles. Solo usaría la clave ID como la clave principal. delegar: lang a Language y no preocuparse por la clave compuesta – Doon

+0

de hecho, gracias. : lang proviene de ald scaffilding. Necesito eliminarlo de aquí ya que uso el modelo de Idioma. Thx –

Respuesta

44

add_index :words, ["id", "language_id"], :unique => true

Se debe trabajar. Tal vez ya tiene algunos datos no únicos en su base de datos y no se puede crear el índice? Pero (como @Doon notó que será redundante ya que id es siempre único). Entonces necesitas crear la clave principal en dos columnas.

Para definir la clave principal de la columna 2 de los carriles de empleo:

create_table :words, {:id => false} do |t| 
    t.integer :id 
    t.integer :language_id 
    t.string :value 
    t.timestamps 
end 
execute "ALTER TABLE words ADD PRIMARY KEY (id,language_id);" 

Y establecer primary_key en su modelo con esta joya: http://rubygems.org/gems/composite_primary_keys:

class Word < ActiveRecord::Base 
    self.primary_keys = :id,:language_id 
end 
+0

esto agregará un índice único en la tabla para id/language_id) pero lo más probable es que la identificación sea la clave principal y esté sujeta a un índice único. por lo que este índice sería redundante ya que id es siempre único. – Doon

+3

También es posible: 'validates: language_id, unicidad: {scope: [: id]}' –

+0

¿Cómo crear una clave combinada única (no primaria) basada en dos columnas? Que básicamente impide la creación de múltiples filas con los mismos valores en la columna a y la columna b .. –

1

Como ya he dicho en mis comentarios será la lucha contra Rieles si prueba esto, y no es realmente compatible con la caja. puede mirar http://compositekeys.rubyforge.org que ofrece una forma de hacer teclas primarias compuestas en rieles. No lo he usado, ya que todavía no lo he necesitado (normalmente cuando tengo algo que es una clave compuesta como si fuera una tabla de unión sin clave principal y un índice único en el par unido (HABTM).

0

Dependiendo de su caso de uso, puede probar composite key gem que le permite definir claves primarias compuestas y también mejora ActiveRecord para tratar este tipo de modelo (ayuda mucho para las asociaciones de este modelo o para url_for helpers etc.) .

Así que si usted planea en usar este modelo como cualquier modelo de otros carriles de la gema va a ayudar mucho.

0

que se enfrentaron a un problema similar al migrar un sitio a rieles. tenía una tabla que almacena da texto ta para cada idioma de mi sitio está disponible en así que tenía algo como esto:

CREATE TABLE Project_Lang(
    project_id INT NOT NULL, 
    language_id INT NOT NULL, 
    title VARCHAR(80), 
    description TEXT, 

    PRIMARY KEY pk_Project_Lang(project_id, language_id), 

    FOREIGN KEY fk_Project_Lang_Project(project_id) 
     REFERENCES Project(project_id) 
     ON DELETE RESTRICT ON UPDATE CASCADE, 

    FOREIGN KEY fk_Project_Lang_Language(language_id) 
     REFERENCES Language(language_id) 
     ON DELETE RESTRICT ON UPDATE CASCADE 
)ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE = utf8_spanish_ci; 

Pero ya que los carriles no maneja claves primarias compuestas fuera de la caja que se vio obligado a cambiar la estructura de la mesa, así que tenía que es clave primaria propia:

CREATE TABLE Project_Lang(
    project_lang_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    project_id INT NOT NULL, 
    language_id INT NOT NULL, 
    title VARCHAR(80), 
    description TEXT, 

    UNIQUE INDEX(project_id, language_id), 

    FOREIGN KEY fk_Project_Lang_Project(project_id) 
     REFERENCES Project(project_id) 
     ON DELETE RESTRICT ON UPDATE CASCADE, 

    FOREIGN KEY fk_Project_Lang_Language(language_id) 
     REFERENCES Language(language_id) 
     ON DELETE RESTRICT ON UPDATE CASCADE 
)ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE = utf8_spanish_ci; 

también he creado un índice único para las columnas que anteriormente hicieron la clave principal compuesta de manera que se introduce ningún registro duplicado. Luego, en mi modelo de Rails, pude simplemente:

self.primary_key = "project_lang_id" 

Y eso funcionó. No es lo que quería, pero es mejor que luchar contra el marco.

1

Modelo

class User < ActiveRecord::Base 
    has_secure_password 
    self.primary_keys = :name 
end 

Migración

class CreateUsers < ActiveRecord::Migration 
    def change 
    create_table :users do |t| 
     t.string :name, null: false 
     t.string :emailid 
     t.string :password_digest 
     t.integer :locked, :default => 0 
     t.text :secretquestion 
     t.string :answer 

     t.timestamps null: false 
    end 
    add_index :users, :name, :unique => true 
    end 
end 

Usted recibirá esta tabla

image

0

Al igual que @ rogal111 dicho, pero si una clave principal ya existe entonces usted querrá hacer esto

ALTER TABLE sections DROP PRIMARY KEY, ADD PRIMARY KEY(id, workspace_id, section_key); 
0

En los carriles 5, puede hacer lo siguiente:

create_table :words, primary_key: [:id, :language_id] do |t| 
    t.integer :id 
    t.integer :language_id 
    t.string :value 
    t.timestamps 
end 

Asimismo, no es necesario para establecer el atributo en el primary_keyWord modelo.

Cuestiones relacionadas