Ruby on rails class_eval块参数和class_eval字符串参数的差异

Ruby on rails class_eval块参数和class_eval字符串参数的差异,ruby-on-rails,ruby,Ruby On Rails,Ruby,为了简化我的情况,我有一个模块,在我的Rails应用程序初始化时加载到Mongoid::Document中: Mongoid::Document.send(:include, ActiveRecordBridge) 本模块定义了一种方法: def has_many_records(*records) options = records.extract_options! if options[:polymorphic] class_eval <<-EOS

为了简化我的情况,我有一个模块,在我的Rails应用程序初始化时加载到Mongoid::Document中:

Mongoid::Document.send(:include, ActiveRecordBridge)
本模块定义了一种方法:

def has_many_records(*records)
  options = records.extract_options!
  if options[:polymorphic]
    class_eval <<-EOS
      def #{ record }
        @#{ record } ||= #{ record.to_s.singularize.classify.constantize }.where( document_id: String(id), document_type: self.class.name)
      end
    EOS
  end
end
这非常有效,但后来另一位开发人员将gem添加到我的系统中,并在SomethingElse类中使用了它:

class SomethingElse < ActiveRecord::Base
  sync :all
end
虽然这是可行的,但这不是我想要的,因为现在我显式地编写了其他内容,而不是使用字符串插值


我的问题:当块参数没有导致此错误时,会导致此错误的字符串参数如何?

当您传入正在插值的字符串参数时,
record.to_.singularize.classify.constantize
。最后一次调用
constantize
尝试查找常量
SomethingElse
。开发中的Rails应用程序通常设置为延迟加载它们的类,因此只有在这一点上,应用程序才会尝试加载包含
SomethingElse
的文件,并且由于文件包含错误,因此在加载时会遇到错误


在第二种情况下,只有在实际调用
SomethingElse
时,才会到达对
SomethingElse
的引用,这意味着只有在该点才会加载文件并遇到错误。您可以尝试启动控制台并调用该方法,或者只是键入
SomethingElse
——两者都会引发错误。

class\u eval with the block根本不会引发错误。这就是我问题的重点。只有在传递字符串时才会引发错误。您认为我的初始值设定项是在同步所需的其他初始化之前被调用的吗?因为在我的初始值设定项中,我指定要加载的这个文件,首先用01_uu作为前缀,然后我还注意到在我的初始值设定项中有另一个文件sync_ucore,之后会加载它。如果第二个调用直到稍后才被调用,那么它不抛出错误是有意义的,因为在加载类之前可能需要另一个初始值设定项。但是再说一次,类不是在任何初始值设定项之前加载的吗?我认为默认情况下,类只有在使用时才会被加载。我再次遇到这个问题,但这一次是阴谋造成的错误。在字符串被计算并尝试加载常量的意义上,您是对的。此时,由于该初始值设定项在用于配置类的初始值设定项之前运行,因此会发生错误。当我更改initializers的优先级并确保首先初始化所有类的配置,然后加载使用它们的初始化器时,错误就会消失。是你的回答引导我走上了正确的道路,因此我认为它是正确的。
class SomethingElse < ActiveRecord::Base
  sync :all
end
Uncaught exception: undefined method `sync' for #<Class:0x007fb7910530c0>
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activerecord-4.1.5/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
    /Users/donato/projects/core revisions/core/app/models/something_else.rb:73:in `<class:Task>'
    /Users/donato/projects/core revisions/core/app/models/something_else.rb:19:in `<top (required)>'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:443:in `load'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:443:in `block in load_file'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:633:in `new_constants_in'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:442:in `load_file'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:342:in `require_or_load'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:480:in `load_missing_constant'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:180:in `const_missing'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/inflector/methods.rb:238:in `const_get'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/inflector/methods.rb:238:in `block in constantize'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/inflector/methods.rb:236:in `each'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/inflector/methods.rb:236:in `inject'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/inflector/methods.rb:236:in `constantize'
    /Users/donato/.rvm/gems/ruby-2.1.2@core/gems/activesupport-4.1.5/lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
    /Users/donato/projects/core revisions/core/lib/active_record_bridge.rb:55:in `block in has_many_records'
      class_eval do
          def something_elses
            @something_elses ||= SomethingElse.where(document_id: String(id), document_type: self.class.name)
          end
        end