2012-10-05 13 views
29

vorrei definire una chiave univoca per i record sulla base di 2 colonne: 'id' e 'lingua'Definire una chiave primaria unica basata su 2 colonne

per lasciare l'utente invia le seguenti stringhe: id = 1 language = it value = blabla inglese id value = 1 lingua = fr = blabla francese

ho provato ad usare set_primary_key e anche add_index, ma non ha funzionato (add_index: parole [ "id", "language_id" ],: unique => true)

Ho il seguente modello:

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

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

    validates :value, :uniqueness => true 

end 

e questo

class Language < ActiveRecord::Base 
    has_many :words 

    attr_accessible :lang 
end 
+0

se la parola appartiene a un linguaggio perché è necessario memorizzare il lang con esso? Puoi semplicemente delegarlo al modello di lingua. Detto questo, combatterai le rotaie. Vorrei solo usare la chiave ID come chiave primaria. delegato: lang to Language e non preoccuparti per la chiave composita – Doon

+0

davvero, grazie. : lang sta arrivando da un ponteggio. Devo rimuoverlo da qui poiché utilizzo il modello di linguaggio. Thx –

risposta

44

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

Dovrebbe funzionare. Forse hai già alcuni dati non univoci nel tuo database e l'indice non può essere creato? Ma (come @Doon notato che sarà ridondante dal momento che ID è sempre unico). Quindi è necessario creare la chiave primaria su due colonne.

Per definire chiave primaria 2 colonna rotaie usate:

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);" 

e impostare primary_key nel modello con questo gioiello: http://rubygems.org/gems/composite_primary_keys:

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

aggiungerà un indice univoco sulla tabella per id/language_id) ma più che probabile id sarà ancora la chiave primaria e soggetta a indice univoco. quindi questo indice sarebbe ridondante poiché ID è sempre unico. – Doon

+3

Possibile anche: 'valida: lingua_id, unicità: {scope: [: id]}' –

+0

Come creare una chiave univoca (non primaria) combinata basata su due colonne? Che sostanzialmente impedisce la creazione di più righe con gli stessi valori sulla colonna a & colonna b .. –

1

Come ho detto nei miei commenti vi verrà combattendo rotaie se si prova questo, e non è supportato veramente fuori dalla scatola. è possibile consultare http://compositekeys.rubyforge.org che offre un modo per eseguire le chiavi primarie composite nelle guide. Non l'ho usato, come non ho ancora avuto bisogno (normalmente quando ho qualcosa che è una chiave composita come se fosse solo una tabella di join senza chiave primaria e un indice univoco sulla coppia unita (HABTM).

0

A seconda del caso d'uso, si consiglia di provare composite key gem che consente di definire le chiavi primarie composite e migliora anche ActiveRecord per gestire questo tipo di modello (aiuta molto le associazioni a questo modello o per url_for helpers ecc.) .

Quindi se avete intenzione di utilizzare questo modello come qualsiasi modello di altri binari la gemma aiuterà molto.

0

ho affrontato un problema simile quando la migrazione di un sito per Rails. ho avuto un tavolo che memorizza il testo da ta per ogni lingua il mio sito è disponibile così ho avuto qualcosa di simile:

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; 

Ma poiché Rails non gestisce le chiavi primarie composite, fuori dalla scatola sono stato costretto a cambiare la struttura della tabella in modo che aveva è propria chiave primaria:

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; 

ho anche creato un indice univoco per le colonne che precedentemente hanno fatto la chiave primaria composta in modo che non siano inseriti record duplicato. Quindi nel mio modello Rails potrei semplicemente:

self.primary_key = "project_lang_id" 

E questo ha fatto il trucco. Non è quello che volevo ma è meglio che combattere la struttura.

1

Modello

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

migrazione

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 

Otterrete questa tabella

image

0

Proprio come @ rogal111 detto, ma se una chiave primaria esiste già, allora si vorrà fare questo

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

In Rails 5 è possibile effettuare le seguenti operazioni:

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

Inoltre non è necessario impostare l'attributo primary_key sulla Modello Word.

Problemi correlati