Skip to content

Error Handling

dburry edited this page Jul 15, 2012 · 17 revisions

Error Handling

Here is an example of using full error handling in your app. This method uses a table-less activerecord class to handle validations for the search form.

 # app/models/search_form.rb
 class SearchForm

   # table-less model
   # someday include ActiveModel::Model may simplify this...
   include ActiveModel::Validations
   def initialize(params={})
     params.each { |atr, val| send("#{atr}=", val) } if params
   end
   def persisted?
     false
   end
   def to_key
     nil
   end

   # set up attrs and defaults
   attr_accessor :query, :page
   def page
     @page.blank? ? '1' : @page
   end

   # validation of attrs
   validates_presence_of :query
   validate do
     if query.present? && ! results?
       errors.add :query, errors.generate_message(:query, :not_found)
     end
   end
   validates_numericality_of :page, :only_integer => true,
       :greater_than_or_equal_to => 1,
       :less_than_or_equal_to => proc { |search_form| search_form.maximum_page },
       :if => proc { |search_form| search_form.query.present? }

   # shortcuts for accessing info about the searches query
   include IndexedSearchHelper
   PAGE_SIZE = 10
   def maximum_page
     # total_pages comes from IndexedSearchHelper
     results? ? total_pages(PAGE_SIZE, count) : 1
   end
   def results
     @results ||= IndexedSearch::Entry.find_results(parsed_query, PAGE_SIZE, page.to_i)
   end
   def count
     @count ||= query.blank? ? 0 : IndexedSearch::Entry.count_results(parsed_query)
   end
   def results?
     count > 0
   end
   def parsed_query
     @parsed_query ||= IndexedSearch::Query.new(query)
   end

 end
 # config/routes.rb
 Foo::Application.routes.draw do
   resource :search
   # plus resources for the models you've defined to be searchable!
 end
 # app/controllers/searches_controller.rb
 class SearchesController < ApplicationController
   def show
     @search_form = SearchForm.new(params[:search_form])
   end
 end
 <!-- app/views/searches/show.erb -->
 <%= form_for @search_form, :url => search_path, :method => :get, :authenticity_token => false do |search_form| %>
   <%= search_form.text_field :query %>
   <%= search_form.hidden_field :page %>
   <%= search_form.submit %>
 <% end %>

 <% if ! @search_form.valid? %>
   <% @search_form.errors.full_messages.each do |message| %>
     <div><%= message %></div>
   <% end %>
 <% elsif @search_form.results? %>
   <% @search_form.results.each do |result| %>
     <!-- assumes every model has a name attribute to display here -->
     <div><%= link_to result.model.name, result.model %></div>
   <% end %>
 <% end %>
 # config/locales/en.yml
 en:
   helpers:
     submit:
       search_form:
         create: Go!
   activemodel:
     errors:
       models:
         search_form:
           attributes:
             query:
               blank: must be entered
               not_found: not found, try again
             page:
               not_a_number: must be a number
               not_an_integer: must be an integer
               greater_than_or_equal_to: must be greater than or equal to %{count}
               less_than_or_equal_to: must be less than or equal to %{count}

You might notice it includes validation and error reporting for a page number, yet doesn’t include any fancy page navigation in the view… We’ll leave that for a different exercise. :)