Ruby on rails 在初始值设定项中重新打开类会中断属性访问器

Ruby on rails 在初始值设定项中重新打开类会中断属性访问器,ruby-on-rails,ruby,Ruby On Rails,Ruby,我正在尝试使用Rails4.2中的初始值设定项向ActiveRecord模型添加方法。但是,只要在初始值设定项中重新打开该类,就会破坏现有的属性访问器 模型应用程序/models/thing.rb: class Thing < ActiveRecord::Base end class Thing def self.new_method "hello" end end 测试文件test/models/thing_test.rb: require File.expand_p

我正在尝试使用Rails4.2中的初始值设定项向ActiveRecord模型添加方法。但是,只要在初始值设定项中重新打开该类,就会破坏现有的属性访问器

模型应用程序/models/thing.rb:

class Thing < ActiveRecord::Base
end
class Thing
  def self.new_method
    "hello"
  end
end
测试文件test/models/thing_test.rb:

require File.expand_path("../../test_helper", __FILE__)

class ThingTest < ActiveSupport::TestCase
  test "the truth" do
    thing = Thing.new
    thing.test_field = 1
    puts thing.new_method
  end
end

我想我很乐意这样做,但我想知道为什么仅仅重新打开类就不起作用。

我认为这是因为您声明了没有继承的方法。默认访问器来自
ActiveRecord::Base
。所以,当您声明新方法时,您重写了inheritor中的所有内容。

我认为这是因为您声明了没有继承的方法。默认访问器来自
ActiveRecord::Base
。因此,当您声明新方法时,您将覆盖继承器中的所有内容。

关键是您没有重新打开该类:您正在定义一个新的类。在开发和测试中,类在首次使用时被加载。通过在初始值设定项中定义
Thing
,可以防止加载Thing.rb文件


当您使用
Thing.class\u eval
时,您并没有定义一个新类,因此rails从Thing加载
Thing
。rb:此时,您正在添加
Thing
而不是替换它。

关键是您没有重新打开该类:您正在定义一个新类。在开发和测试中,类在首次使用时被加载。通过在初始值设定项中定义
Thing
,可以防止加载Thing.rb文件

当您使用
Thing.class\u eval
时,您并没有定义一个新的类,所以rails从Thing加载
Thing
。rb:此时您正在添加
Thing
而不是替换它


我在文件的顶部放了一条调试器语句。在调试器中,我可以查询Thing.superclass,得到ActiveRecord::Base。我可以创建一个实例,并在其上调用test_字段

仅仅是观察实验的行为就改变了结果。当您在调试器语句处停止时,类不存在。但在调试器控制台中计算
对象时,它是自动加载的

您可以在实际的初始值设定项中以这样或那样的方式触发模型的加载

# initializers/thing.rb
Thing # trigger autoloading
class Thing
  ...
end


# or
require 'app/models/thing.rb' # load explicitly
class Thing
  ...
end

我在文件的顶部放了一条调试器语句。在调试器中,我可以查询Thing.superclass,得到ActiveRecord::Base。我可以创建一个实例,并在其上调用test_字段

仅仅是观察实验的行为就改变了结果。当您在调试器语句处停止时,类不存在。但在调试器控制台中计算
对象时,它是自动加载的

您可以在实际的初始值设定项中以这样或那样的方式触发模型的加载

# initializers/thing.rb
Thing # trigger autoloading
class Thing
  ...
end


# or
require 'app/models/thing.rb' # load explicitly
class Thing
  ...
end

如果我使用
class-Thing
我会得到相同的结果如果我使用
class-Thing
我不会在初始值设定项中创建类,我会尝试重新打开它并添加一个方法。我的理解是Ruby允许这样做,初始化器不是先执行的。初始化器运行时,该类已经存在。我在文件顶部放置了一条调试器语句。在调试器中,我可以查询
Thing.superclass
,得到ActiveRecord::Base。我可以创建一个实例并调用它的test_字段。我不是在初始值设定项中创建类,而是尝试重新打开它并添加一个方法。我的理解是Ruby允许这样做,初始化器不是先执行的。初始化器运行时,该类已经存在。我在文件顶部放置了一条调试器语句。在调试器中,我可以查询
Thing.superclass
,得到ActiveRecord::Base。我可以创建一个实例并在上面调用test_字段。谢谢你的解释-这不是我自己会得出的结论!谢谢你的解释——这不是我自己会得出的结论!
Thing.class_eval do
  def self.new_method
    "hello"
  end
end
# initializers/thing.rb
Thing # trigger autoloading
class Thing
  ...
end


# or
require 'app/models/thing.rb' # load explicitly
class Thing
  ...
end