Cory O'Daniel – These are just words Software development, thoughts, and randomness

17Nov/112

Rails 3 Easy Search forms using SimpleForm and ActiveModel

For the sites I'm currently working on I have search pages all over the place for different resources, especially on the backend. In the past I would forego using form builders and just do some HTML to make a form GET the data. I hate HTML.

So I did some poking around to see what I could do to DRY up my time on creating these search forms. My first thought was to create a Search class and use active model, but it sucked because I everytime I had to create a new form I had to come into the search class and add a bunch of attr_accessors for all of the search fields. That sucks.

So I decided to mix it up with OpenStruct and ActiveModel

require 'ostruct'
class Search < OpenStruct
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend  ActiveModel::Naming
 
  def initialize(*args)
    super
  end
 
  def persisted? ; false ; end;
end

Now I use this one model for searching of all of my resources.

I create the form super easily with SimpleForm:

= simple_form_for(@search, url: my_cool_path(), html:{method: :get}) do |f|
  = f.input :text
  = f.select :category,  Product::CATEGORIES
  = f.input :minimum_price
  = f.input :maximum_price
  = f.submit :search

In your controller you are going to get a params[:search] hash with :text, :category, :minimum_price, :maximum_price.

Want to persist that search across page reloads?

class ApplicationController < ActionController::Base
  before_filter :persist_search
  protected
  def persist_search
    @search = Search.new params[:search]
  end
end

Now you'll have a Search object in all of your requests with your user's search params. Use it as you will to return them the resources they are looking for.

*Side note*
I use the above logic for all of my resources, until one of my resources has a requirement like a validation. Then I break it into something like FlightSearch:

require 'ostruct'
# ostruct for that lazy goodness
class FlightSearch < OpenStruct
  # Get activemodel in there for all its cool functionality like model name, pluralization, validation, yada yada yada
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend  ActiveModel::Naming
 
  validates_presence_of :origin_airport, :destination_airport
 
  # you can do cool things here, just make sure you call super so ostruct 
  # takes all those hash params and makes them methods
  def initialize(*args)
    super
  end
 
  # ActiveModel needs to know that this wasn't persisted.
  def persisted? ; false ; end;
end

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Comments (2) Trackbacks (0)
  1. In search.rb, why is this necessary?

    def initialize(*args)
    super
    end

    Not trying to critique/criticize, just curious.

  2. I just left it in there and clipped out some code I had in that method. You don’t need it.


Leave a comment


No trackbacks yet.