2012-10-05 136 views
29

唯一的主键,我想定义基于2列独特记录键:“身份证”和“语言”定义基于2列

让用户提交以下字符串: ID =我尝试使用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

如果这个词属于一种语言,您为什么需要将它存储在它的语言?您可以将其委托给语言模型。这就是说你会与铁轨战斗。我只是使用ID键作为主键。代表:朗语言,而不用担心复合键 – Doon

+0

的确,谢谢。 :lang来自ald scaffilding。我需要从这里删除它,因为我使用语言模型。 Thx –

回答

44

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

它应该工作。也许你已经有一些非唯一的数据在你的数据库和索引不能创建?但是(正如@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 
+0

这将为id/language_id在表格上添加唯一索引),但更可能的id仍然是主键,并受到唯一索引的影响。所以这个索引是多余的,因为id始终是唯一的。 – Doon

+3

也有可能:'validates:language_id,uniqueness:{scope:[:id]}' –

+0

如何基于两列创建一个组合的唯一键(不是主键)?这基本上可以防止在列a和列b上创建具有相同值的多行。 –

1

正如我在我的评论说,你将战斗如果你尝试这样的话,它并没有真正支持开箱即用。你可以看看http://compositekeys.rubyforge.org,它提供了一种在rails中执行复合主键的方法。我还没有使用它,因为我还没有需要(通常当我有一些组合键,比如它只是一个连接表,没有主键和连接对上的唯一索引(HABTM)。)

根据
0

您的使用情况下,你可能会想尝试composite key gem它允许您定义复合主键,也ehances的ActiveRecord对付这种模型(帮助了很多协会,以这种模式或url_for助手等) 。

所以,如果你在使用这个模型任何其他轨道模型的创业板将有很大的帮助计划。

0

我网站迁移到Rails的时候遇到了类似的问题。我有用于存储文本DA表TA为每种语言我的网站提供,所以我有这样的事情:

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" 

而且做到了这一点。不是我想要的,但比战斗框架更好。

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 

你会得到这个表

image

0

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

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

在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模型。