5 Tips for ActiveResource

posted by andy, Thu Apr 24 16:30:00 UTC 2008

The first couple of tips have an indrect impact on ActiveResource. Still, they are worth keeping in mind because they simplify the data with which ActiveResource deals.

Tip 1: Use delegate and :method for encapsulation

If your crash course in Ruby involved reading the Agile book, then the delegate method may be new to you. Delegate is a class-level command that allows you to pass certain method calls on to an associated model. For example, if you have a highly-factored address book you might have a pair of models like this:

class Address < ActiveRecord::Base
  belongs_to :zip_code
end

class ZipCode < ActiveRecord::Base
  has_many :addresses
end

That's a model with some theoretical purity... but in practice it's cumbersome. You really want to deal with an address that has all the information you'd like to render (street, city, state, zip) in on model. Atleast it should feel that way. That's precisely where the delegate command comes into play.

class Address < ActiveRecord::Base
  belongs_to :zip_code
  delegate :city, :state, :zip, :to=>:zip_code
  delegate 'city=', 'state=', 'zip=', :to=>:zip_code
end

Modeled as shown above you can ask an address for it's city and the address will pass the request on to the zip_code object to which it belongs, retrieve the answer, and return it to you. (It's taking advantage of the fact that Rails is doing some method_missing magic to provide getters and setters for your attributes). That level of encapsulation will become increasingly important when you begin to use ActiveResource heavily. In many cases you may want to return only a few fields from an associated model and, as in the example above, you do not want or need to reveal how you've organized your data to the outside world.

The final piece to the puzzle with respect to ActiveResource will be making sure you use the :method parameter when you serialize the delegating object to xml.

addresses_controler.rb

...
def show
  @address = Address.find(params[:id], :include=>:zip_code)
  respond_to do |format|
    format.html # show.html.erb
    format.xml  { render :xml => @address.to_xml(:methods=>[:city, :state, :zip])
  end
end
...

As shown, the call to @address.to_xml tries to include the results of calling the city, state, and zip getter methods on address. The delegate command causes the Address object to pass that request on to the association ZipCode object and the results are returned and placed into the xml envelope as if they were attributes of the address (which they are, indirectly). The application that's consuming all this through ActiveResource remains blissfully unaware of your modeling nirvana. It simply receives some nicely formatted xml along the lines of this:

<home-address>
  <id type="integer">1</id>
  <street>123 Main St.</street>
  <city>Anytown</city>
  <state>XX</state>
  <zip>12345</zip>
</home-address>

Tip 2: Clean up the delgation you just learned to keep the code clean and clear

If you start maximizing your use of delegate your code can get untidy especially since delegate introduces some duplication when you're dealing with attribute accessors. If we keep in mind that class declarations are still Ruby scripts then we can clean the attribute accessor delegation pretty easily while making the intent very clear.

class Address < ActiveRecord::Base
  belongs_to :zip_code
  [:city, :state, :zip].each do |delegated_accessor|
    delegate "#{delegated_accessor}", "#{delegated_accessor}=", :to=>:zip_code
  end
end

On to some tips with more direct bearing on ActiveResource itself.

Tip 3: Use AppConfig to get your site information out of the class file!

The Core did a great job modeling ActiceResource along the lines of ActiveRecord so that using ActiveResource feels very natural to any Rails programmer. But it's also left me stumped as to why there is no equivalent to /config/databases.yml. I suppose that in some cases you will be using a well-known, established, public REST interface but I'm finding ActiveResource to be a very natural way to develop 'sub-applications' that can be shared to create a larger application. Because of that I need to be able to have different site information for development, test, and production. Clearly some configuration is needed.

Even though I shudder at the thoughts that a name like 'AppConfig' brings to mind, it's a great part of the solution to this problem. If you're not familiar with it, AppConfig allows you to provide a yaml config files for global (/config/app_config.yml) and environment-specific (e.g., /config/environments/development.yml) configuration. The plugin reads these config files, merges inforamtion as necessary, and provides all the options as class-level attributes of the AppConfig class.

sites:
  addressbook: http://localhost:3001
  financials: 
    url: http://localhost:3002
    username: money
    password: talks

The yaml above shows two different types of configuration that would be useful for ActiveResource, organized together under a 'sites' attribute. The first one (addressbook) is the way I started before I ran into an application that needed http basic authentication. The site info consists only of the url. The second one (financials) came out of the latter need. A quick extension of ActiveResource causes these to spring into action.

class ActiveResource::Base
  protected
  def self.establish_site_connection(site_id)
    raise(ArgumentError, "#{site_id} is not defined for #{RAILS_ENV}") unless AppConfig.sites.respond_to?(site_id)
    site_info = AppConfig.sites.send(site_id)
    return site_info.respond_to?(:url) ? site_with_basic_auth_info(site_info) : site_info
  end
  
  def self.site_with_basic_auth_info(site_info)
    site = URI.parse(site_info.url)
    site.userinfo = "#{site_info.username}:#{site_info.password}"
    return site.to_s
  end
end

I've been dropping the code above into /lib/core_ext/active_resource_extension.rb. The first method (establish_site_connection) is meant to emulate ActiveRecord::Base#establish_database_connection. It accepts a site id in the form of a symbol or string and retrieves the site configuration matching that id. If that site info is already a simple string, that string is returned unmodified. If the site_info is further broken down into the url, user name and password for http basic authentication then that is handed off to the site_with_basic_auth_info method to build up a simple string.

It's true that the http basic authentication credentials could be written into the url. In fact, that's exactly what the site_with_basic_auth_info does. If that's the case, then why add the username and password to the config file?

Tip 4: Share your site AppConfig settings between your applications

When you have the fortunate advantage of controlling both your ActiveResource-based application and your ActiveRecord-based application you can share the configuration information between the applications. Specifically, you can share the username and password information used for http basic authentication so that both sides can be externally configured... and reconfigured. By sharing the configuration files and including the use of AppConfig in the source application for the ActiveResource your http basic authentication will be as simple as

def basically_authenticated(user, password)
  user==AppConfig.sites.financials.username && password==AppConfig.sites.financials.password
end

What makes this even more compelling is that AppConfig (as anything leaning on yaml) allows you to use ERb in your configuration files. Why is that significant?

Tip 5: Use Embedded Ruby in your configuration files to automatically change your user/password

Clearly with http basic authentication you will want to go the extra step of passing through a secure connection, but if you're too tired to add an 's' to your http, then you'll want to change your clear-text password. Often. Embedding Ruby might be just the trick because you could share a single algorithm between your applications that would change the password for you.

sites:
  addressbook: http://localhost:3001
  financials: 
    url: http://localhost:3002
    username: <%= %w{money cash penny moulah dineiros pennywise poundfoolish}[Date.today.wday] %>
    password: <%= Digest::SHA1.hexdigest("#{Date.today.to_s}---financials") %>

There is a potential pitfall here. With this type of approach -- shifting the user/password each day -- the application servers will have to be kept in step. A reboot on one machine will require a reboot or restart on the other to make sure the applications share the same username/password since the AppConfig object will be re-loaded when the webserver starts. Pick the scheme that works best for you.

Filed Under: Rails | Tags:

Comments

  1. pusnuvi 05.15.08 / 07AM
    kF0Y1E xsrfihdfpmac, [url=http://ajywozcaclzu.com/]ajywozcaclzu[/url], [link=http://aljoyuadgchb.com/]aljoyuadgchb[/link], http://ibtvvhbvilwe.com/
  2. scuko301 05.18.08 / 14PM
  3. scuko78 05.20.08 / 04AM
  4. assan162 05.20.08 / 20PM
    a , cialis on line, buy cheap acomplia online,, antidepressants, tramadol online rx, viagra no prescription, buy cialis online, order ultram, buy kamagra, acomplia buy best, tramadol 200 pills online,, order levitra, buy 150 tramadol tablets, where can i buy tramadol, get rx for tramadol online,, ultram 50mg, buy namebrand tramadol, order prozac online 40 mg, viagra cheap, tramadol 200 pills online, order prozac online 40 mg, tramadol online lowest price, pfizer zoloft, prozac price from on line pharmacy, viagra by mail, medication online soma, cheap kamagra, levitra 20mg, cheapest online cost for levitra, codeine tramadol online without presciption, propecia, viagra on line, generic levitra, generic cialis, propecia pills, no prescription cialis, propecia drug, tramadol online, prozac purchase online, cheap viagra, online viagra, buy ultram, cialis viagra, cheapest cialis, buy tramadol with discount, cheap tramadol no prescription, levitra viagra vs, soma online consult,, rx tramadol online, buy kamagra online, buy cialis online, generic levitra, acomplia online generi, buy viagra cheap, buy prozac online, ultram,, non perscription generic cialis, buy acomplia online, tramadol online ups delivery, buy tramadol without priscription, buy cheap rimonabant online, generic ultram, online drugstore tramadol, tramadol no doctor, where to buy viagra, discount cialis, rimonabant acomplia side effects, generic prozac, viagra pills, tramadol pills online, order viagra, ordering viagra,, rimonabant acomplia side effects, how to buy tramadol, buy rimonabant, prozac purchase online, cialis tadalafil, soma carisoprodol,, viagra without a prescription, acomplia usa pharmacy, viagra online, buy cialis viagra, soma carisoprodol,, cheap soma,
  5. assan110 05.22.08 / 11AM
    a , order propecia online, cheap viagra, viagra online, buy tramadol, buy acomplia online,, cialis on line, generic prozac, purchase zimulti, cheap tramadol no prescription, purchase kamagra, rimonabant acomplia side effects, prozac purchase online, buy propecia online, discount cialis, cheap viagra, discount cialis, buy viagra cheap, cialis levitra viagra, buy tramadol online, order viagra, does propecia work, buy viagra, tramadol online in florida,, prozac side effects,, shop pharmacy for soma, propecia drug, zoloft, pain pill ultram, does propecia work, viagra prices,, cheapest online cost for levitra, buy check e tramadol, tramadol prescription, pain pills ultram, prozac side effects, cialis tadalafil, tramadol 200 pills online, online viagra, prozac online sales,, tramadol pills online, cheap kamagra, ultram pain pill, generic ultram, buy soma cheap, buy prozac online, alternatives to viagra,, buy prozac online, levitra vardenafil, buy tramadol without, generic cialis online, acomplia no prescription, 10 mg generic prozac without prescription, online tramadol usa, soma, buy pills tramadol, online cialis, ultram pain killers, ordering viagra, pfizer zoloft, ordering viagra, levitra online, order soma, prozac price from on line pharmacy, get rx for tramadol online, levitra online, tramadol on line pharmacy, zoloft medication, tramadol prescription, where can i buy tramadol, buy prozac 40mg online, buy acomplia online, pain pills ultram, buy namebrand tramadol, zoloft depression, buy cheap acomplia, tramadol 50mg,, best tramadol online, generic ultram, soma online,
  6. assan38 05.23.08 / 07AM
  7. assan217 05.23.08 / 23PM
    a , purchase levitra online, buy pfizer viagra, propecia, propecia, tramadol online, cheap cialis, acomplia, buy viagra now, prednisone online, buying soma, viagra without a prescription, cheap ultram, buy cialis online, cialis generic, tramadol, levitra, levitra pills, buy propecia, generic viagra, generic soma,, cialis on line, rimonabant diet pill, purchase cheap tramadol,, buy soma, buy cheap acomplia online, buy soma, where to buy soma,, buy rimonabant, cialis levitra viagra, buy propecia online, buy generic viagra, cheapest cialis, order soma, prednisone online, levitra, viagra and levitra, buying viagra,, buy acomplia online, generic levitra, purchase cheap tramadol, buy augmentin now, generic prozac,, buy augmentin now, prednisone, buy zoloft, generic soma,, acomplia, buy viagra online, buy viagra, buy cheap rimonabant, buy cialis, tramadol, soma, generic levitra, buy viagra online, purchase soma, buy prozac online, cheap viagra, levitra, zoloft,, buy augmentin, cialis levitra viagra, cialis, purchase tramadol, buy tramadol online, buy zoloft online,, acomplia weight loss drug, purchase prednisone, buy cialis online, buy acomplia, order tramadol online, tramadol online, online tramadol, cheap ultram, generic cialis, purchase cheap levitra, cheap generic cialis, order tramadol online,, ultram, buy prozac, buy propecia online, buy rimonabant online, buy viagra, viagra tablets, cheap viagra, buy soma cheap, order tramadol online, buy ultram, generic levitra, cialis generic, levitra, rimonabant diet pill,, levitra online, buy propecia online, discount cialis, cheap ultram, buy augmentin now,, cheap augmentin,, cheap ultram online , online tramadol,, buy acomplia, buying soma, rimonabant diet pill, buy viagra online, cheap levitra online , buy propecia, buy soma online, viagra without a prescription, cialis levitra viagra, buy rimonabant online, ordering viagra,, cialis on line, cheapest cialis, cheap ultram online , tramadol hcl, ultram 50mg,, generic viagra, order cialis, cialis,