2013-10-01 25 views
1

我有一个奇怪的问题,我只是无法弄清楚。Rails 4与MySQL的备用主键

我想使用mysql的群集能力来在磁盘上彼此相邻存储相关记录。 Mysql通过表上的主键进行集群,这对于默认的导轨模型来说是ID。

但是,对于很多表格来说,表格的主键可能是有意义的,例如,user_id,subscription_id,在每个表格旁边聚集相关记录,并且当您询问时进行非常有效的查找用户所有订阅的数据库。

要做到这一点,我创建了一个MySQL表所示:

execute('create table subscriptions (
      id   integer not null auto_increment, 
      user_id integer not null, 
      feed_id integer not null, 
      folder_id integer, 
      created_at  datetime, 
      updated_at  datetime, 
      primary key (user_id, feed_id), 
      key id (id) 
     ) engine=InnoDB default charset=utf8'); 

请注意,我的PK是USER_ID,FEED_ID但我仍然有本ID列,我想轨仍然使用它作为是什么相信是桌上的PK。

首先,这一点都没有,直到我设置工作:

class Subscription < ActiveRecord::Base 

    self.primary_key = 'id' 
    ... 
end 

现在到了陌生的一部分。

当我运行测试中,我得到一个奇怪的错误:

Mysql::Error: Field 'id' doesn't have a default value: INSERT INTO `subscriptions` 

但是 - 如果我坚持在开发模式的应用程序,并通过网页做的操作,它工作得很好。

很多谷歌搜索后,我发现猴子补丁停止Rails的设置MySQL成为更严格的模式:

class ActiveRecord::ConnectionAdapters::MysqlAdapter 

private 
    alias_method :configure_connection_without_strict_mode, :configure_connection 

    def configure_connection 
    configure_connection_without_strict_mode 
    strict_mode = "SQL_MODE=''" 
    execute("SET #{strict_mode}", :skip_logging) 
    end 
end 

如果我补充这一点,我的测试套装似乎工作(对于大多数测试,但不全部),但是创建的任何模型的ID均为零。

再次在生产模式下,通过网页工作得很好,模型得到一个auto_increment ID预期。

有没有人有任何想法,我可以做什么这使我的测试套件在此设置中正常工作?

+0

不会使用UUID主键比这更可靠吗? – tadman

+0

不确定UUID PK。它实际上只是另一个与ID序列相似的代理PK。我并不想开始讨论MySQL集群,但通过在user_id,feed_id上使用PK,这意味着即使用户长时间创建Feed时,它们也将全部存储在磁盘上,允许所有这些数据以一个数据库读取或两个而不是多个读取。它也是桌子上的天然钥匙,因为桌子在这双桌子上应该是独一无二的。 –

+0

为什么不在'(user_id,feed_id)'对上抛出一个唯一的约束/索引并且让​​PK单独存在?对于Rails来说,这可能比试图混淆PK更容易。 –

回答

0

我想清楚发生了什么事。

我不记得的是开发数据库是通过对数据库运行迁移创建的,该数据库也生成schema.rb文件。然后使用schema.rb文件加载测试数据库。

因此,虽然我的开发数据库看起来和我的预期一样,但测试数据库看起来不同 - 看起来生成schema.rb文件的代码无法理解我创建的数据库格式,也没有创建反映的schema.rb我的迁移正确。

如果我打开我的测试数据库:

$ rake db:migrate RAILS_ENV=test 

然后运行我的测试套件:

$ rake test:all 

事情正常工作。这是因为测试:在运行测试套件之前,所有任务都不会重新加载数据库。

所以,我在问题中描述了创建一个替代主键,同时保持导轨ID键工作,除了schema.rb部分。