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
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.
You can exclude the format string from paths with:
class MyModel < ActiveResource::Base
self.include_format_in_path = false
end
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
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