1

我正面临一个奇怪的错误。谁能解释一下这是什么原因。。

我有一个名为站点、设置和体验的模型。

设置和体验有数据库列“

在我的站点模型中,我有这个代码

  def populate_experiences_bit_set
    self.experiences.map(&:bit).inject(0, :|)
  end

  def populate_settings_bit_set
    self.settings.map(&:bit).inject(0, :|)
  end

在我名为 2_28.rake 的 rake 文件中,有一个名为bit的方法

 def bit(klass)
    current_class = klass.find(:all)
    if current_class.count == 0
      return 1
    else
      return (current_class.last.bit * 2)
    end
  end

此方法用于同一 rake 文件中的 rake 任务“get_value”之一。

在同一个文件中还有另一个名为 create_sites_report_data 的 rake 任务,其中有一行:

site.populate_experiences_bit_set

现在当我运行 rake 任务时

rake releases:2.28:create_sites_report_data

我收到一条错误消息

" 尝试调用私有方法 /Users/rakeshshetty/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-2.3.5/lib/active_record/attribute_methods.rb:236:in `method_missing' "

In console, this works fine 

>> s = Site/364
=> #<Site id: 364, name: "1 Field Ambulance - Detachment Wainwright", type: "Site", created_at: "2009-12-29 16:53:58", updated_at: "2009-12-29 16:53:58", short_name: "1 Field Am", self_updated_at: nil, last_updater_id: nil, vfp_id: "2BL0NFMI1", dup_reference_id: nil, field_id: nil, marked_as_deleted: false>
>> s.experiences.map(&:bit).inject(0, :|)
=> 0
>> s.settings.map(&:bit).inject(0, :|)
=> 64

我将 2_28.rake 文件中的方法名称从 bit 替换为 bit_x Rake 工作正常

blsi1181a:cpi_2.24 rakeshshetty$ rails -v 
Rails 2.3.5 
blsi1181a:cpi_2.24 rakeshshetty$ ruby -v 
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.3.0]

我的问题是位是设置和体验中的一个字段。它如何调用 rake 方法函数 bit() ?这个 rake 文件是在应用程序加载后加载的吗?

4

1 回答 1

2

我认为这是问题所在:

该模型没有bit方法,它使用“方法缺失”方法创建它(即,当您在对象上调用不存在的方法时,它会调用其 method_missing 方法,默认情况下会引发异常)。

ActiveRecord 使用缺少的方法来设置相关表的列的方法(即:

Site.new.bit -> the method does not exist -> method_missing -> 
  is there a column called 'bit'? -> yes -> create the method bit with this code

现在,您bit在对象级别创建了一个方法。可能它打破了method_missingActiveRecord 的方法:

Site.new.bit -> the method exists -> call that method

资源:


编辑:经过深入分析

如果您查看 ActiveRecord 源(接近错误):

def method_missing(method_id, *args, &block)
  method_name = method_id.to_s

  if self.class.private_method_defined?(method_name)
    raise NoMethodError.new("Attempt to call private method", method_name, args)
  end

  [...]

现在,试试这个任务:

namespace :rake_test do

  desc 'With bit method'
  task :with => :environment do

    def bit(klass)
      # Implementation
    end

    puts Object.private_method_defined?("bit")
    puts Settings.private_method_defined?("bit")

  end

  desc 'Without bit method'
  task :without => :environment do

    puts Object.private_method_defined?("bit")
    puts Settings.private_method_defined?("bit")

  end

end

让我们运行它们:

rake rake_test:with ; rake rake_test:without

输出:

true
true
false
false

当您定义bit方法时,您处于对象上下文中(这不仅适用于 rake 任务文件,而且适用于每个 ruby​​ 脚本文件)。所以你定义了一个Object.bit方法;正如您从 Rails 源代码中看到的那样,在定义模型bit方法之前,它会尝试查看是否存在Model.method,如果存在,它会引发异常。

作为(就像每个标准类)的Settings类子类,您的定义破坏了事物。Objectbit

于 2012-06-15T14:29:33.383 回答