Zdefiniuj unikalny klucz podstawowy oparty na 2 kolumnach

Chciałbym zdefiniować unikalny klucz dla rekordów oparty na 2 kolumnach: 'id' i 'language'

Aby użytkownik mógł przesłać następujące ciągi : id = 1 language = en value=blabla english id = 1 language = fr value=blabla french

Próbowałem użyć set_primary_key i add_index, ale nie zadziałało (add_index :words, ["id", "language_id"], :unique => true)

Mam następujący model:

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

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

  validates :value, :uniqueness => true

end  

I to

class Language < ActiveRecord::Base
    has_many :words

    attr_accessible :lang
end
Author: Ricardo Valeriano, 2012-10-05

7 answers

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

Powinno zadziałać. Może masz już jakieś unikalne dane w db i indeks nie może być utworzony? Ale (jak zauważył @Doon, będzie to zbędne, ponieważ id jest zawsze unikalne). Musisz więc utworzyć klucz podstawowy na dwóch kolumnach.

Aby zdefiniować 2-kolumnowy klucz podstawowy w rails użyj:

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

I ustaw primary_key w swoim modelu za pomocą tego klejnotu: http://rubygems.org/gems/composite_primary_keys :

class Word < ActiveRecord::Base
    self.primary_keys = :id,:language_id
end
 45
Author: rogal111,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 12:45:05

W Rails 5 możesz wykonać następujące czynności:

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

Nie jest również konieczne ustawianie atrybutu primary_key w modelu Word.

 4
Author: Vadim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-14 15:02:20

Jak już powiedziałem w komentarzach, będziesz walczył z rails, jeśli spróbujesz tego, a to nie jest naprawdę wspierane po wyjęciu z pudełka. możesz spojrzeć na http://compositekeys.rubyforge.org, który oferuje sposób wykonywania kompozytowych kluczy podstawowych w rails. Nie używałem go, ponieważ nie miałem jeszcze potrzeby (zwykle, gdy mam coś, co jest kluczem kompozytowym, jak to jest po prostu tablica złączeń bez klucza podstawowego i unikalny indeks na połączonej parze (HABTM).

 1
Author: Doon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 12:42:19

Model

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

Migracja

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

Dostaniesz tę tabelę

obraz

 1
Author: Bhavnesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-28 11:20:41

W zależności od przypadku użycia możesz wypróbować composite key gem, który pozwala zdefiniować złożone klucze podstawowe, a także ehan ActiveRecord do radzenia sobie z tego typu modelem (bardzo pomaga w skojarzeniach z tym modelem lub dla helperów url_for itp.).

Więc jeśli planujesz używać tego modelu jak każdego innego modelu rails, gem bardzo pomoże.

 0
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 12:43:06

Napotkałem podobny problem podczas migracji witryny do Rails. Miałem tabelę, która przechowuje dane tekstowe dla każdego języka moja strona jest dostępna w więc miałem coś takiego:

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;

Ale ponieważ Rails nie obsługuje złożonych kluczy podstawowych po wyjęciu z pudełka, musiałem zmienić strukturę tabeli, aby miała swój własny klucz podstawowy:

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;

Utworzyłem również unikalny indeks dla kolumn, które wcześniej tworzyły złożony klucz główny, tak aby nie wstawiano zduplikowanego rekordu. Następnie w moim modelu Rails mogłem po prostu:

self.primary_key = "project_lang_id"
I to załatwiło sprawę. To nie jest to, czego chciałem, ale jest lepsze niż walka z ramami.
 0
Author: Sergio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-16 22:55:58

Tak jak powiedział @rogal111, ale jeśli klucz podstawowy już istnieje, będziesz chciał to zrobić

ALTER TABLE sections DROP PRIMARY KEY, ADD PRIMARY KEY(id, workspace_id, section_key);
 0
Author: Son Tr.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-01 03:30:12