class_eval块参数和class_eval字符串参数差异

时间:2015-05-08 20:46:02

标签: 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
      def #{ record }
        @#{ record } ||= #{ record.to_s.singularize.classify.constantize }.where( document_id: String(id), document_type: self.class.name)
      end
    EOS
  end
end

现在我的Mongoid课程使用它:

class Something
  include Mongoid::Document
  has_many_records :something_else, polymorphic: true
end

这很有效,但是另一位开发人员将sync gem添加到我的系统中,并在SomethingElse类中使用了它:

class SomethingElse < ActiveRecord::Base
  sync :all
end

一旦启动Rails应用程序,我就会遇到以下异常:

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的字符串参数时,错误消失了:

      class_eval do
          def something_elses
            @something_elses ||= SomethingElse.where(document_id: String(id), document_type: self.class.name)
          end
        end

虽然这有效,但这不是我想要的,因为现在我明确地写了something_else而不是使用字符串插值。

我的问题:导致此错误的字符串参数怎么样,而block参数不会?

1 个答案:

答案 0 :(得分:0)

当您传入字符串参数时,您正在插入record.to_s.singularize.classify.constantize。对constantize的最后一次调用会尝试查找常量SomethingElse。开发中的Rails应用程序通常设置为懒惰地加载它们的类,所以只有在这一点上app才会尝试加载包含SomethingElse的文件,因为文件包含加载时遇到的错误。

在第二种情况下,在您实际调用SomethingElse之前未达到对something_elses的引用,这意味着只有在此时才会加载文件并遇到错误。你可以尝试启动一个控制台并调用该方法或只输入SomethingElse - 两者都应该引发错误。