0

好吧,这是一个非常奇怪的问题。我正在尝试编写一个扩展 ActiveRecord::Migrations 的库,以便我可以在 Rails 迁移中编写这样的代码:

class TestEnterprise < ActiveRecord::Migration
  def up
    enterprise_mti_up superclass_table: 'test_superclasses', subclass_tables: ['test_subclass_ones', 'test_subclass_twos']
  end
  def down
    enterprise_mti_down superclass_table: 'test_superclasses', subclass_tables: ['test_subclass_ones', 'test_subclass_twos']
  end
end

这是库代码的示例:

def enterprise_mti_up(*args)
  enterprise_mti args.extract_options!, direction: :up
end

def enterprise_mti_down(*args)
  enterprise_mti args.extract_options!, direction: :down
end

当我在任一方向运行迁移时,一切似乎都正常:

==  TestEnterprise: migrating =================================================
-- enterprise_mti_up({:superclass_table=>"test_superclasses", :subclass_tables=>["test_subclass_ones", "test_subclass_twos"]})
   -> 0.0005s
==  TestEnterprise: migrated (0.0007s) ========================================

但是数据库保持不变,因为实际上 Rails 以某种方式将来自 enterprise_mti_up 和 enterprise_mti_down 的选项哈希转换为字符串!当我更改其中一个函数来操作哈希时,我得到以下结果:

def enterprise_mti_down(*args)
  opts = args.extract_options!
  puts "opts: #{opts}"
  puts "opts[:superclass_table]: #{opts[:superclass_table]}"
  puts "args: #{args}"
  puts "args.last.class: #{args.last.class}"
  enterprise_mti args.extract_options!, direction: :down
end

...

==  TestEnterprise: reverting =================================================
-- enterprise_mti_down({:superclass_table=>"test_superclasses", :subclass_tables=>["test_subclass_ones", "test_subclass_twos"]})
opts: {}
opts[:superclass_table]:
args: ["{:superclass_table=>\"test_superclasses\", :subclass_tables=>[\"test_subclass_ones\", \"test_subclass_twos\"]}"]
args.last.class: String
   -> 0.0002s
==  TestEnterprise: reverted (0.0005s) ========================================

有谁知道为什么将哈希转换为字符串以及如何将哈希传递给我的方法?谢谢!

注意:在我的测试中,我发现如果我在选项哈希之前传递一个字符串作为第一个参数,那么一切都会按照预期的方式工作。但我不应该在散列之前有任何论据。这使我认为 Rails 可能天生就期望将字符串/符号作为迁移方法中的第一个参数。

4

1 回答 1

1

解决了我的问题,虽然我仍然不知道它为什么会发生。我使用以下行将我的模块 (ActiveRecord::EnterpriseMtiMigrations) 包含在 ActiveRecord 代码中:

ActiveRecord::ConnectionAdapters::SchemaStatements.send :include, ActiveRecord::EnterpriseMtiMigrations

我从另一个 gem 中抄袭了这一行,acts_as_relation,它为 Rails 添加了 MTI 功能。但是,acts_as_relation 定义的迁移方法之后需要一个字符串参数和一个选项哈希。该模式与 ActiveRecord::ConnectionAdapters::SchemaStatements 中几乎所有方法的定义方式相匹配(例如,“create_table table_name, opts_hash”)。

鉴于这一事实,我有一种预感,通过将我的方法包含到 SchemaStatements 模块中,我以某种方式强制我的第一个参数成为一个字符串,以匹配上述模式。我用以下代码替换了上面的代码行:

ActiveRecord::Migration.send :include, ActiveRecord::EnterpriseMtiMigrations

现在一切正常(在删除了extract_options!@muistooshort 建议的第二个之后)。去搞清楚。

于 2013-10-29T12:59:25.413 回答