“What’s New in Edge Rails: Easy Join Table Conditions”

Just came across this new cool feature in edge rails…

For an application with anything above a moderate level of domain complexity it’s quite likely that you’ve had to perform a query utilizing a join table:

class Article < ActiveRecord::Base
belongs_to :user
end

class User < ActiveRecord::Base
has_many :articles
end

# Get all the users that have published articles
User.find(:all, :joins => :article,
:conditions => [articles.published = ?, true])

t always makes me feel slightly embarrassed to have to resort to using String snippets to specify my query logic, and this little bit is no exception. Well, now we can specify conditions on a join table in a more concise manner:

# Get all the users that have published articles
User.find(:all, :joins => :article,
:conditions => { :articles => { :published => true } })

Note how you’re able to specify the join-table conditions as a hash whose key corresponds to the table or association name of the join table? You can now let Rails worry about forming the correct SQL condition even across complex joins.

However, don’t let the ease of this feature make you use it over a properly associated domain-model. For instance, this join query:

# Get all articles for a given user
Article.find(:all, :joins => :user,
:conditions => { :users => { :id => @user.id } })

is more appropriately represented as:

@user.articles

Technorati Tags: , , , ,

“What’s New in Edge Rails: Better Cross-Site Request Forging Prevention”

Hot on the heels of the in-depth look at Rails security options comes the addition of the CsrfKiller plugin into rails core.

The CsrfKiller plugin adds a unique session token field to all forms
that is checked on every non-GET request. This ensures that the request
received is in fact coming from the session of the authorized user
(check out wikipedia’s CSRF article if you need more details on the technique).

All you need to do to enable this protection is to add a protect_from_forgery statement in your controller that takes the familiar :except or :only option along with salt to use when generating the unique token:

And now this is the default functionality. No need to specify anything if you want the default behavior. You can still override as in the following examples, however.

class PostsController < ApplicationController protect_from_forgery :secret => ‘2kdjnaLI8’, :only => [:update, :delete, :create] …end

If you’re already using edge Rails’ default cookie session store then you don’t have to specify the :secret key.

protect_from_forgery :only => [:update, :delete, :create]

If you’re not on a cookie session store you can also change the digest
method used to generate the unique token (the default is ‘SHA1’).

protect_from_forgery :secret => 2kaienna9ea90djnaLI8, :digest => MD5

If a request comes in that doesn’t match the request forgery protection token for the current session then an ActionController::InvalidAuthenticityToken exception will be thrown. Perhaps a good place to try out the new exception handling syntax ?
Caveats: The request forgery protection only kicks in in the following scenarios:

  • Non-GET requests, so make sure the only requests that modify state are your PUT/POST/DELETE
  • On html and ajax requests. Override verifiable_request_format? if you want to expand that requests.

And what to do if you want to disable CSRF protection? Just add this to whatever controllers you don’t want to be affected:

skip_before_filter :verify_authenticity_token

And if you want to disable this site-wide, just add this to application.rb:

self.allow_forgery_protection = false