Определите уникальный первичный ключ на основе двух столбцов
Я хотел бы определить уникальный ключ для записей на основе двух столбцов: 'id' и 'language'
чтобы пользователь представил следующие строки:
id = 1 язык = en value = blabla english
id = 1 язык = fr value = blabla french
Я попытался использовать set_primary_key, а также add_index, но это не сработало (add_index: слова, [ "id", "language_id" ],: unique = > true)
У меня есть следующая модель:
class Word < ActiveRecord::Base
belongs_to :dictionnary
belongs_to :language
attr_accessible :lang, :rev, :value, :dictionnary_id, :language_id
validates :value, :uniqueness => true
end
и этот
class Language < ActiveRecord::Base
has_many :words
attr_accessible :lang
end
Ответы
Ответ 1
add_index :words, ["id", "language_id"], :unique => true
Он должен работать. Может быть, у вас уже есть некоторые не уникальные данные в вашем db, и индекс не может быть создан? Но (как заметил @Doon, он будет лишним, так как id всегда уникален). Поэтому вам нужно создать первичный ключ на двух столбцах.
Чтобы определить 2 первичный ключ столбца в рельсах, используйте:
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);"
И установите primary_key в вашей модели с этим камнем: http://rubygems.org/gems/composite_primary_keys:
class Word < ActiveRecord::Base
self.primary_keys = :id,:language_id
end
Ответ 2
Как я уже сказал в своих комментариях, вы будете сражаться с рельсами, если вы попробуете это, и на самом деле это не поддерживается из коробки. вы можете посмотреть http://compositekeys.rubyforge.org, который предлагает способ создания составных первичных ключей в рельсах. Я не использовал его, поскольку у меня еще не было необходимости (обычно, когда у меня есть составной ключ, например, это просто таблица соединений без первичного ключа и уникальный индекс на объединенной паре (HABTM).
Ответ 3
В зависимости от вашего варианта использования вы можете попробовать составной камень gem, который позволяет вам определять составные первичные ключи, а также ehances ActiveRecord для решения с такой моделью (помогает много для ассоциаций с этой моделью или для url_for помощников и т.д.).
Итак, если вы планируете использовать эту модель в качестве любой другой модели рельсов, этот камень очень поможет.
Ответ 4
У меня возникла аналогичная проблема при переносе сайта на Rails. У меня была таблица, в которой хранятся текстовые данные для каждого языка, на котором доступен мой сайт, поэтому у меня было что-то вроде этого:
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;
Но поскольку Rails не обрабатывает составные первичные ключи из коробки, я был вынужден изменить структуру таблицы, чтобы у нее был собственный первичный ключ:
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;
Я также создал уникальный индекс для столбцов, которые ранее делали составной первичный ключ, чтобы не было вставлено дублирующаяся запись. Тогда в моей модели Rails я мог просто:
self.primary_key = "project_lang_id"
И это сделал трюк. Не то, что я хотел, но лучше, чем борьба с каркасом.
Ответ 5
Model
class User < ActiveRecord::Base
has_secure_password
self.primary_keys = :name
end
Миграция
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
Вы получите эту таблицу
![image]()
Ответ 6
Так же, как @rogal111 сказал, но если первичный ключ уже существует, вы захотите сделать это
ALTER TABLE sections DROP PRIMARY KEY, ADD PRIMARY KEY(id, workspace_id, section_key);
Ответ 7
В Rails 5 вы можете сделать следующее:
create_table :words, primary_key: [:id, :language_id] do |t|
t.integer :id
t.integer :language_id
t.string :value
t.timestamps
end
Также нет необходимости устанавливать атрибут primary_key
в модели Word
.