Sunday, March 23, 2008

params[:fu] #1 ) Wrap all relevant attributes in a single params key.

This is the simplest form of using form_for and params:

<% form_for @reader do |f| %>
<%= f.text_field :name %
<%= f.text_field :birth_place %>

= f.submit 'Create' %>
<% end %

Processing ReadersController#create (for at 2008-01-14 21:12:56) [POST]
Parameters: { "commit" => "Create",
"reader" => { "name" => "stephen chu", "birth_place" => "hong kong" },
"authenticity_token" => "238ba79b8282882ba01d840352616c2cc79280f0",
"action" => "create",
"controller" => "readers"}

def create
@reader = Reader.create! params[:reader]

By doing this, you eliminate the need to explicitly spell out each parameters posted, like the ugly :name => params[:name], :birth_place => params[:birth_place].

Notice, Active Record is extremely hash-happy. Let's take a few examples and see how it is so hash-hungry (or rather, hash-happy).

@reader = params[:reader]  # => { 'first_name' => 'stephen', 'last_name' => 'chu' }

@readers = Reader.find(:all, :conditions => params[:search]) # => { 'name' => 'chu' }

@reader.attributes = params[:reader] # => { 'first_name' => 'martin', 'last_name' => 'fowler' }

@reader.update_attributes(params[:reader]) # => { 'birth_place' => 'hong kong' }

Notice the find with condition one. No one says I cannot have a hash or form_for that must map to a database table!

All of the above will work in just one line of code, and I am sure you can find more examples as well. Remember, hashes are one of the most underrated Rails toolset to reduce code you need to write. Stay tuned on how we can optimize the use of these AR one-liners.

(back to the TOC of the params[:fu] series)


Clmens Kofler said...

You should at least mention that there may be some attr_protected/attr_accessible in the way ...

Other than that - great series!

codesnik said...

find :all, :conditions => params[:foo] is prone to sql injection, no? :conditions could be a mere string, and although rails mysql driver doesn't allow to run several sql commands at once, I'm pretty sure someone can write something nasty, just by form tampering.

Stephen Chu said...

Last I checked, passing a hash construct to :conditions will trigger params sanitization inside ActiveRecord. Check out the "Conditions" section.

codesnik said...

hash - yes, but string - isn't.
One could easily change your form in a way it would send params[:search] == "1=0);drop table users;select (1"

making resulting SQL:
"select from users where (1=0);drop table users;select (1)".

although this won't work with latest mysql drivers (they have multiple statement execution disabled), I'm pretty sure one can do something interesting with such a technique.

Eric said...

Is there a reason why your main content section is only 40 characters wide?