尝试调用私有方法+与.rake文件冲突

时间:2012-06-15 14:10:42

标签: ruby-on-rails ruby

我正面临一个奇怪的错误。任何人都可以解释一下这个原因..

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

设置和体验包含数据库列“

在我的网站模型中,我有这段代码

  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'之一。

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

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]

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

1 个答案:

答案 0 :(得分:1)

我认为这是问题所在:

该模型没有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方法。可能它打破了ActiveRecord的method_missing方法:

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

作为Settings的{​​{1}}类子类(与每个标准类一样),您的Object定义会破坏事物。

相关问题