Add api key to every request in ActiveResource

2019-02-05 19:48发布

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 api key which is just a param that needs to be on every request. I can't seem to find any information on how to do this.

You define the url the resource connects to via the site= method. There should be an equivalent query_params= method or similar.

There is one good blog post I found related to this and it's from October 2008, so not exactly useful for Rails 3.

Update: I had a thought. Would a small Rack middleware or Metal be the answer to this? It could just pass through the request, tacking it's api_key on.

7条回答
ら.Afraid
2楼-- · 2019-02-05 20:21

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.

查看更多
祖国的老花朵
3楼-- · 2019-02-05 20:29

I'd recommend that you have a base class inheriting from ActiveResource::Base and override the self.collection_path and self.element_path class methods to always inject the API KEY something like:

class Base < ActiveResource::Base
  def self.collection_path(prefix_options = {}, query_options = {})
   super(prefix_options, query_options.merge(api_key: THE_API_KEY))
  end

  def self.element_path(id, prefix_options = {}, query_options = {})
    super(id, prefix_options, query_options.merge(api_key: THE_API_KEY))
  end
end

class User < Base; end

User.all # GET /users/?api_key=THE_API_KEY

This will always inject your API_KEY in your ActiveResource method calls.

查看更多
男人必须洒脱
4楼-- · 2019-02-05 20:30

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

查看更多
啃猪蹄的小仙女
5楼-- · 2019-02-05 20:31

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

查看更多
三岁会撩人
6楼-- · 2019-02-05 20:34

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
查看更多
Explosion°爆炸
7楼-- · 2019-02-05 20:36

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
查看更多
登录 后发表回答