我想基于2列定义记录的唯一键:'id'和'language'
让用户提交以下字符串: id = 1 language = en value = blabla english id = 1 language = fr value = blabla french
我尝试使用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
答案 0 :(得分:47)
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
答案 1 :(得分:6)
在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
属性。
答案 2 :(得分:1)
正如我在评论中所说的那样,如果你尝试这样做,你将会对抗轨道,并且开箱即用并不支持。您可以查看http://compositekeys.rubyforge.org,它提供了在rails中执行复合主键的方法。我没有使用它,因为我还没有需要(通常当我有一些复合键时,就像它只是一个连接表,没有主键和连接对上的唯一索引(HABTM)。 / p>
答案 3 :(得分:1)
<强>模型强>
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
你会得到这张表
答案 4 :(得分:0)
根据您的使用情况,您可能需要尝试composite key gem,它允许您定义复合主键,并且还可以增强ActiveRecord来处理这种模型(对于此模型或url_for的关联有很大帮助)帮手等。)。
因此,如果您计划将此模型用作任何其他轨道模型,那么gem将会有很多帮助。
答案 5 :(得分: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"
这就是诀窍。不是我想要的,但比打击框架更好。
答案 6 :(得分:0)
就像@ rogal111说的那样,但是如果主键已经存在那么你就会想要这样做
ALTER TABLE sections DROP PRIMARY KEY, ADD PRIMARY KEY(id, workspace_id, section_key);