Remove .xml extension from ActiveResource request
Asked Answered
G

4

14

I am trying to use ActiveResource to consume xml data from a third party API. I can use the RESTClient app to successfully authenticate and make requests. I coded my app and when I make a request I get a 404 error. I added:

ActiveResource::Base.logger = Logger.new(STDERR) 

to my development.rb file and figured out the problem. The API responds with xml data to requests that do NOT end in xml. EG, this works in RESTClient:

https://api.example.com/contacts

but ActiveResource is sending this request instead

https://api.example.com/contacts.xml

Is there anyway "nice" way to strip the extension from the request being generated by ActiveResource?

Thanks

Gaillard answered 21/7, 2010 at 15:37 Comment(0)
H
6

You probably need to override the element_path method in your model.

According to the API, the current defintion looks like this:

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}.#{format.extension}#{query_string(query_options)}"
end

Removing the .#{format.extension} part might do what you need.

Hame answered 22/7, 2010 at 4:8 Comment(1)
Yes, this does the trick. I found this article which goes into greater depth on working with ActiveResource and APIs. quarkruby.com/2008/3/11/consume-non-rails-style-rest-apisGaillard
G
13

You can exclude the format string from paths with:

class MyModel < ActiveResource::Base
  self.include_format_in_path = false
end
Gallicism answered 6/12, 2013 at 22:4 Comment(1)
Note that this only works as of ActiveResource 4. If you're stuck on 3.2.x or earlier, it will raise an exception.Mcgray
H
6

You probably need to override the element_path method in your model.

According to the API, the current defintion looks like this:

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}.#{format.extension}#{query_string(query_options)}"
end

Removing the .#{format.extension} part might do what you need.

Hame answered 22/7, 2010 at 4:8 Comment(1)
Yes, this does the trick. I found this article which goes into greater depth on working with ActiveResource and APIs. quarkruby.com/2008/3/11/consume-non-rails-style-rest-apisGaillard
H
6

You can override methods of ActiveResource::Base

Add this lib in /lib/active_resource/extend/ directory don't forget uncomment
"config.autoload_paths += %W(#{config.root}/lib)" in config/application.rb

module ActiveResource #:nodoc:
  module Extend
    module WithoutExtension
      module ClassMethods
        def element_path_with_extension(*args)
          element_path_without_extension(*args).gsub(/.json|.xml/,'')
        end
        def new_element_path_with_extension(*args)
          new_element_path_without_extension(*args).gsub(/.json|.xml/,'')
        end
        def collection_path_with_extension(*args)
          collection_path_without_extension(*args).gsub(/.json|.xml/,'')
        end
      end

      def self.included(base)
        base.class_eval do
          extend ClassMethods
          class << self
            alias_method_chain :element_path, :extension
            alias_method_chain :new_element_path, :extension
            alias_method_chain :collection_path, :extension
          end
        end
      end  
    end
  end  
end

in model

class MyModel < ActiveResource::Base
  include ActiveResource::Extend::WithoutExtension
end
Heirship answered 25/5, 2011 at 14:16 Comment(2)
Note, as of rails 3, you may want to put this under /extras in your app's top level directory (instead of under /lib), since that is now the directory rails will autoload if you uncomment the correct like in config/application.rb.Aharon
This is a pretty heavy-handed solution which modifies the behaviour of ActiveResource application wide. A more localized solution may be better, depending on requirements.Purificator
P
5

It's far simpler to override the _path accessors mentioned in this answer on a class-by-class basis, rather than monkey-patching ActiveResource application-wide which may interfere with other resources or gems which depend on ActiveResource.

Just add the methods directly to your class:

class Contact < ActiveResource::Base

  def element_path
    super.gsub(/\.xml/, "")
  end

  def new_element_path
    super.gsub(/\.xml/, "")
  end

  def collection_path
    super.gsub(/\.xml/, "")
  end
end

If you're accessing multiple RESTful resources within the same API, you should define your own base class where common configuration can reside. This is a far better place for custom _path methods:

# app/models/api/base.rb
class Api::Base < ActiveResource::Base
  self.site     = "http://crazy-apis.com"
  self.username = "..."
  self.password = "..."
  self.prefix   = "/my-api/"

  # Strip .xml extension off generated URLs
  def element_path
    super.gsub(/\.xml/, "")
  end
  # def new_element_path...
  # def collection_path...
end

# app/models/api/contact.rb
class Api::Contact < Api::Base

end

# app/models/api/payment.rb
class Api::Payment < Api::Base

end

# Usage:

Api::Contact.all()      # GET  http://crazy-apis.com/my-api/contacts
Api::Payment.new().save # POST http://crazy-apis.com/my-api/payments
Purificator answered 3/8, 2012 at 22:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.