我有一个奇怪的问题,我无法解决。

我想使用mysql的群集功能将相关记录彼此相邻存储在磁盘上。 Mysql通过表上的主键进行群集,对于默认的rails模型,该键为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列存在,并且我希望Rails仍然使用它,因为它认为是表的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。

有谁对我可以执行的操作使此测试套件在此设置中正常工作有任何想法?

最佳答案

我知道发生了什么事。

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

因此,尽管我的开发数据库看起来像我期望的那样,但是测试数据库看起来却有所不同-似乎生成schema.rb文件的代码无法理解我创建的数据库格式,并且不能创建可以正确反映我的迁移的schema.rb。

如果我用以下方法加载测试数据库:

$ rake db:migrate RAILS_ENV=test


然后使用以下命令运行我的测试套件:

$ rake test:all


一切正常。这是因为test:all任务在运行测试套件之前不会重新加载数据库。

因此,我在问题中描述的在维护rails ID密钥的同时创建替代主键的工作原理,除了schema.rb部分。

关于mysql - Rails 4备用主键与MySQL,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19125207/

10-13 04:44
查看更多