Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

debugging activeresource

I'm trying to get activeresource (on Rails 3.2) working with the Freebase API and I haven't had much luck yet. How can I debug rails to see what's going on and make sure the request is well formed?

I think the suffixed .json is causing the failure but I don't know how to check what's going on?

Error:

ActiveResource::ResourceNotFound: Failed.  Response code = 404.  Response message = Not Found.

Code:

class Freebase < ActiveResource::Base
  class << self # also tried without this, same result
    def element_path(id, prefix_options = {}, query_options = nil)
      prefix_options, query_options = split_options(prefix_options) if query_options.nil?
      "#{prefix(prefix_options)}#{collection_name}/#{id}#{query_string(query_options)}"
    end

    def collection_path(prefix_options = {}, query_options = nil)
      prefix_options, query_options = split_options(prefix_options) if query_options.nil?
      "#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
    end
  end


  self.site = "https://www.googleapis.com/freebase/v1/"
  self.format = :json

  #https://www.googleapis.com/freebase/v1/search?query=nirvana&indent=true

  #Freebase.get('search', :query => 'nirvana')



end

UPDATE:

Ok so I found two things going wrong...

1) The collection_path I'm trying to supersede doesn't work at all.. it still tacks .json onto every request. 2) https://www.googleapis.com:443/freebase/v1/freebases/search.json?query=nirvana It tacks freebase on afterwards... any ideas?

I also tried this fix:

Remove .xml extension from ActiveResource request

But it didn't remove the JSON suffix either.

UPDATE UPDATE:

Added the suggest update below which gives the correct PATH but now I'm getting

GET https://www.googleapis.com:443/freebase/v1/search/?query=monkey
--> 200 OK 2732 (693.3ms)
NoMethodError: undefined method `collect!' for #<Hash:0x007f9bde674900>
like image 923
ere Avatar asked Mar 05 '12 19:03

ere


6 Answers

Add ActiveResource::Base.logger = Logger.new(STDERR) to your config/application.rb ( Rails 3.x ).

You'll get output like :

POST http://localhost:3000/freebase.json
--> 201 Created 0 (15.8ms)

That shows method and response code ...

like image 167
Luca G. Soave Avatar answered Oct 04 '22 10:10

Luca G. Soave


ActiveResource isn't dead, but relative to ActiveRecord I can understand why you'd think so, it is definitely an unloved and underprivileged stepchild.

You'd probably be better off using something like Faraday_Middleware or HTTPParty. The former is my personal preference. Unless what you're doing is pulling from another Rails app or one that has perfect restful behaviour like Rails (which Freebase doesn't), ActiveResource is usually more trouble than it's worth.

That being said, you can accomplish what you want without overwriting any class methods by doing:

  self.site = "https://www.googleapis.com/"
  self.format = :json

  def self.search(word)
    self.find(:all, :from => "/freebase/v1/search/", :params => { :query => word })
  end
like image 22
holden Avatar answered Oct 03 '22 10:10

holden


enter image description here

To get detail login for ActiveResource have to patch the request method inside the gem(method.

place bellow files inside config/initializers you will get http method, path, request body, request hedaers

response body and header is already there if you need. doc

config/initializers/activeresource_patch.rb

module ActiveResource
  class Connection
    private
      def request(method, path, *arguments)
        result = ActiveSupport::Notifications.instrument("request.active_resource") do |payload|
          payload[:method]      = method
          payload[:request_uri] = "#{site.scheme}://#{site.host}:#{site.port}#{path}"
          payload[:request_path] = path
          payload[:request_body] = arguments[0]
          payload[:request_headers] = arguments[1]
          payload[:result]      = http.send(method, path, *arguments)
        end
        handle_response(result)
      rescue Timeout::Error => e
        raise TimeoutError.new(e.message)
      rescue OpenSSL::SSL::SSLError => e
        raise SSLError.new(e.message)
      end
  end
end

config/initializers/activeresource_logger.rb

Rails.application.configure do

  def activeresource_logger
  @activeresource_logger ||= Logger.new("#{Rails.root}/log/activeresource_logger.log")
  end

  ActiveSupport::Notifications.subscribe('request.active_resource')  do |name, start, finish, id, payload|
   if Rails.env.development?
    activeresource_logger.info("====================== #{start} : #{payload[:method].upcase} ======================")
    activeresource_logger.info("PATH: #{payload[:request_path]}")
    activeresource_logger.info("BODY: #{payload[:request_body]}")
    activeresource_logger.info("HEADERS: #{payload[:request_headers]}")
    # activeresource_logger.info("STATUS_CODE: #{payload[:result].code}")
    # activeresource_logger.info("RESPONSE_BODY: #{payload[:result].body}")
   end
  end

end
like image 24
Alupotha Avatar answered Sep 30 '22 10:09

Alupotha


ActiveResource is going to expect that endpoint to return the data in a very specific format.

For the longest time we've been using ActiveResource at my company for inter-application communication. However more recently we've started leaning towards HTTParty because it performs a lot less voodoo magic, and tends to be a much small exercise in hair-pulling.

Here's an example of how we're using HTTParty now:

module CoreResources
  class Job
    include HTTParty
    base_uri Rails.configuration.core_resource_uri
    basic_auth Rails.configuration.core_resource_user, Rails.configuration.core_resource_password

    def self.search(entity)
      get("/api/v1/jobs.json", :query => {:entity_id => entity.id})
    end

    def self.find(id)
      result = get("/api/v1/jobs/#{id}.json")
      raise CoreResources::JobNotFound.new if result.response.code == "404"
      raise "Unexpected response from resource job find: #{result.response.code} #{result.response.to_s}" if result.response.code =~ /^(?:4|5)..$/
      result
    end
  end
end

The problem with ActiveResource is that it will take the very specifically-crafted json or xml markup, and instantiate ActiveResource objects and nested objects based on it. It's having issues calling collect because something in the json response was supposed to be formatted like an enumerable, and wasn't (likely the parent node should have been an array or something, not sure), which makes it blow up.

With HTTParty you get a json-parsed collection to work with.

It's easy enough for me to do this:

jobs = CoreResources::Job.search(my_entity)
puts jobs.inspect

# [{
#    "id" => 4,
#    "created_by_id" => 12,
#    "description" => "I like pie"
# },
# {
#    "id" => 5",
#    "created_by_id" => 12,
#    "description" => "Mmm, cake"
# }]

Which let's me access jobs via an easy collection array/hash construct jobs[0].fetch("description"), as opposed to ActiveResource: jobs[0].description. ActiveResource is slower to insantiate those collections, needlessly takes up memory with them, and encourages you to duplicate code that should just be served by the endpoint in your ActiveResource model (Then again, if you're using a third-party API you may have no other choice, but I have never successfully gotten ARes to interface with third-party API's).

We've run into a lot of other ActiveResource problems where it does this nonsensical dynamic creation of class names based on nested resources from your endpoint, but half the time does it incorrectly... It's really just a mess.

Moral of the story: Much more of a fan of HTTParty now. That endpoint is probably just not returning data in the right format, and unless it does ActiveResource will be a hackfest to get it to read it right.

like image 32
nzifnab Avatar answered Oct 03 '22 10:10

nzifnab


ActiveResource has a fairly narrow use-case. You probably want to use a more generic interface for working with Freebase.

Some code from the LinkTV Platform's FreeBase API might be of some help.

like image 34
aceofspades Avatar answered Oct 02 '22 10:10

aceofspades


The NoMethodError: undefined method 'collect!' for #<Hash:0x007f9bde674900> error seems to be an issue on rails https://github.com/rails/rails/issues/2318 . I had a similar problem but the hacks provided didn't work so I had to tweak them a bit , you can find my answer here .

like image 30
lesce Avatar answered Oct 03 '22 10:10

lesce