Tag: Rails

  • Rails come with some awesome assertion methods for writing tests:

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

    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
      create_a_user
    end
    

    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.
          create_a_user
        end
      end
    end
    

    That looks ugly. Let’s try something different:

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

    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 }
      end
    
      before = {}
      expressions.each {|exp, _| before[exp] = eval(exp, b)}
    
      yield
    
      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)
      end
    end
    

    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.

  • 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
        File.delete("db/schema.rb")
        Rake::Task["db:drop"].execute
        Rake::Task["db:create"].execute
        Rake::Task["db:migrate"].execute
        Rake::Task["db:seed"].execute
        if !Rails.env.test?
          Rake::Task["db:data"].execute
        end
      end
    
      desc "Generate sample data for developing"
      task :data => :environment do
        # Create the sample data in here
      end
    end

    Enjoy!

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

  • 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
    *** CURRENT SOURCES ***
    
    http://gemcutter.org
    http://gems.rubyforge.org/
    http://gems.github.com
    

    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([email protected])
    end
    

    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
      #...
    end
    

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

  • For my Ruby on Rails pet project Is it Science Fiction? I’ve reached that point when I wanted to show tabs. You know, for the menu, on top of the page. I quickly wrote something like:

    <ul class="tabs">
      <li><%= link_to 'Home', root_url %></li>
      <li><%= link_to 'Recommend', new_item_url %></li>
      <li><%= link_to 'Ranking', items_url %></li>
      <% if session[:user_name] -%>
        <li><%= link_to 'Log out', session_url, :method => :delete %></li>
        <li><%= link_to 'My Profile', edit_profile_url %></li>
      <% else %>
        <li><%= link_to 'Log in', new_session_url %></li>
      <% end %>
    </ul>
    

    and styled it like the Listamatic Unraveled CSS tabs. And everything was good, except that the current tab wasn’t highlighted. Highlighting it is a matter of setting the correct class for it.

    For that I created a new version of link_to that adds the “current” class to a link if it points to the current page. That is not very hard actually, but you have to consider that some tabs, like Ranking, are not only highlighted when that page is show, but when any subpage (like a ranked item) is shown as well. After trying many solutions (in an effort to find the simplest one) I’ve settled for link_to2 and the tabs now look like this:

    <ul class="tabs">
      <li><%= link_to2 'Home', root_url %></li>
      <li><%= link_to2 'Recommend', new_item_url %></li>
      <li><%= link_to2 'Ranking', items_url, {:extra_current => {:controller => :items, :action => :show}} %></li>
      <% if session[:user_name] -%>
        <li><%= link_to 'Log out', session_url, :method => :delete %></li>
        <li><%= link_to2 'My Profile', edit_profile_url %></li>
      <% else %>
        <li><%= link_to2 'Log in', new_session_url %></li>
      <% end %>
    </ul>

    Look at the Ranking tab, it has an extra_current that adds other pages to be treated as current. The code to do this is the following (I’ve put it in application_helper.rb):

    module ApplicationHelper
      def link_to2(*args, &block)
        if block_given?
          options      = args.first || {}
          html_options = args.second || {}
        else
          name         = args.first
          options      = args.second || {}
          html_options = args.third || {}
        end
    
        if current_page?(options) or as_array(html_options[:extra_current]).any? {|o| current_page2? o}
          html_options[:class] = add_class(html_options[:class], "current")
        end
    
        html_options.delete(:extra_current)
    
        if block_given?
          link_to(options, html_options, &block)
        else
          link_to(name, options, html_options, &block)
        end
      end
    
      private
    
      def add_class(classes, new_class)
        ((classes or "").split(" ") << new_class).join(" ")
      end
    
      def as_array(o)
        if o == nil
          []
        elsif not o.is_a? Array
          [o]
        else
          o
        end
      end
    
      # current_page? of {:controller => :blah, :action => :bleh} when the routes also require an id raises a route error. current_page2? doesn't.
      def current_page2?(p)
        current_page? p
      rescue
        return false
      end
    end
    
    

    Feel free to pick the code and use it in any way you want. I’m thinking of turning it into a gem, but I need a better name than link_to2, any ideas?

  • Ruby on Rails has a special object called flash which hold its contents for one more request. It’s particularly useful to show messages after a redirect. Since it’s good style to redirect after each succesful form post, that’s where you put the messages such as: “You’ve logged in”, “Thank you for your feedback”, “The book has been added”, etc.

    This flash object looks like a hash table. I normally use two items in there: notice, for good stuff and errors, for bad stuff. I want these messages to be displayed in all pages, so whenever something bad or good happens, I just drop stuff in the notice or error and forget about it. This is trivial to do, I just put this:

    <% if flash[:error] -%>
      <p class='error'><%=h flash[:error] %></p>
    <% end -%>
    <% if flash[:notice] -%>
      <p class='notice'><%=h flash[:notice] %></p>
    <% end -%>

    on the application layout.

    The problem with doing that is that it doesn’t look nice. I expect error messages and success messages to be near the forms or UI elements I’m interacting with. That means that every view or page will put it in a different location. No problem, you just add that same snippet where you want the messages to appear.

    Then there’s a second problem: you get messages twice. If you remove them from the application layout, then you have to remember to put in absolutely every view, even those that you don’t expect to never show an error or notice. I don’t trust myself to always remember to do anything, so what happens is that I can’t just drop something in the flash and expected it to be show, I have to check every time.

    I’m doing this in for a pet projects with less than 10 views, but I think big. I think of the project having 100 views and three coders than don’t know all the implicit rules, like adding the display message snippet to every view they create.

    I’ve came up with this solution. I created a partial view with this content:

    <% if not @messages_rendered -%>
      <% if flash[:error] -%>
        <p class='error'><%=h flash[:error] %></p>
      <% end -%>
      <% if flash[:notice] -%>
        <p class='notice'><%=h flash[:notice] %></p>
      <% end -%>
    <% end -%>
    <% @messages_rendered = true -%>

    That partial view is rendered from the views and also from the application layout, but it displays the messages only once. Thankfully Rails renders the partials inside the views first, so that the messages gets displayed according to the view, and if the view didn’t display them, the application layout will.

  • NetBeans could make the Ruby on Rails experience great for the vast majority of developers who are using Windows, where installing Ruby, Rails, PHP, MySQL, Python, etc is always a pain and the end result is ugly. But it falls short in some important ways which turned my experience with it into a nightmare.

    The reason I say “for developers using Windows” is because I believe that for everybody else, the experience is great already. Or as good as it can be and NetBeans can be an excellent IDE, but not improve the installation and managing experience.

    This is my story, my rant.

    I downloaded the latest NetBeans and installed it. When creating my first Ruby project, I encountered the first problem. Ruby chocked on my username, which was “J. Pablo Fernández”. You could say it was my fault. Windows 7 asked for my name and I typed it. I wasn’t aware it was asking for my username. Even then I would have typed the same, because Windows 7 doesn’t distinguish between usernames and names, and in the 21st century, computers should be able to deal with any character anywhere.

    I know it’s not NetBeans’ fault, it’s Ruby’s. But! Can you imagine a Software Engineer telling Steve Jobs “oh, copying files in a Mac behaves weirdly because it uses rsync and that’s its behavior, you see, it makes sense because…”? Of course Steve would have interrupted: “You’ve failed me for the last time”. The next developer would have patched rsync, trying to get the patch upstream, or creating an alternate rsync or stop using rsync.

    I’ve spent many hours creating another user, migrating to it, which in Windows is like 100 times harder than it should.

    Hours later, as soon as I created a project I got a message saying that I should upgrade gem, Ruby’s package manager, because the current version was incompatible with the current Rails version. By then I had already played with NetBeans’ gem interface telling it to upgrade everything, it should have upgraded gem as well, not just the gems. Every single developer out there running NetBeans must be encountering this error, and indeed there are quite a few threads about it on forums.

    Trying to upgrade gem with NetBeans was impossible. I think what they did to install and upgrade gems in NetBeans is excellent, but failing to upgrade gem itself was a huge drawback. This one was NetBeans’ fault. Neverfear, let’s do it from the command line.

    When doing it from the command line I encountered another error:

    \NetBeans was unexpected at this time.

    Looking around it seems it’s because of the spaces in “Program Files (x86)”. That means that the command line environment for Ruby that NetBeans installs is broken for everybody. I repeat: everybody. The answer: install it somewhere else.

    Well, I have two things to say about it: first, fix the freaking thing, Ruby, gem, whatever. Paths can have spaces and all kind of weirdness. It’s a big world full of people speaking languages that can’t be represented with ASCII and people that believe computers should do our bidding, instead of the other way around. “If I want spaces you better give me spaces, useless lump of metal and silicon”.

    Second, if you know one of your dependencies is broken, try to avoid triggering the broken behavior or at least warn the user about it. “We see you picked C:\Program Files (x86)\ to install NetBeans, which is pretty standard, but you know, Ruby is broken and can’t work in there, not even JRuby, so if you plan to use those at all, please consider installing it somewhere else.”

    I uninstalled NetBeans, or tried to. The uninstaller didn’t work. I deleted it and tried to install it on C:\ProgramFilesx86, which failed because some other directory created by NetBeans somewhere else existed from the previous installation, which halted the installation. I started a dance of run installer, remove dir, run installer, remove dir, run installer… until it worked.

    Once I finished I found out that NetBeans installed in C:\ProgramFilesx86\Netbeans 6.7.1. Yes, that’s a space. Oh my…

    As a bonus, NetBeans can’t automatically find Sun’s JDK in its default directory. I had to point to it by hand. Sun was, as usually, absolutely disrespectful of the platform conventions and installed its crap in C:\Sun. I would have picked another place but I thought “I’m sure some stupid program will want to pick that shit from there”. Silly me.

    12 hours have passed and I still haven’t been able to write a single line of source code. I contemplated installing Ruby by hand, but it’s so ugly that I decided I’m not going to use Windows for this. I’m going to work on another platform where installing Ruby is trivial and where I would probably never touch NetBeans because I have other editors.

    I know there’s a lot not really related to NetBeans here, for example, the fact that working with Python, or Ruby or MySQL in Windows is a pain; but it’s a great opportunity for NetBeans. There are developers wanting to use those languages and environments and if NetBeans makes it easy for them, they will pick NetBeans not because of its editor, but because of everything else (which is what I was hoping to get out of NetBeans).

    Aside from doing some usability tests, the people working on NetBeans should learn from the people working on Ubuntu (not the people working on Evolution) and instead of asking me for debugging traces when I report a simple obvious bug and then tell me it’s not their fault, they should submit those bugs upstream, to Ruby, gem, or whatever. Whenever someone like me submits that bug to NetBeans they should mark it as duplicate of an existing open bug that points to the upstream bug. I would have followed that link and told the Ruby developers “wake up!”. As it is, I didn’t. It’s too much work for me.

    Reviewed by Daniel Magliola. Thank you!

  • This is a remake of Installing Rails 2 on Ubuntu but targeting Ruby in general and with some improvements. Essentially the same, actually, but more usable, at least for myself.

    Ubuntu, like many other free operating systems, have a beautiful package management system that will track what depends on what, what is installed, what is not, what is not longer needed, which versions of each. If you tamper with it, you are asking for trouble. If you do a manual upgrade, from sources, eventually a package upgrade will downgrade your version or some other application being incompatible will not work. And once you start throwing files in /usr, you start to ask for trouble. I’ve been using this type of operating systems for years and I’ve learned this by experience.

    (more…)
  • Ubuntu, like many other free operating systems, have a beautiful package management system that will track what depends on what, what is installed, what is not, what is not longer needed, which versions of each. If you tamper with it, you are asking for trouble. If you do a manual upgrade, from sources, eventually a package upgrade will downgrade your version or some other application being incompatible will not work. And once you start throwing files in /usr, you start to ask for trouble. I’ve been using this type of operating systems for years and I’ve learned this by experience.

    Nevertheless you, as I, want to try and code with Rails 2, right? Well, this is how I installed it in my Kubuntu box (should work the same for any Ubuntu and Debian derivate as well as others). I’ve decided to install everything on /opt/rails. I like to keep more-or-less self-contained directories in /opt. So I started with:

    (more…)