문제

I am using dynamic dispatch to define several class methods in a class that inherits from 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

This works great for the first call, whatever it is (Invoice.get_details, Invoice.get_pending_notifications...), but always fails on the second call.

I would like to understand why this is happening and what I can do to get it fixed.

도움이 되었습니까?

해결책

Researching this further, I have found that self.site is not actually changing when I ask it to. It tells me it is changing in the logs, but it lies! self.site does not change from its initial set state in the first method called. I have a theory as to why this is not working and a workaround to get it working.

First, my theory:

When any one of the class methods defined is called, site is set. Since site is outside of the scope of the class method being called, once it is set initially, it cannot be changed thereafter.

An example:

Invoice.get_details

Invoice.site is initially set to "localhost:8080/Invoice/getDetails"

Invoice.get_pending_notifications

Invoice.site cannot be changed because it is already defined as "localhost:8080/Invoice/getDetails"

The above is just a working theory.

How I got this working:

Remove all references to self.site except for the initial set self.site = "localhost:8080" and instead use a url string. (Under the section "Finding resources from custom paths" at 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

Using the code above, I can call any of the methods defined, each pointing to a different url, without issue.

다른 팁

Most likely the site is not getting reset properly. Try this, it works under ruby console:

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top