9

Active Resource can make use of HTTP authentication set at the class level. For instance:

class Resource < ActiveResource::Base
end

Resource.user = 'user'
Resource.password = 'password'

or

Resource.site = "http://user:password@site.com/"

But what if I use different HTTP authentication based on which user is logged in? If I change Resource.user and Resource.password, is that going to cause a race condition where requests from one thread suddenly start using the authentication of a user whose requests are running simultaneously in a different thread? Or is this a non-issue (as long as I reset the authentication between requests) because rails servers are not multithreaded?

Even if there's no thread safety problem, it still seems risky that if I fail to reset them, the previous user's credentials will be used automatically by future requests.

Update: After being frustrated with ActiveResource, I wrote my own REST library: https://github.com/DeepWebTechnologies/well_rested

Nick Urban
  • 3,568
  • 2
  • 22
  • 36

2 Answers2

7

Monkey patch the host, user and password methods of ActiveResource::Base class:

class ActiveResource::Base
  # store the attribute value in a thread local variable
  class << self
    %w(host user password).each do |attr|               

      define_method(attr) do
        Thread.current["active_resource.#{attr}"]
      end

      define_method("#{attr}=") do |val|
        Thread.current["active_resource.#{attr}"] = val
      end
    end
  end
end

Now set the credentials in every request

class ApplicationController < ActionController::Base

  around_filter :set_api_credentials

private 

  # set the credentials in every request
  def set_api_credentials
    ActiveResource::Base.host, 
      ActiveResource::Base.user, 
        ActiveResource::Base.password = current_user_credentials
    yield
  ensure
    ActiveResource::Base.host = 
      ActiveResource::Base.user = 
        ActiveResource::Base.password = nil
  end

  DEFAULT_HOST, DEFAULT_USER, DEFAULT_PASSWORD= [
    "http://www.foo.com", "user1", "user78102" ]

  def current_user_credentials
    current_user.present? ? 
      [ current_user.host, current_user.login, current_user.password] : 
      [ DEFAULT_HOST, DEFAULT_USER, DEFAULT_PASSWORD]
  end

end
Harish Shetty
  • 64,083
  • 21
  • 152
  • 198
  • 1
    Does this mean that yes, it does cause a race condition? Or is this just a precaution? – Nick Urban Nov 11 '11 at 16:34
  • Yes it does, in production mode you can run in to race condition if you want to change the connection parameter per request. Using Thread local variable addresses this issue. – Harish Shetty Nov 15 '11 at 04:12
  • I have similar solution for setting `self.site` without race condition problem http://stackoverflow.com/questions/8623204/set-site-user-fields-in-activeresource/9053643#9053643 – troex Jan 29 '12 at 13:51
  • I have updated the answer to work in webservers such as `thin` and `puma`. – Harish Shetty Apr 24 '13 at 03:34
2

As of Active Resource 4.1.0, those settings are thread local, so this example would not cause a race condition anymore.

This is the relevant commit: https://github.com/rails/activeresource/commit/538588ddba9ffc9bf356790e9186dc7e6adad12f

stefanlindbohm
  • 343
  • 3
  • 9