将api密钥添加到ActiveResource中的每个请求

时间:2010-05-27 04:16:59

标签: ruby-on-rails ruby ruby-on-rails-3 activeresource

我有2个RESTful Rails应用程序,我正试图互相交谈。两者都是用Rails 3编写的(目前是beta3)。对服务的请求将需要使用api密钥,这只是每个请求都需要的参数。我似乎无法找到有关如何执行此操作的任何信息。

您可以通过site =方法定义资源连接到的网址。应该有一个等效的query_params =方法或类似方法。

我发现有一篇很好的博客文章与此有关,而且是从2008年10月开始,因此对Rails 3来说并不完全有用。

更新:我有个想法。小型机架中间件或金属是否可以解决这个问题?它可以通过请求,将其添加到api_key上。

7 个答案:

答案 0 :(得分:21)

使用model#prefix_options这是一个散列,用于将params传递给查询字符串(甚至作为Model.prefix部分的子目录,例如“/ myresource /:param /”将被prefix_options [:param]的值替换在前缀中找不到的任何哈希键都会被添加到查询字符串中,这就是我们想要的情况。)

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

答案 1 :(得分:10)

我最近遇到过类似的问题,如果您使用的是Rails3,它支持使用自定义标题,这可以让这些情况更轻松。

在您提出请求的一边,添加

headers['app_key'] = 'Your_App_Key'

到您从ActiveResource :: Base

继承的类

在您是服务器上,对于身份验证,只需将其作为

接收

request.headers['HTTP_APP_KEY']

例如:

class Magic < ActiveResource::Base
    headers['app_key'] = 'Your_App_Key'
end

现在Magic.get,Magic.find,Magic.post都将发送app_key

答案 2 :(得分:4)

我有更好的解决方案!我在中间件中尝试使用Rack,但我没有找到任何解决方案....

我建议您使用此模块来覆盖ActiveReouse :: Base

的方法

在/ lib / active_resource / extend /目录中添加此lib不要忘记取消注释 config / application.rb

中的“config.autoload_paths + =%W(#{config.root} / lib)”
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

在模型中

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

答案 3 :(得分:3)

基于Joel Azemar的回答,但我不得不做出一些改变...... 首先,在我使用的活动资源gem(2.3.8)中,没有&#39; new_element_path&#39;,所以显然失败的别名.. 其次,我更新了令牌添加到查询的方式,因为它会在您自己添加更多参数时立即中断。例如。请求http://example.com/api/v1/clients.xml?vat=0123456789?token=xEIx6fBsxy6sKLJMPVM4(通知?token = i.o.&amp; token =)

这是我更新的代码段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

答案 4 :(得分:2)

Active Resource目前没有将api密钥传递给远程服务的好方法。将api_key作为参数传递将其添加到远程服务上的对象属性中,我假设这不是您的行为。这当然不是我需要的行为

答案 5 :(得分:2)

我建议你有一个继承自ActiveResource::Base的基类,并覆盖self.collection_pathself.element_path类方法,以便始终注入API KEY,如:

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

这将始终在您的ActiveResource方法调用中注入您的API_KEY。

答案 6 :(得分:1)

活动资源对象的行为很像(简化的)Active Record对象。 如果您希望传递新参数,则可以通过将其添加为属性在AR对象上进行设置。例如:

jane = Person.create(:first => 'Jane', :last => 'Doe', :api_key => THE_API_KEY)

它应该将api_key作为参数传递给所有其他参数。