在动态方法中更改实例变量(使用ActiveResource的动态资源)

时间:2013-05-21 20:03:54

标签: ruby-on-rails ruby ruby-on-rails-3 activeresource dynamic-dispatch

我正在使用动态调度来定义继承自ActiveResource的类中的几个类方法。

class Invoice < ActiveResource::Base
  self.site = 'http://localhost:8080/'

  def self.define(method)
    define_singleton_method(method) do |params = {}|
      site = self.site
      self.site = "#{self.site}/Invoice/#{method.to_s.camelize(:lower)}"

      puts "self.site -> #{self.site}"  
      results = Invoice.all(params: params)

      self.site = site
      puts "changing self.site back to #{site}"     

      return results
    end
  end

  define :get_details
  define :put_approval
  define :get_attachment
  define :get_pending_notifications
end

这适用于第一次调用,无论它是什么(Invoice.get_details,Invoice.get_pending_notifications ...),但在第二次调用时总是失败。

我想了解为什么会发生这种情况以及我可以做些什么来解决这个问题。

2 个答案:

答案 0 :(得分:1)

进一步研究,我发现self.site在我提出要求时并没有真正改变。它告诉我它在日志中正在发生变化,但它确实存在! self.site在第一个调用的方法中不会从其初始设置状态更改。我有一个关于为什么这不起作用的理论以及使其工作的解决方法。

首先,我的理论:

当调用任何一个定义的类方法时,设置site。由于site超出了被调用的类方法的范围,因此一旦初始设置它,就不能再进行更改。

一个例子:

Invoice.get_details

Invoice.site最初设置为“localhost:8080 / Invoice / getDetails”

Invoice.get_pending_notifications

Invoice.site无法更改,因为它已被定义为“localhost:8080 / Invoice / getDetails”

以上只是一个有效的理论。

我是如何工作的:

删除对self.site的所有引用,但初始集self.site = "localhost:8080"除外,而是使用url字符串。 (在http://ofps.oreilly.com/titles/9780596521424/activeresource_id59243.html

的“从自定义路径中查找资源”部分下
class Invoice < ActiveResource::Base
  self.site = "localhost:8080"
  def self.define(method)
    define_singleton_method(method) do |params = {}|
      url = "#{self.site}/Invoice/#{method.to_s.camelize(:lower)}"

      # results = Invoice.all(params: params) <- Change this call to below
      results = Invoice.find(:all, from: url, params: params) 

      return results
    end
  end

  define :get_details
  define :put_approval
  define :get_attachment
  define :get_pending_notifications
end

使用上面的代码,我可以调用任何定义的方法,每个方法指向不同的URL,没有问题。

答案 1 :(得分:0)

网站很可能无法正常重置。试试这个,它在ruby控制台下工作:

class Invoice < ActiveResource::Base
  self.site = 'http://localhost:8080/'

  def self.define(method)
    define_singleton_method(method) do |params = {}|
      site = self.site
      begin
        self.site = "#{self.site}/Invoice/#{method.to_s.camelize(:lower)}"
        Invoice.all(params: params)
      ensure
        # this code will always be run, even if there is an exception above
        # and it won't affect the original value returned above
        self.site = site
      end
    end
  end

  define :get_details
  define :put_approval
  define :get_attachment
  define :get_pending_notifications
end