Helpful Error Messages in-direct from your App

Custom error pages directly from your app are far better than hand-made pages or those that rails gives you by default. But if they use your controllers/helpers they may send a user into a crash-loop (arriving on /500 and boom-> /500…)

So simple add an errors controller, build some templates(name is e500, since” def 500″ will not work), set them to page caching and ping them after each deploy.

#routes.rb as lat rule
  %w[500 404 422].each do |error|
    map.connect error, :controller=>'errors', :action=>"e#{error}"
  end

#errors_controller.rb
class ErrorsController < ActionController::Base
  helper :all
  layout 'blank' #new layout, without dynamic gimmicks
  caches_page 'e500', 'e404', 'e422'

  #no authentification, so just nil
  def current_user
    nil
  end
  helper_method :current_user
end

#e500.html.erb
<h1>BOOM!</h1>

#deploy.rb
task :ping_error_pages do
  %w[500 404 422].each do |error|
    run "wget -O /dev/null localhost/#{error} --quiet"
  end
end

after "deploy:restart", *%w(
  rs:ping_error_pages
  ...
)

How to Load Javascript Last with Inline JS

Load JS last, or it will halt the browser while loading… AMEN!

You may protest:
But i use some inline javascript and nothing will work, when jQuery / Prototype / Mootolls / … is not loaded already!!

Version 1: content_for :js

#in your body: (HAML example, works for ERB too...)
%h1 My great title
- content_for :js do
  :javascript
    $(function(){
      $('h1').html('inline js rocks!')
    });

#in you footer
  =js_tag 'jquery', 'application', 'whatever'
  yield :js #this will output all content_for blocks...

Instantly better load times, and no need to abandon inline js!!

Version 2: Caching !?
When action/fragment-caching, this can get problematic, since the content_for will not be call, and hence the js will be missing.
This can be fixed by introducing a ‘later’ method, which gets filled with everything that should be done once your js framework is loaded.

#in your views
later(function(){
  $('#xxx').do_something();
})

#in you footer
later(); //call all those methods that have been stacked...

#in your head
later = function(){
  var stack = [], i_ran=0;
  return function(execute_later){
   if(typeof(execute_later)=='undefined'){
     i_ran=1;
     for(var i=0;i<stack.length;i++)stack[i].call();//execute them all
   } else {
     if(i_ran)execute_later.call()//page is loaded already, just execute
     else stack.push(execute_later)//page not finished, store
   }
 };
}()

Simple Meta Tags with MetaOnRails

Simple meta tag rules (from google webmaster tools):

  1. do not add useless meta tags
  2. add site-wide-unique meta tags
  3. add max 10 keywords
  4. in doubt add no meta tags, search engines will grab something

Obey or be penalized.

For simplicity use: MetaOnRails Rails plugin

Usage

#in your head (no not that head...)
=display_meta

#in your views, add unique keywords/description that matter
set_meta(
  :keywords=> [@movie.category, @movie.genre,@user.name]*' ',
  :description=>@movie.description
)

Output

<meta name="description" content="my description" />
<meta name="keywords" content="my,keyword" />

A More Useful login_as Test Helper

I just got upset that i could not do login_as User.first or User.first.id, so i fixed that…

Usage

#in your tests...
login_as :quentin
login_as false
login_as User.first
login_as User.first.id + 1

Install

#authenticated_test_helper
  def login_as(user)
    id = case user
      when false,nil then nil
      when Symbol,String then users(user).id
      when Fixnum then user
      else user.id
    end
    @request.session[:user_id] = id
  end

Alter Column the Missing Migration Method for ActiveRecord

Changing many columns is not so easy, because change_column forces you to enter all attributes you want (default,limit,null…) again.
So to make less errors we just alter the attributes we want to change and leave the rest alone.

Install

#Inside your migration
def self.alter_column(table,column,text)
  execute("ALTER TABLE #{quote_table_name(table)} ALTER #{quote_column_name(column)} #{text}")
end

Usage

# to set the default to nil, without remembering all the other 
# stuff change_column needs
alter_column(:users,:name,"DROP DEFAULT")

So thats very basic, but i hope it helps anyway 🙂