I have 2 RESTful Rails apps I\'m trying to make talk to each other. Both are written in Rails 3 (beta3 at the moment). The requests to the service will require the use an ap
An Active Resource Object behaves much like a (simplified) Active Record object. If you wish to pass through a new param, then you can set it on the AR object by adding it as an attribute. eg:
jane = Person.create(:first => 'Jane', :last => 'Doe', :api_key => THE_API_KEY)
it should pass the api_key as a parameter, along with all the others.
I have much nicer solution ! I try with Rack in middleware but i no find any solution in this way....
I propose you this module for override methods of ActiveReouse::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 AuthWithApi
module ClassMethods
def element_path_with_auth(*args)
element_path_without_auth(*args).concat("?auth_token=#{self.api_key}")
end
def new_element_path_with_auth(*args)
new_element_path_without_auth(*args).concat("?auth_token=#{self.api_key}")
end
def collection_path_with_auth(*args)
collection_path_without_auth(*args).concat("?auth_token=#{self.api_key}")
end
end
def self.included(base)
base.class_eval do
extend ClassMethods
class << self
alias_method_chain :element_path, :auth
alias_method_chain :new_element_path, :auth
alias_method_chain :collection_path, :auth
attr_accessor :api_key
end
end
end
end
end
end
in model
class Post < ActiveResource::Base
include ActiveResource::Extend::AuthWithApi
self.site = "http://application.localhost.com:3000/"
self.format = :json
self.api_key = 'jCxKPj8wJJdOnQJB8ERy'
schema do
string :title
string :content
end
end
I recently was faced with a similar issue, if you are on Rails3, it supports using custom header which makes life much easier for these situations.
On the side you are making the request from, add
headers['app_key'] = 'Your_App_Key'
to the class you are inheriting from ActiveResource::Base
On you are server, for Authentication, simply receive it as
request.headers['HTTP_APP_KEY']
For Example:
class Magic < ActiveResource::Base
headers['app_key'] = 'Your_App_Key'
end
now Magic.get, Magic.find, Magic.post will all send the app_key
Use model#prefix_options which is a hash for passing params into query string (or even as substitions for parts of the Model.prefix, e.g. "/myresource/:param/" will be replaced by the value of prefix_options[:param] . Any hash keys not found in the prefix will be added to the query string, which is what we want in your case).
class Model < ActiveResource::Base
class << self
attr_accessor :api_key
end
def save
prefix_options[:api_key] = self.class.api_key
super
end
end
Model.site = 'http://yoursite/'
Model.api_key = 'xyz123'
m = Model.new(:field_1 => 'value 1')
# hits http://yoursite:80/models.xml?api_key=xyz123
m.save
An Active Resource currently has no good way of passing an api key to the remote service. Passing api_key as a parameter will add it to the objects attributes on the remote service, I assume that this is not the behaviour you'd except. It certainly wasn't the behaviour I needed
Based on Joel Azemar's answer, but I had to make some changes.. First of all, in the active resource gem I used (2.3.8), there is no 'new_element_path', so aliasing that obviously failed.. Second, I updated the way the token is added to the query, because as was, it would break as soon as you add more params yourself. E.g. request for http://example.com/api/v1/clients.xml?vat=0123456789?token=xEIx6fBsxy6sKLJMPVM4 (notice ?token= i.o. &token=)
Here's my updated snippet auth_with_api.rb;
module ActiveResource #:nodoc:
module Extend
module AuthWithApi
module ClassMethods
def element_path_with_auth(id, prefix_options = {}, query_options = nil)
query_options.merge!({:token => self.api_key})
element_path_without_auth(id, prefix_options, query_options)
end
def collection_path_with_auth(prefix_options = {}, query_options = nil)
query_options.merge!({:token => self.api_key})
collection_path_without_auth(prefix_options, query_options)
end
end
def self.included(base)
base.class_eval do
extend ClassMethods
class << self
alias_method_chain :element_path, :auth
# alias_method_chain :new_element_path, :auth
alias_method_chain :collection_path, :auth
attr_accessor :api_key
end
end
end
end
end
end