【问题标题】:SQLite migration removes 'add_index' and 'add_foreign_key' from schema.rb fileSQLite 迁移从 schema.rb 文件中删除 'add_index' 和 'add_foreign_key'
【发布时间】:2013-01-09 09:39:39
【问题描述】:

我在同一个 Rails 项目上使用 SQLite3 和 MySQL,但在两台不同的计算机上。我注意到,当我运行所有迁移时生成的 schema.rb 在两种环境中看起来都不同。当我在 SQLite3 环境中运行迁移时,从schema.rb 文件中删除了以下语句

add_index "places", ["user_id"], :name => "places_user_id_fk"
add_foreign_key "places", "users", :name => "places_user_id_fk"

请注意,我使用的是 foreigner gem,它使用 add_foreign_keyremove_foreign_key 扩展了迁移。

以下是与问题相关的迁移和模型:

# 20130123004056_create_places.rb
class CreatePlaces < ActiveRecord::Migration
  def change
    create_table :places do |t|
      t.string :name
      t.string :location
      t.integer :user_id
      t.timestamps
    end
  end
end

...

# 20130123234250_add_foreign_key.rb
class AddForeignKey < ActiveRecord::Migration
  def change
    add_foreign_key(:places, :users)
  end
end

...

# user.rb
class User < ActiveRecord::Base
  has_many :places
end

...

# place.rb
class Place < ActiveRecord::Base
  belongs_to :user    
end

问题:如何定义usersplaces 之间的关系,SQLite3 和 MySQL 都可以处理?

【问题讨论】:

  • add_foreign_key 不是 Rails 的一部分。这是哪里来的?
  • @Deefour 对不起,我忘了提到我使用的 gem。

标签: mysql ruby-on-rails sqlite rails-migrations foreigner


【解决方案1】:

foreignerREADME 明确声明

支持以下适配器:

  • sqlite (外键方法是无操作的)

所以您的 SQLite 数据库没有设置外键约束因为foreigner 不支持它们。从 SQLite 数据库生成 db/schema.rb 时,这就是没有指定外键的原因。

Rails Guide on Migrations 经常提到外键

如果您需要执行特定于您的数据库的任务(例如创建外键约束),那么execute 方法允许您执行任意 SQL

甚至还有how to add/remove a foreign key的例子。

在刚开始使用 Rails 时使用过foreigner,我建议您将其从Gemfile 中删除,或者

  1. 根本不要使用外键;只需在 ActiveRecord 关联中指定您的级联
  2. 使用上述链接示例中描述的 execute 迁移方法(并确保所有不同的 RDBMS 支持您放入 execute 方法中的任何内容)
  3. 如果您坚持使用外键,请停止在开发中使用 SQLite。无论如何,您不会在生产中使用 SQLite,并且已经在其他机器上使用更好的 RDMS(MySQL,“更好”,因为它具有 正在寻找的外键支持)。

正如您在 cmets 中的 pointed out 一样,SQLite 缺乏对创建表后添加外键的支持;它们不能通过 Rails 中的未来迁移添加。 我个人建议您使用选项 1 或 3,因为在迁移中通过 execute 命令创建一个满足 SQLite 限制同时在其他设备上具有相同最终结果的解决方案将更加困难RDMS'。

【讨论】:

  • 作为posted here,我遇到了包含手动SQL代码的迁移确实会引发异常的问题。
  • 您应该将问题作为另一个问题发布;这有点超出了这个范围。
  • 我必须撤消您帖子中的“正确答案”标志。 SQLite 不支持在创建表后对其进行更改。来自SQLite documentation:“[...] 其他类型的 ALTER TABLE 操作,例如 [...] ADD CONSTRAINT 等被省略。” here 讨论了同样的问题。
  • 我已经修改了我的答案,以便为选择 2(您似乎一直坚持的)提供更好的指导,并提供了第三种选择。我对您问题的原因的诊断是正确的(您使用的是外国人)。我修正了选项 2 的措辞;它不够通用。所有RDBMS都必须支持execute中的任何(如您所见,以这种方式添加外键不适用于SQLite)。我无法为您应该在execute 行中添加的内容提供解决方案,因为我个人认为这是错误的做法。如果这意味着我的回答对你来说不够正确,那很好。
  • 我同意。我最终删除了外键。在我的项目中,我使用inherited_resources,它负责我正在寻找的参照完整性。谢谢。
猜你喜欢
  • 1970-01-01
  • 2014-11-05
  • 2011-07-10
  • 1970-01-01
  • 2018-11-12
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
相关资源
最近更新 更多