Определите уникальный первичный ключ на основе 2 столбцов
Я хотел бы определить уникальный ключ для записей на основе 2 столбцов: 'id' и'language'
Чтобы пользователь мог отправить следующие строки : id=1 язык=en значение=blabla английский id=1 язык=fr значение=blabla французский
Я попытался использовать set_primary_key, а также add_index но это не сработало ( add_index :слова, ["идентификатор", "language_id"], :уникальная = правда )
У меня есть следующая модель:
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
7 ответов:
add_index :words, ["id", "language_id"], :unique => true
Это должно сработать. Может быть, у вас уже есть какие-то не уникальные данные в вашей БД и индекс не может быть создан? Но (как заметил @Doon, это будет избыточно, так как id всегда уникален). Поэтому вам нужно создать первичный ключ на двух столбцах.
Для определения первичного ключа 2 столбца в rails используйте:
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
В Rails 5 Вы можете сделать следующее:
create_table :words, primary_key: %i[id language_id] do |t| t.integer :id t.integer :language_id t.string :value t.timestamps end
Также нет необходимости устанавливать атрибут
primary_key
в моделиWord
.
Как я уже сказал в своих комментариях, вы будете бороться с рельсами, если вы попробуете это, и это действительно не поддерживается из коробки. вы можете посмотреть на http://compositekeys.rubyforge.org , который предлагает способ создания составных первичных ключей в rails. Я не использовал его, так как у меня еще не было необходимости (обычно, когда у меня есть что-то, что является составным ключом, например, это просто объединенная таблица без первичного ключа и уникального индекса на присоединенной паре (HABTM).
Модель
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
Вы получите эту таблицу
В зависимости от вашего варианта использования вы, возможно, захотите попробовать составного ключа драгоценный камень, которая позволяет определять составные первичные ключи, а также ehances и ActiveRecord, чтобы бороться с такого рода модель (помогает для организаций, для этой модели или для url_for помощников и т. д.).
Поэтому, если вы планируете использовать эту модель, как и любую другую модель рельсов, драгоценный камень очень поможет.
Я столкнулся с подобной проблемой при переносе сайта на 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"
И это сделало свое дело. Это не то, что я хотел, но лучше, чем бороться с рамками.