Определите уникальный первичный ключ на основе 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 31

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"

И это сделало свое дело. Это не то, что я хотел, но лучше, чем бороться с рамками.

Как и сказал @rogal111, но если первичный ключ уже существует, то вы захотите сделать это

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