38

我想为基于 2 列的记录定义一个唯一键:“id”和“语言”

让用户提交以下字符串: id=1 语言=en 值=blabla 英语 id=1 语言=fr 值=blabla 法语

我尝试使用 set_primary_key 和 add_index 但它不起作用( add_index :words, ["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
4

7 回答 7

54

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

它应该工作。也许您的数据库中已经有一些非唯一数据并且无法创建索引?但是(正如@Doon 注意到的那样,这将是多余的,因为 id 总是唯一的)。所以你需要在两列上创建主键。

要在 rails 中定义 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);"

并使用此 gem 在您的模型中设置 primary_key:http ://rubygems.org/gems/composite_primary_keys :

class Word < ActiveRecord::Base
    self.primary_keys = :id,:language_id
end
于 2012-10-05T12:33:01.337 回答
9

在 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

于 2017-03-23T22:31:27.027 回答
2

模型

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

你会得到这张桌子

图片

于 2016-03-24T07:44:59.243 回答
1

正如我在评论中所说,如果你尝试这个,你会遇到障碍,而且它并没有真正支持开箱即用。您可以查看http://compositekeys.rubyforge.org ,它提供了一种在 Rails 中执行复合主键的方法。我没有使用它,因为我还没有需要(通常当我有一些复合键的东西时,就像它只是一个没有主键的连接表和连接对(HABTM)上的唯一索引)。

于 2012-10-05T12:42:19.810 回答
0

根据您的用例,您可能想尝试使用复合键 gem,它允许您定义复合主键并增强 ActiveRecord 来处理这种模型(对于与此模型的关联或 url_for 助手等有很大帮助)。

因此,如果您计划将此模型用作任何其他导轨模型,那么 gem 将有很大帮助。

于 2012-10-05T12:43:06.930 回答
0

在将站点迁移到 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"

这就是诀窍。不是我想要的,但比战斗框架更好。

于 2016-02-16T22:55:58.267 回答
0

就像@rogal111 说的那样,但是如果主键已经存在,那么你会想要这样做

ALTER TABLE sections DROP PRIMARY KEY, ADD PRIMARY KEY(id, workspace_id, section_key);
于 2016-12-01T03:30:12.510 回答