1

我有一个奇怪的问题,我无法弄清楚。

我想利用 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。

有没有人知道我可以做什么让我的测试套件在这个设置中正常工作?

4

1 回答 1

0

我弄清楚发生了什么事。

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

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

如果我加载我的测试数据库:

$ rake db:migrate RAILS_ENV=test

然后运行我的测试套件:

$ rake test:all

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

因此,除了 schema.rb 部分之外,我在问题中描述的在维护 rails ID 键的同时创建备用主键的内容有效。

于 2013-10-02T14:38:47.697 回答