Better assert difference?

Rails come with some awesome assertion methods for writing tests:

assert_difference("User.count", +1) do

That asserts that the count of user was incremented by one. The plus sign is not needed, that’s just an integer, I add it to make things clear. You can mix several of this expressions into one assert_difference:

assert_difference(["User.count", "Profile.count"], +1) do

That works as expected, it asserts that both users and profiles were incremented by one. The problem I have is that I often found myself doing this:

assert_difference "User.count", +1 do
  assert_difference "Admin.count", 0 do
    assert_difference "Message.count", +3 do  # We send three welcome messages to each user, like Gmail.

That looks ugly. Let’s try something different:

assert_difference("User.count" => +1, "Admin.count" => 0, "Message.count" => +3) do

Well, that looks nicer, and straightforward, so I implemented it (starting from Rails 3 assert_difference):

def assert_difference(expressions, difference = 1, message = nil, &block)
  b = block.send(:binding)
  if !expressions.is_a? Hash
    exps = Array.wrap(expressions)
    expressions = {}
    exps.each { |e| expressions[e] = difference }

  before = {}
  expressions.each {|exp, _| before[exp] = eval(exp, b)}


  expressions.each do |exp, diff|
    error = "#{exp.inspect} didn't change by #{diff}"
    error = "#{message}.\n#{error}" if message
    assert_equal(before[exp] + diff, eval(exp, b), error)

Do you like it? If you do, let me know and I might turn this into a patch for Rails 3 (and then let them now, otherwise they’ll ignore it).

Update: this is now a gem.

Redirect to SSL in Rails applications

I’ve looked at the various ssl_requirement repositories out there. I concluded the most modern and maintained version is yardstick’s which is released as a gem called sslrequirement, but I’ve failed to use it properly. So I just did it by hand.

First, we need a simple method that will let us know whether SSL is enabled or not. We don’t want to redirect to SSL in development mode because it’ll fail. In the application controller I’ve created:

  def ssl_enabled?
    !(Rails.env.development? || Rails.env.test?)

Switching to SSL is not only a matter of redirecting. If you show a login or signup form in your homepage, like I do in Restraq, you want that to point to https even if the page was loaded as http. So I’ve added this helper method in the application controller:

  def https
    ssl_enabled? ? "https://" : "http://"
  helper_method :https

and then for the forms I just do this:

form_for ..., :url => session_url(resource_name, :protocol => https)


form_for ..., :url => registration_url(resource_name, :protocol => https)

And then the redirection part, which is a before filter in the application controller because I want to redirect when hitting Devise controllers:

  def enforce_ssl_if_needed
    if request.protocol == "http://" && ssl_enabled? &&
            (controller_name == "registrations" || controller_name == "sessions")
      redirect_to :protocol => https
    return true

and that’s it. I’m not actually testing it yet. For a similar solution with tests you might want to check out SSLShopper’s article about this.

Really resetting the database

When I start coding a Ruby on Rails project, I find myself modifying the migration files over and over. I know this is not the way they were intended to use, but to avoid upfront design, I only ad fields when I need them. If I respected the way migrations were intended I would end up with hundred of migrations the first day and I would waste half my day just creating migrations.

After a project is deployed or a second developer is working on it, I revert to the way migrations are intended and I create a new one every time there’s a change I need in the database.

As migrations are intended to run only once, if you modify them, they won’t get run; and if you force them to run them, they’ll fail, because the database already contains such a table. So I’ve found myself doing this quite often:

rake db:drop && rake db:create && rake db:migrate && rake db:seed && rake db:data

db:data is a task I created to generate some sample data. Good known data that I can use to test the site locally. I’m using Factory Girl to create it, which I also use for the tests so I can re-use as much data creating logic as possible. It’s very good to get to a known state of the project you are developing and to get other developers started right away. I really recommend everyone doing it.

The problem is that I also need to reset my test data, so I end up having this other command and it gets horrible:

RAILS_ENV=test rake db:drop && RAILS_ENV=test rake db:create && RAILS_ENV=test rake db:migrate && RAILS_ENV=test rake db:seed

Note: no db:data this time.

I’ve got tired of re-writing these commands or trying to find them in my bash history, so I decided to write a Ruby task that will do it for me and here it is in case you want to use it too:

namespace :db do
  desc "Crush and burn the database"
  task :hard_reset => :environment do
    if !Rails.env.test?

  desc "Generate sample data for developing"
  task :data => :environment do
    # Create the sample data in here


Update: To delete all records without resetting the whole database, check my post Deleting all records in a Rails project.

My Profile page: a RESTful single resource using Formtastic

I’ve just implemented the My Profile tab for Sano:


Can I write 500 words about? Well, I can try.

I like using RESTful routes. In case you don’t know what they are let me try to explain it quick, at least the relevant part. You normally have a set of route rules that would point /movies to the movie listing, /movies/new to a form to add a new movie, /movies/123 to see the movie 123. With RESTful routes in Rails all that is done automatic in a single line:

map.resources :movies

What you are doing is defining a resource. The resource has several actions that can be performed on them:

  • index (a.k.a.: listing)
  • new
  • edit
  • create
  • update
  • destroy

In Sano I have a weights resource that is a very fine example of it:

map.resources :weights

Running the rake routes command we can see all the routes it generate:

    weights GET    /weights(.:format)          {:action=>"index", :controller=>"weights"}
            POST   /weights(.:format)          {:action=>"create", :controller=>"weights"}
 new_weight GET    /weights/new(.:format)      {:action=>"new", :controller=>"weights"}
edit_weight GET    /weights/:id/edit(.:format) {:action=>"edit", :controller=>"weights"}
     weight GET    /weights/:id(.:format)      {:action=>"show", :controller=>"weights"}
            PUT    /weights/:id(.:format)      {:action=>"update", :controller=>"weights"}
            DELETE /weights/:id(.:format)      {:action=>"destroy", :controller=>"weights"}

You see the (.:format) in there? That means that every route is also accessible in alternative formats. For example: xml. Go and try it, add some weights and access

If you are curious, the code for that is this:

def index
  @weights = user.weights.all

  respond_to do |format|
    format.xml  { render :xml => @weights }

I now want everything to be a resource. How can “my profile” be a resource? Well, it’s not hard. It’s not a collection resource, it’s a single resource. There’s no list of profiles, no creation of new profiles or destruction of profiles. There’s only editing and updating of a single profile (which is actually your user).

It turns out that in Rails, that’s very easy to define:

map.resource :profile, :only => [:edit, :update]

Notice how it says “resource” instead of “resources” and it only allows certain actions. Rails is really quite flexible here, logging in is also a resource. It’s called session and you can create them, by logging in, or destroy them, by logging out (no editing). There’s also an extra action needed by OpenID. This is the route definition:

map.resource :session, :only => [:new, :create, :destroy], :member => { :finish_creating => :get }

The “member” part specifies that action to be only for items, not for the whole collection. If it was a collection resource, you could have extra listings. The same way you have index, you could have sorted_index.

The form in the my-profile-page is an example of what Formtastic is good at. This is the whole form:

<% semantic_form_for @user, :url => profile_url do |f| %>
  <% f.inputs do -%>
    <%= f.input :name %>
    <%= f.input :email %>
    <%= f.input :height, :hint => "meters" %>
    <%= f.input :gender, :as => :radio, :collection => [["Male", false], ["Female", true]] %>
    <%= f.input :birthday, :start_year => 1900, :end_year => %>
  <% end -%>
  <% f.buttons do -%>
   <%= f.commit_button :label => "Update profile" %>
  <% end -%>
<% end %>

Special thanks to Ryan Bates who covered the gender case in Railscasts episode 184 and Eifion Bedford of ASCIIcasts for making it easy to find. It surely would have take me some time to figure it out.

Can you please update your profile on Sano?

There you go 553 words!

I love to code

I said I was done for the day more than 6 hours ago, but I love to code, I couldn’t stop. I wanted to implement a small feature: make the creation of new weights simpler for the common case and I did it:


Note: That change is not yet deployed. I don’t play with servers while I’m half-asleep.

This took awfully long. The problem was that in the process I’ve found a bug in Formtastic, which made me realize I was running version 0.2.4 when the latest version was 0.9.2. That is because I was using justinfrench-formtastic:

config.gem 'formtastic', :lib => 'justinfrench-formtastic'

when I should have been using formtastic from gemcutter:

config.gem 'formtastic'

When I moved to 0.9.2 I’ve found two bugs on it, one was temporary solved and then reverted (and I fixed it by reverting the revertion) and the other is still there but I’m not 100% confident my solution is the appropriate one. At any rate I forked Formtastic in GitHub, fixed the bugs and made a merge request.

Conclusion: Git is great, GitHub is great, Formtastic is great, open source is great, Rails is great and yes, I am great ;)

Sano is open for business

I really wish I was able to get farther in one day, but I think it’s good enough that I went from idea to deployed app. On retrospective I wasted too much time figuring out formtastic. I don’t regret doing it because it was in my TODO list and in the long run it should make me more productive, but in the short run maybe I should have used the good old forms.

The other two big waste of times was CSS and tables and an issue with the Ruby OpenID gem. Both problems I encountered before and both times I gave up trying to solve them and moved on. I should have moved on again this time; but instead I figured them out.

The application is at Please don’t break it ;) Remember to log in and if you add data I’ll be grateful as it’ll make my migrations more realistic:


I’m done for today.

Super Exception Notifier

I like knowing when something goes wrong with my web apps, so I’m using Super Exception Notifier to get by email a report should any exception be raised in the app. If you go to Super Exception Notifier’s site you’ll see some instructions on how to add it to your project. This is how I do it.

Add the gem requirement in environment.rb:

config.gem 'super_exception_notifier', :version => '~> 2.0.0', :lib => 'exception_notifier'

Then be sure to have gemcutter in your gem sources:

gem sources

If you don’t have it, you can add it this way:

gem install gemcutter
gem tumble

To install the gem, in your Rails project run:

sudo rake gems:install

Create a file in config/initializers, I’ve called it exception_notifier.rb and inside I’ve set up the only really needed value for the notifications, the email address:

# Notification configuration
ExceptionNotifier.configure_exception_notifier do |config|
  config[:exception_recipients] = %w(

The last task is to make your application controller noisy by adding one line to it (the second one of course):

class ApplicationController < ActionController::Base
  include ExceptionNotifiable

You also need to be sure that you have ActionMailer properly configured, otherwise no mail is going to get through.