Подтвердить что ты не робот

Определите уникальный первичный ключ на основе двух столбцов

Я хотел бы определить уникальный ключ для записей на основе двух столбцов: '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
4b9b3361

Ответ 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.