What's New in Edge Rails: The Ins and Outs of ActiveResource

Posted by ryan
at 9:58 AM on Friday, June 30, 2006



See here from some syntactical changes that occurred after this post was published

Following the tail of David Heinemeier Hansson’s much talked about RailsConf keynote speech comes the addition of the ActiveResource library to edge Rails. What’s all the hype about? Well, I’ll let you read David’s post for the lowdown, then I’ll try to do some justice to the concept….. Done reading? If you were too lazy let me give you the one line summary: CRUD is great because it’s consistent, simple, expressive and foundational. Every application should be built solely on CRUD operations – and Rails is going to help you construct such applications.. Great, let’s carry on.

If you haven’t noticed, it appears that the next version of Rails will whole heartedly embrace the RESTful model of application development. Not only was it the topic of David’s keynote speech, but we’ve seen a lot of updates into edge rails that support the various aspects of RESTful calls (for instance we’ve seen REST support in the various link helpers and the ability to populate a Hash directly from XML). REST is a great companion to the RAILs style of simple, expressive application development.

for those that need a quick primer on REST, see the bottom part of this post

ActiveResource provides a large piece of the REST puzzle by basically implementing the client side of a RESTful system – the parts of a decoupled system that consume RESTful services. At its essence, ActiveResource provides a way to utilize model objects as REST-based client proxies to remote services. Ok, sounds impressive, but what does this mean?

Let’s look at an example of a typical find call on a Person model object:


Person.find(1).name #=> "Ryan"

Doesn’t appear to be anything out of the ordinary going on here – except that under the covers it’s not a database SELECT that’s occuring. Instead, if the Person model is an Active Resource, this find call is actually sending an HTTP GET request across the wire to a RESTful service:

GET http://api.myremote.com/people/1
<= Ryan

See how an XML response comes back from the GET request? That XML is automatically transformed for us behind the scenes into a Person object. (Hmmm, now that Hash.create_from_xml addition we saw come across in edge rails a few days ago makes sense.. ). There’s a lot of power in that – transparently making a remote call (based on REST principles) simply by using the same methods you’re used to using with Active Record.

What about creating or deleting? Same thing:


Person.new(:name => "Ryan").save

HTTP request:

POST http://api.myremote.com/people
=> Ryan
<= Location: http://api.myremote.com/people/1

With the create, a POST HTTP request is made and an XML document is submitted as the request in the format we saw come across before – the XML structure of the Person object with its values. The return value is the URL that represents where that resource now lives (from which the id of the new person can be parsed). Note: this create functionality of ActiveResource is not yet committed to edge rails, it’s been deduced from various other resources and presentations

Deletes just return a 200 status code when successful (note there’s not yet a Person.destroy(id) class method like in ActiveRecord – you have to get the item first).


Person.find(1).destroy

HTTP request:

DELETE http://api.myremote.com/people/1
<= Status: 200

To be clear, ActiveResource is not meant to replace ActiveRecord in your controllers since that would involve an unecessary trip across the wire. However, when building APIs and de-coupled services, Active Resource makes perfect, painlessly simple sense in the consumption of such services. To implement the Active Resource client proxy, all you have to do is the extend ActiveResource:Struct and point to the remote URL:

1
2
3
4
Person = ActiveResource::Struct.new do |person|
  person.uri = "http://api.myremote.com/people"
  person.credentials :name => "me", :password => "password"
end

From this simple setup ActiveResource will now perform the following on each individual operation:

Model request Http REST operation request body Request URI Response
find(id)GETN/A/people/id.xml
1
2
3
<person>
  <name>name</name>
</person>
save (update)PUT
1
2
3
<person>
  <name>name</name>
</person>
/people/id.xmlStatus: 200 OK
save (create)POST
1
2
3
<person>
  <name>name</name>
</person>
/peopleLocation: http://x/people/id.xml
destroyDELETEN/A/people/id.xmlStatus: 200 OK
listGETN/A/people
1
2
3
4
5
<people>
  <person>
    <name>name</name>
  </person>
</people>


So we know how ActiveResource abstracts the calling of REST services from the client side, but how do we implement those RESTful services? I suspect you’re going to see the server side components flowing into edge rails for the 1.2 release, but there are already a few plugins that provide that functionality.


What is REST?

REST is the request and manipulation of web-accessible resources through the use of standard HTTP request methods (GET, POST, PUT, DELETE). REST is based on the notion that the individual HTTP methods represent the type of action to take (the verb) and the URI is the location of the resource to act upon (the noun). Using this paradigm, the same URL can be used to perform different actions. For instance, if I wanted to get the person with id 1, I might make this call:

GET: /person/1

And if I wanted to delete that person, I would call the same URL with a different request type:

DELETE: /person/1

There you go, the noun is the URL representing a single resource, and the action to perform is the type of request. No longer do we need different URLs for every system action. One url, many actions. Powerful and concise.

Saying it in a slightly different way, REST is the invocation of an atomic, CRUD-based operation on a web accessible resources by the appropriate HTTP method instead of the URL of the request.

HTTP has several types, or methods, of making a request. We’re all familiar with GET, used to fetch a resource or URL, and POST which is most often used to submit form data. However, there are also the PUT and DELETE methods of requests (among others) that largely go unused. The whole idea behind REST is to properly synchronize the intent of the request with the method of the request.

It’s not uncommon to see the following URL to delete an item: http://url/people/delete?id=1. Somebody requests that URL and the resource is deleted from the server. But, this represents a break between the effect of the request and the type of request. When a browser or application requests that URL (via a GET), a deletion occurs within the system. How a deletion should be requested is with the HTTP DELETE method. That way the method of the request (DELETE) matches the effect of the request (something is deleted). There are similar mappings between every REST action and the basic CRUD operations:

CRUD operation REST method
Create POST
Read GET
Update PUT
Delete DELETE

You will often see REST and CRUD being compared as they mirror one another – REST is how CRUD operations are invoked in an HTTP-networked environment.

References:

tags: rails, rubyonrails, active resource

Rails v1.1.4 Released

Posted by ryan
at 3:20 AM on Friday, June 30, 2006



Rails v1.1.4 is now out, fast on the heels of the Rails v1.1.3 security fix.

official announcement

tags: rails, rubyonrails

What's New in Edge Rails: Some Handy Enumerable helpers

Posted by ryan
at 10:17 AM on Tuesday, June 27, 2006



Enumerable has received a few handy little extensions in edge Rails. The first is the ability to sum the contents of the enumerable:

orders.sum { |o| o.total * discount }

or

orders.sum(&:total)

For those interested in the implemention, it’s pretty straight forward:

def sum
  inject(0) { |sum, element| sum + yield(element) }
end

And next we have index_by which will convert an enumerable to a hash keyed on the given block. This is definitely best explained with an example. Suppose we have an array of City objects that we want to convert to a hash based on the city names:

hash = cities.index_by(&:name)
hash #=> ["New York" => <City ...>, "London" => <City ...>]

We now have a hash of cities keyed on the citys’ names.

For those that aren’t familiar with the &:symbol syntax used as a parameter to these methods – it’s just a way to form a block that says get the value of the this symbol on the passed in object.

So in the case of:

orders.sum(&:total)

what we’re really saying is:

orders.sum { |o| o.total }

It’s just a nice shortcut to access the value of a single property.

tags: rails, rubyonrails

What's New in Edge Rails: Pessimistic Locking

Posted by ryan
at 9:03 AM on Tuesday, June 27, 2006



Tim Lucas over at SitePoint already talked about this feature and has added good detailed explanation in the comments.

Rails has long provided optimistic locking through the use of its lock_version magic column. In a natural compliment to that functionality, edge rails now also provides pessimistic locking support:

http://dev.rubyonrails.org/changeset/4460 http://dev.rubyonrails.org/changeset/4461 http://dev.rubyonrails.org/changeset/4462

Pessimistic locking is specified with the lock option in your standard find method:

Person.transaction do
  p = Person.find(1, :lock=> true)
  p.username = 'new'
  p.save!
end

This will lock the person row during the course of the specified transaction and prevent updates from occuring while the object is manipulated.

You can also lock an already loaded model with the new lock! method:

person.lock!

which is equivalent to:

person.reload(:lock => true)

Optimistic vs. Pessimistic Locking


With optimistic locking a check is done on the lock_version column by the Rails framework when a row is updated to make sure that it has the same value as when the model was first read from the database. If the lock_version has changed while the object has been in memory we assume that it’s been updated underneath us and a ActiveRecord::StaleObjectError is thrown. This is easily implemented by appending a WHERE lock_version = X clause to the update SQL. If no rows are updated it means the lock_version has changed. The important thing to note here is that this protection is provided at the application level.

Pessimistic locking is functionality provided by the database that happens at the database level. When invoked it actually locks the row(s) in question so that other update requests are blocked. This is usually done with the FOR UPDATE SQL clause. The benefit of this is that you have an exclusive lock on that row so no other operations can occur and you are guaranteed the data will not change. However, this is also the big downside – everybody else is blocked! You would never want to obtain an exclusive lock on a row and then either forget about it or have it locked for an extended amount of time. When another part of your application wants to update that data no errors will be raised, it will just hang. Nasty. Basically, don’t use pessimistic locking unless you know what you’re doing and have a reliable way of releasing the lock.

tags: rails, rubyonrails, locking, optimistic locking, pessimistic locking

What's New in Edge Rails: Rails v1.1.3 Release Fast Approaching

Posted by ryan
at 8:07 AM on Tuesday, June 27, 2006



Looks like Rails v1.1.3 is almost here (after this false alarm saturday.)

I’ll try to wrap up the changes between 1.1.2 and 1.1.3 in another post when it’s official.

Looks like it’s just some small security fixes – so not much to detail here…

tags: rails, rubyonrails

What's New in Edge Rails: Create a Hash from XML

Posted by ryan
at 6:13 AM on Tuesday, June 27, 2006



Hash has been extended to provide the ability to create a new hash from an xml string. While this is now used internally by Rails to handle XML requests, it’s also available for use as you see fit.

The basic premise is that XML is mostly a nested set of key => value pairs which is pretty much what a hash is. Population and creation of a hash from an XML structure makes perfect sense and can simplify your use of XML.

What happens when you call Hash.create_from_xml(xml) is that each xml element gets set as a key in the hash and the value of that element is stored as the value in the hash (with typecasting).

For instance, this:

Hash.create_from_xml <<EOX
<user>
  <id type="integer">1</id>
  <user-name>ryan</user-name>
</user> 
EOX

gets you this hash:

{ :user => { :id => 1, :user_name => "ryan" } }

Notice how the integer value of the id was actually cast as an integer. Also note how element names such as user-name get modified into the Ruby form user_name. Collections of more than one item are handled pretty intuitively as well – being stored as an array of hashes:

hash = Hash.create_from_xml <<EOX
<users>
  <user>
    <id type="integer">1</id>
    <user-name>ryan</user-name>
  </user> 
  <user>
    <id type="integer">2</id>
    <user-name>doug</user-name>
  </user>
</users>
EOX

hash[:users] #=> {:user => [ { :id => 1, :user_name => "ryan" },
                             { :id => 2, :user_name => "doug" } ] }

hash[:users][:user].last #=> { :id => 2, :user_name => "doug" }

All in all just a really easy way to process XML.

tags: rails, rubyonrails, xml

What's New in Edge Rails: find_or_initialize_by_...

Posted by ryan
at 4:58 PM on Monday, June 26, 2006



Parallel to the find_or_create_by_X method that will find the requested model if it exists or create it and return it if it doesn’t is the new find_or_initialize_by_X which will find the requested model or create, but not save it, if it doesn’t exist.

The associated unit tests show us that an object initialized by this method is not yet saved to the database whereas the create version is:

assert Company.find_or_initialize_by_name("38signals").new_record?

assert !Company.find_or_create_by_name("38signals").new_record?

tags: rails, rubyonrails

What's New in Edge Rails: Mongrel Support 5

Posted by ryan
at 4:26 PM on Monday, June 26, 2006



The script/server startup script that boots either WEBrick or Lighttpd has gotten an update that will now start mongrel if it detects it on your system.

If you have both lighty and mongrel installed then the script will startup lighty mongrel, and of course WEBrick is the fall back if nothing else is available.

As usual, you can force startup of a specific server by passing it in on the command line:

script/server mongrel or script/server lighttpd

Looks like mongrel’s quick rise to prominence continues with the official backing of Rails…

tags: rails, rubyonrails, mongrel

Rails, Mac Minis and Mackerels

Posted by ryan
at 4:15 PM on Wednesday, June 14, 2006



It’s a pleasure to work with such nature lovers, philanthropists and all around Rails supporters. It almost makes up for the wierdness.

Rails 1.2 Preview?

Posted by ryan
at 11:47 AM on Wednesday, June 14, 2006



Apparently, our friends over at Slingshot have super-secret access to that elusive worm-hole and have procured Rails v1.2!! Last I checked, 1.2 wasn’t quite ready for prime-time yet.

They tell me the acts_as_desired_application plugin is superb!

(Can’t be too hard on them though – they look like a nice replacement for the vapor-company RailsBase, are RailsDay sponsors AND have nice plans!)

tags: rubyonrails,rails,slingshot hosting

Dapper Drake is my Friend. And so is Jim

Posted by ryan
at 5:36 AM on Thursday, June 08, 2006



I’ve been a deb guy for as long as I’ve been using linux as my littany of various howtos can attest. While deb is great I’ve always had to go through a few kernel compiles and what not to get hibernate/suspend and MS VPN support working on my Latitude laptop.

On a tip from my co-worker, Jim, I tried Ubuntu’s latest offering, Dapper Drake.

Wow

An effortless install with full serial IDE support, suspend, hibernate, MS VPN, a stable gnome WM – you name it. I am really impressed.

Check it out

tags: ubuntu,debian

Installing the ExceptionNotifier Plugin 8

Posted by ryan
at 4:11 PM on Wednesday, June 07, 2006



Use

ruby script/plugin install exception_notification

to install Jamis Buck’s handy plugin.

I write this only because I spent 5 minutes trying ExceptionNotifier, exception_notifier and variants thereof before realizing exception_notification is the magic word. Yeah, I now realize it’s the directory name as it exists in subversion, but my mind wasn’t quite there 5 minutes ago.

Maybe this will save somebody 5 minutes of their own time.

Or maybe you will mock me.

You Can Have Your Tada List - I'll Take the Milk

Posted by ryan
at 6:32 AM on Wednesday, June 07, 2006



All you 37 Signals fan-boys can have your tada list – the truth of the matter is that Remember the Milk has it beat in every possible way. Simplicity doesn’t mean the dearth of features – it means presenting essential features in a concise and intuitive manner. Tada list simply removes features. No due dates, no priorities? – that’s not of much use to me.

tags: tadalist, rememberthemilk, todos

What's New in Edge Rails: Convenient Finder Parameter Hashes

Posted by ryan
at 5:30 PM on Tuesday, June 06, 2006



There’s now a convenient way to call Active Record finder methods when the query is based solely on AND ed equality conditions.

Before:

Article.find(:all, :conditions => [ "author_id = ? and status = ?", @author.id, 'published' ], :limit => 10)

Now:

Article.find(:all, :conditions => { :author_id => @author.id, :status => 'published' }, :limit => 10)

Instead of having to finagle with the SQL string and the correct number of ? placeholders – we can now just pass in the hash of parameters which will be AND ed together to form the SQL query.

Ahh, that’s nice.

tags: rubyonrails, rails

What's New in Edge Rails: Cleaning up Your Plugins 0

Posted by ryan
at 5:18 PM on Tuesday, June 06, 2006



Changesets 4427 and 4440 provide an uninstall hook for plugins. Previously, all that was done when a plugin was uninstalled via ruby script/plugin remove plugin_name was that the plugin directory was deleted.

Now, Rails allows plugin developers to do specific cleanup tasks on uninstall by providing an uninstall hook. This is useful when the plugin provides specific CSS, view or DB resources that can be safely removed when the plugin is uninstalled.

All plugins need to do is provide an uninstall.rb file in the plugin directory (similar to the standard init.rb install file) with the teardown logic specific to that plugin. The plugin template now provides a uninstall.rb file too, so everything is in place for the plugin to properly clean up after itself.

tags: rubyonrails, rails, plugins

Changing PostgreSQL's Data Directory in Ubuntu

Posted by ryan
at 4:46 PM on Tuesday, June 06, 2006



When installing PostgreSQL on debian the install process asks you what directory you want to contain your actual table data – which is nice when you want to use a dedicated partition instead of the default /var/lib/postgresql/data. However, in Ubuntu (Dapper Drake and Breezy Badger) the install process doesn’t give you the option of changing the default directory. Here are some quick notes on how to change the data directory to an existing non-default data dir (specifically for postgresql 7.4):

  1. remove the /etc/postgresql/7.4/main/pgdata symlink
  2. create a new pgdata symlink that points to your desired data directory.
  3. Make sure the pg_hba.conf, pg_ident.conf, postgresql.conf and root.crt symlinks in the data dir point back to the originals in /etc/postgresql/7.4/main

Restart postgres and you should now be running from you desired, non-default data directory.

tags: postgresql,postgres,ubuntu

Note to Self: Reloading my Rails App Within the Console 3

Posted by ryan
at 7:14 AM on Friday, June 02, 2006



I’m posting this more as a personal reminder than anything else – so go elsewhere if you’re looking for true wisdom:

How to reload my controllers and model while running in Rails’ handy script/console utility:

reload!

or

Dispatcher.reset_application!

The differences between the two I do not yet know (and now I do – thanks to Curt’s comment – reload! just calls Dispatcher.reset_application!)

References: Caveats:

tags: rubyonrails,rails

Is PlanetRubyOnRails Deprecated?

Posted by ryan
at 6:32 AM on Friday, June 02, 2006



RubyCorner has come along and provided a great service to the Ruby and Rails community by essentially taking over where PlanetRubyOnRails.org has stalled – providing Ruby related feed aggregation. I think this is great and RubyCorner is doing a great job with good functionality lilke favorites, blacklists etc..

However, does this mean that PlanetRubyOnRails is essentially dead? I can’t find anywhere to add or suggest a feed (that works). Maybe you have to be one of the Ruby elite to have a spot on the planet… It would be nice to see the service propped up a little better though – there’s got to be space for two such sites.

rubyonrails,rails,rubycorner,planetrubyonrails

What's New in Edge Rails: Routing Refactored

Posted by ryan
at 10:10 AM on Thursday, June 01, 2006



It would appear that Rails’ routing implementation is being gutted:

though we have been re-assured that the API remains unchanged. Those messing with the routing internals, however, “expect breakage”.

rubyonrails, rails

What's New in Edge Rails: Using Collections of Records as the "IN" SQL Condition

Posted by ryan
at 9:45 AM on Thursday, June 01, 2006



It’s currently somewhat difficult to use the IN SQL condition within ActiveRecord’s finder methods – most solutions I’ve seen involve building your own SQL string or popping back out to the object level and performing more queries than necessary to get around this limitation. Changesets 4391, 4387 and 4390 let you now pass in a collection of ActiveRecord objects as a parameter to the SQL condition that will be expanded to a comma-seperated list of ids.

So, if you have a collection of posts and want to get all comments for those posts, this finder call:

comments = Comment.find(:all, :conditions => ['post_id IN (?)', posts])

Will result in this SQL:

SELECT * FROM COMMENTS WHERE POST_ID IN (1, 2, 3, ..)

Ya jive? You’re now able to pass in a collection of records to your SQL finder methods that will be automatically expanded into a comma-seperated list of ids. This makes it much easier to use the IN (?) SQL condition within ActiveRecord.

Parallel to this functionality is the addition of the Array.to_s(:db) method which does basically the same thing, converts an array of ActiveRecord objects into a comma-seperated list of ids (this is what changeset 4387 adds). This addition makes the following identical to the Comment.find(...) call mentioned earlier:

comments = Comment.find(:all, :conditions => ['post_id IN (?)', posts.to_s(:db)])

Surprisingly, the implementation of the expansion of an ActiveRecord array does not utilize Array.to_s(:db)...

rubyonrails, rails

What's New in Edge Rails: Parameter Driven Response-Type Determination

Posted by ryan
at 9:02 AM on Thursday, June 01, 2006



The HTTP_ACCEPT header is used by web-clients to tell your application what type of response it wants and is the magic behind the very slick responds_to method of your controller. Rails edge now supports the case when you want to specify the type of response as a request parameter and not as an http header.

Currently, when a client sends an Http request to your app with an HTTP_ACCEPT header value of application/xml, you can do this in your controller to render the response as the appropriate XML:


# From example at:
# http://api.rubyonrails.com/classes/ActionController/MimeResponds/InstanceMethods.html#M000062
...
respond_to do |wants|
  wants.html
  wants.xml { render :xml => @people.to_xml }
end
...

Great, we’ve got an easy way to render the type of response the client has asked for without duplicating our controller logic. But, we don’t yet have a way to trigger this little bit of magic from anything other than the Http header – not a very friendly place to hang out. That’s what changeset 4384 addresses – the ability to determine the requested response type from a normal http parameter instead of the http header.

How it Works

Telling the request what response type you want is now as easy as adding a format parameter to your request and using the same respond_to determination as before. So this request sent from your web browser (which always sends an HTTP_ACCEPT header value of text/html or */*)


http://host/action?format=xml

Will override the supplied HTTP_ACCEPT header and will trigger the xml block of respond_to in your controller (imitating HTTP_ACCEPT = application/xml)

Overall a great way to programatically specify the response type without monkeying with http headers.

For further reading on the topic, here are some related posts:

tags: http headers, rubyonrails, rails