7

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>
Community
  • 1
  • 1
ere
  • 1,689
  • 1
  • 19
  • 39
  • 2
    Is activesource a dead subject? I can hardly find any documentation, and what exists is 2 years old. And hardly any fresh questions exist relating to it? Should I be using something else? – ere Mar 10 '12 at 10:46

6 Answers6

21

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 ...

Luca G. Soave
  • 11,195
  • 10
  • 55
  • 105
4

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
holden
  • 13,081
  • 21
  • 89
  • 157
  • That seems to fix the path problem, but now I get GET https://www.googleapis.com:443/freebase/v1/search/?query=monkey --> 200 OK 2732 (693.3ms) NoMethodError: undefined method `collect!' for # – ere Mar 10 '12 at 11:12
2

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
Alupotha
  • 8,014
  • 4
  • 43
  • 45
1

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.

nzifnab
  • 14,852
  • 3
  • 46
  • 62
  • What URL is your ActiveResource model hitting? You could post the response, or at least a dumbed-down version if it, so we could see why ActiveResource can't parse it if you're really dead-set on using ARes. – nzifnab Mar 13 '12 at 20:55
1

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.

aceofspades
  • 7,444
  • 1
  • 33
  • 47
1

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 .

Community
  • 1
  • 1
lesce
  • 6,074
  • 5
  • 25
  • 34