Ruby is a wonderful language. And Rails is a wonderful framework.
Why ? Because of Duck typing !!!
Example :
You build a database application for a book store
Books are classified by :
- Genre
- Author
- Country
On a search page, you can search with a title text field, author select box, genre checkboxes.
So we want to create a search form with all the fields described above :
<%= form_tag('/search') do %> <p> <label for="title">title</label> <%= text_field_tag 'title' %> </p> <p> <label for="author">Author</label> <%= select_tag 'author', options_for_select @authors, @selected_author %> </p> <% @genres.each do |g| %> <p> <label for="<%= 'genre_' + g.id.to_s %>"><%= g.label %></label> <%= check_box_tag 'genre[]', g.id, g.id == @selected_genre, :id => "genre_#{g.id}" %> </p> <% end %> <% end %>
When I submit the code, it does not keep the value of the search fields, as it is when passing activerecord object in form helpers (with text_field not text_field_tag.)
Ok!! And what if I construct an object behaving like activerecord object ?
My template will be like this :
<%= form_for @search do |f| %> <p> <%= f.label :title, 'Title' %> <%= f.text_field :title %> </p> <p> <%= f.label :author, 'Author' %> <%= f.select :author, @authors %> </p> <% @genres.each do |g| %> <p> <label for="<%= 'genre_' + g.id.to_s %>"><%= g.label %></label> <%= check_box_tag 'search[genre][]', g.id, g.id == @selected_genre, :id => "genre_#{g.id}" %> </p> <% end %> <%= submit_tag "Search" %> <% end %>
Yes we have a namespace called “search” on all parameters such as “search[title]” but I think it is not ugly, instead the code will be more readable !!!
Ok, but what’s the magic ? How can I have an activerecord like search object ?
Simply like that :
# encoding: utf-8 class Search def initialize(params={}) @params = Hash.new.merge(params['search'] || {}) end def method_missing(method_sym,*args) case method_sym.to_s when /^\[\]=?$/ @params.send(method_sym,*args) when /^(.*)=$/ @params.update($1,*args) else @params[method_sym.to_s] end end end
In your controller, simply instantiate a @search variable with your parameters :
# app/controllers/search_controller.rb def search @search = Search.new(params) # .... end

