• Flash of Convenience

    Flash messages in Rails applications need a bit of love. A lot of them tend to be identical within a given app, and it’s a bit annoying to manage defaults and fallback for all these calls to I18n.t(). The following is a small helper-method and a simple structure to keep it all neatly organized.

    For this to work, add the text you want shown to your config/locale/en.yml (by default):

    en:
      posts:
        create:
          flash:
            created: "Your post will now be reviewed before publishing"
    
      flash:
        created: "Successfully created"
        updated: "Successfully updated"

    Here the posts#create action has a custom flash for the :created flash-message. All other controllers and actions in the application where a flash-message of :created is used the default message of "Successfully created" will be shown.

    Next, add this to your ApplicationController (this is all of the magic):

      protected
      def flash_message cause, args = {}
        primary_key = "#{controller_name}.#{action_name}.flash.#{cause}"
        default_key = "flash.#{cause}".to_sym
        I18n.t primary_key, args.merge(default: default_key)
      end

    Finally, this is how you use it within an action:

      flash[:notice] = flash_message(:created)
      # and
      redirect_to :root, notice: flash_message(:created)

    Try to keep the actions somewhat generic like :created, :deleted, :updated, etc. This makes the default values easier to manage.

    What just happened?

    The I18n system has some neat convenience shortcuts we’re using here. First of all we build the primary flash lookup-key based on the current controller and action.

    Second bit of functionality used here is the fallback message. Fallback messages can be given as an explicit string, or a symbol. When a symbol is used it will be used to lookup a new message in the I18n backend. We use that for the :default argument where the fallback is set to be a global flash message like flash.created.

    Now you can customize all the flashes in your app without touching the code, you have all these small bits of user interface in a single file for easy overview. You can also easily vary the messages between languages, customize text where it is necessary, and have a convenient global fallback message.

  • Getting to know Ruby debugger

    This is a guest-post by Cameron Dykes, about getting started with the ruby debugger.

    A key step to debugging any program is replicating the environment to ensure you can consistently produce the bug. In my early Ruby days, to inspect the environment, I used a primitive method: placing puts lines in my code to print values to the console (let’s call them “inspection puts”).

    It may have looked something like this:

    class Buggy
      # assuming perform_operation and special_options exist...
      def buggy_method(param=nil, options={})
        puts "\n\n\nDEBUG"
        puts "param: #{param}"
        puts "options: #{options}"
        @instance_var = perform_operation(special_options(param, options))
      end
    end

    The case for ruby-debug

    This method very easily gives me the information I need, but it has some downsides:

    1. To inspect the return value of special_options I have to add another inspection puts.
    2. Every addition of a new puts requires that I restart the application to inspect the results.
    3. To inspect how special_options and perform_operation are handling the data, I have to add inspection puts inside of them.
    4. I must remember to remove all of the inspection puts before I push the code.

    If only there was a better way to do this.

    ruby-debug to the rescue! By putting a breakpoint in our code, we have the ability to inspect environment state, check the return value of any methods, and step through our code one line at a time. This is much more versatile than inspection puts because the full environment is available to us. The “I wonder what the value of this is” problem is gone since we can inspect whatever we want. The step functionality the debugger gives us is useful as well, allowing us to step inside of a called method while maintaining the interactive environment.

    Setting up ruby-debug

    To get set up with the debugger, we’ll need to install the gem:

    # Using MRI-1.9.2
    gem install ruby-debug19
    
    # Using MRI-1.8.7 or Ruby Enterprise Edition
    gem install ruby-debug

    ruby-debug in action

    Let’s update the example from above using a debugger breakpoint instead of inspection puts:

    class Buggy
      # assuming perform_operation and special_options exist...
      def buggy_method(param=nil, options={})
        require 'ruby-debug'; debugger
        @instance_var = perform_operation(special_options(param, options))
      end
    end

    The next time the method is called, the debugger will stop and give us an interactive shell. We can inspect the values of each variable with the eval command:

    eval param
    eval options

    We can also see what the return value is of the invoked methods:

    eval special_options(param, options)
    eval perform_operation(special_options(param, options))

    We can even use the step command to enter inside of special_options and perform_operation to see what they do.

    Here are the various debugger commands that I most commonly use:

    • list, l - show the code for the current breakpoint
    • eval, e - evaluate expression and print the value
    • step, s - next line of code, moving within methods
    • continue, c - continue in the program until the program ends or reaches another breakpoint
    • quit, q - abort the program

    Many more commands are available, which can be seen by entering help in the debugger.

    Better debugging ftw!

    With the ruby-debug gem, we have a better tool for diving in to our code than inspection puts. Using a debugger breakpoint, we can interactively step through our code with less cleanup.

    Happy debugging!

    Debugging references

    Who am I?

subscribe via RSS