Reconnect your BackgrounDRb database sessions

November 11th, 2007

I ran into a problem with my BackgrounDRb scheduler last night: The MySQL server had to be restarted, and the scheduler got confused because its connection had gone away. By default, a BackgrounDRb worker will not reconnect to its database unless you explicitly tell it to do so. Here's how you can do that.

Read the rest of this entry »

BackgrounDRb Notes

August 12th, 2007

UPDATE: Since this post, a new version of BackgrounDRb has been released, and as such, some, if not most or all of this information should be considered outdated. Unfortunately, I haven't had a chance to check out the new version, but I'll update this page if I end up installing it.

BackgrounDRb is a great Ruby-based scheduler, but its documentation isn't quite as mature as I'd like, so I wanted to jot down some notes to help anyone who's been trying (and possibly failing) to get everything working correctly.

Note #1: You may create a file called config/backgroundrb_schedules.yml to set up default schedules when your BackgrounDRb service starts. This is not to be confused with the -c command-line switch, which is meant to point to the location of your backgroundrb.yml file (its default location is config/backgroundrb.yml).

Note #1a: If you choose to create the above-mentioned YAML file, its format might confuse you a bit, if you're accustomed to Rails' database.yml file or its fixture YAML files: You must prepend each line (except schedule names) with a colon, since BackgrounDRb accesses its YAML variables through symbols. For example:

# The following line should NOT be prepended with a colon (schedule name)
my_worker:
  # Each value inside our my_worker key SHOULD be prepended with a colon
  :class: MyWorker
  :job_key: :my_worker_key

Note #2: If you would like a schedule to repeat at a certain interval, include the :repeat_interval key beneath your :trigger_args parameter (you can't use this parameter with the :cron_trigger trigger type because repeat intervals are built into the cron structure). If you're using a YAML configuration file, it will look something like this:

my_worker:
  :class: MyWorker
  :job_key: :my_worker_key
  :worker_method: :do_work
  :trigger_args:
  :repeat_interval: 2.minutes

The :repeat_interval parameter accepts an integer, in seconds. Since BackgroundDRb is a Rails plugin, you can freely use Rails' time methods (seconds(), minutes(), hours(), etc.) to better format your number. The current (as of August 13, 2007) BackgrounDRb documentation describes :repeat_interval at times, and :interval other times. Setting the :interval key will do nothing.

Note #3: Any call to the logger object from within your workers gets put, by default, into logs/backgroundrb.log. All server calls (startup messages and trigger executions) get logged to logs/backgroundrb_server.log. This may seem trivial, but you could be racking your brain wondering why your worker isn't properly logging its responses. It most likely is, but maybe not in the log file at which you are looking.

Note #4: The BackgrounDRb documentation chooses to access worker classes by their underscored symbol variants (e.g., the MyWorker class would be referenced as :my_worker). You can choose to access your workers by their true class names (e.g., MyWorker) for verbosity's sake.I may add more notes as I come across other gotchas. Check back occasionally for updates.

Singleton can't be dumped

August 12th, 2007

I ran into a new error today, and after digging around my code for a bit, I figured out what was going on. I have an after_filter in my ApplicationController called set_last_url. It came from the session handling code in active_record_store, and its contents look like this:

class ApplicationController < ActionController::Base
  after_filter :set_last_url

  def set_last_url
    session[:last_url] = params
  end
end

For normal purposes, this method should be fine. Its purpose is to capture the last place you visited, and redirect you back after logging in or creating a new account. However, the params hash doesn't always contain information you'd like to store in the session object. In my case, it was an uploaded file. Here is the error along with a snippet of the backtrace:

Processing ItemsController#create (for 127.0.0.1 at 2007-08-12 16:09:38) [POST]
Session ID: 7797d006f6d7668e81a16564043e064f
Parameters: {"action"=>"create", "list_id"=>"1", "controller"=>"items", 
             "item"=>{"name"=>"Futurama", "price"=>"1.00", "url"=>"http://www.futurama.com", 
             "description"=>"DVD Set", "image"=>#}}

TypeError (singleton can't be dumped):
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/session/active_record_store.rb:83:in `dump'
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/session/active_record_store.rb:83:in `marshal'
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/session/active_record_store.rb:135:in `marshal_data!'
    …

I had two options that became readily apparent: I could change my code such that I only store the controller, action, and possibly ID parameters into the session object. Unfortunately, sometimes I add parameters to the end of my query string, and I don't want to omit them from the redirect URL. The other option was to act on the request method, which is what I ended up doing. In practice, I realized I didn't need to set the last URL after calls that were anything except GET, so I edited my filter definition a bit:

class ApplicationController < ActionController::Base
  after_filter :set_last_url

  def set_last_url
    session[:last_url] = params if request.get?
  end
end

No more error!

Save vs. Save!

August 8th, 2007

When learning about ActiveRecord objects, two methods usually taught are ActiveRecord::Base#save and ActiveRecord::Base#create. For beginners–especially those new to Ruby as a language–these methods are fine and unobtrusive. I'm finding myself using their counterparts, ActiveRecord::Base#save! and ActiveRecord::Base#create!, respectively as time goes on, for a few reasons.

First, a bit of an explanation of what the exclamation mark at the end of a method tells you, since it's generally different in Ruby and in ActiveRecord. In general, when talking about built-in Ruby methods, the exclamation mark tells you, "This method will return the object it was passed, edited in place." Take this example:

>> str = ' A phrase with spaces '
=> " A phrase with spaces "
>> str.strip
=> "A phrase with spaces"
>> str
=> " A phrase with spaces "
>> str.strip!
=> "A phrase with spaces"
>> str
=> "A phrase with spaces"

The String#strip method removes leading and trailing spaces from a string and returns the edited string, without editing the string object itself. Conversely, the String#strip! method also removes leading and trailing spaces from a string, but it also edits the string object itself, then returns it. You can see that subsequently displaying the str object after the call to str.strip! returns the stripped string; the string object has been edited and saved, as opposed to just edited and returned, with str.strip.

ActiveRecord handles the exclamation mark differently than Ruby, generally speaking. When we think of methods with an exclamation mark at the end in methods such as ActiveRecord::Base#save! and ActiveRecord::Base#create!, what we are told is, "Try to save or create this ActiveRecord object, but if you can't for some reason (usually validation), raise an exception." In contrast, the ActiveRecord::Base#save and ActiveRecord::Base#create methods will return true if the object was successfully saved or created, and false if not.

Why would you choose to have ActiveRecord raise an exception when trying to create an object? Here are a couple reasons:

  • Using a Rails plugin like exception_notification, you can be alerted by email if an object was not saved or created for some reason. If you have code that's silently returning false when trying to save an object, you might not notice an issue with your code. This can lead to database inconsistencies and unhappy users.
  • When testing, sometimes you have a method handle a lengthy process, such as importing a record from an external source, massaging the data, and creating various objects in the database to correspond with the incoming data. If any one of these things fails, your encapsulating method might not let you know, but if you're raising exceptions, you can do something like this:
assert_nothing_raised do
  Person.import_from_external_source
end

If anything fails, you'll get a test failure and you can delve deeper into your code to figure out what's going wrong.

I use ActiveRecord::Base#save! and ActiveRecord::Base#create! when I want to make sure an object will be created, and their non-exclaiming counterparts when it's not critical that the records be updated or created (e.g., if we're importing data for an existing person and an "Email" record already exists for the person for the specified email address, we can just test for failure based on our validations and move on, without re-importing the record).

Rescue your ActionView helpers

July 27th, 2007

Exceptions help us check for specific places where our code might throw a specific error, but they're also extremely handy when used in the general sense, in combination with the rescue keyword. In views, or any place you regularly throw around ActiveRecord associations, there is a lot of error checking to be done that might not always get caught. Rescuing a general exception in these cases can be very helpful. My problem was view code…

For a long while, I was plagued with view code that might fail if the associations tied to a particular object on which I was working were nil. Take this code, for example:

<!– people/index.rhtml –>
<%= h @person.name %><br />
<%= h @person.company.name %><br />
<%= h @person.company.ceo.phone %><br />

In a perfect world, all of these associations will exist, and the code will spit out exactly what it needs to. Unfortunately, sometimes, through data validation errors or in cases where the data just doesn't come over (say, when working with external systems), you're going to get exceptions. If the @person object exists, but the @person.company association does not, the second and third lines will fail. If the @person.company object exists but the @person.company.ceo association does not, the third line will fail. How do we check against this? Here's one way:

<!– people/index.rhtml –>
<%= h @person.name %><br />
<%= h @person.company.name if @person.company %><br />
<%= h @person.company.ceo.phone if @person.company && @person.company.ceo %><br />

As you might imagine, this code can get unmanageable very quickly. Here's a better way, through the use of helpers and the rescue keyword:

# people_helper.rb
module PeopleHelper
  def show_company_name(person)
    return h(person.company.name)
  rescue
    return ''
  end

  def show_ceo_phone(person)
    return h(person.company.ceo.phone)
  rescue
    return ''
  end
end
<!– people/index.rhtml –>
<%= @person.name %><br />
<%= show_company_name @person %><br />
<%= show_ceo_phone @person %><br />

Now, if either the company or the ceo associations do not exist, Ruby will throw an exception. This exception is rescued by our helper methods and an empty string will be returned. Our view is cleaner and more maintainable, and we can rest easy knowing that if for some reason we have a nil object somewhere in our expression, we'll safely catch it.

Easier Association Proxies

May 2nd, 2007

A few months ago, I wrote about association extensions and how to create more dynamic finders from your associations. While this method is nice, there are other ways to offer the same/similar functionality while inheriting a bit more functionality.

Read the rest of this entry »

Overriding ActiveRecord's attribute accessors

April 17th, 2007

I sometimes create database columns with the intent of having comma-separated values as their contents; a common occurrence is for email recipients. Having a comma-separated list of recipients in my interface, however, isn't really the way I'd like to display the column's contents. When I'm working with multiple values in my views, I'd much rather have an array. By overriding ActiveRecord's default accessor for the column, we can convert the string into something more flexible on the interface side.

Read the rest of this entry »

Inline ERB templating — for free

February 28th, 2007

I needed to support an email templating system in the project I'm working on, but creating my own seemed like a pain, especially with so many templating systems out there. I looked at Liquid (the templating system used by Mephisto) and eRuby, but ultimately, the answer was right under my nose the entire time…

Read the rest of this entry »

Extending render with a collection

February 22nd, 2007

Partials offer a lot in the way of cutting out common code, especially when you couple them with a collection of objects. Take this code, for example:

<% for item in @items -%>
  <%= render :partial => "item", :locals => { :item => item } %>
<% end -%>

While pretty nice, Rails has an easier way to do it, with the :collection option:

<!– items/list.rhtml –>
<%= render :partial => "item", :collection => @items %>

<!– items/_item.rhtml –>
<div class="item">
  <%= h item.name %>
  <%= h item.description %>
</div>

Now that looks pretty sweet. Rails automatically takes the name of your partial and adds a local variable by the same name, setting its value to the current iteration through our collection. But… we've got a visual problem with our page. We have the margin-bottom CSS attribute on all div objects in the class item set to 1em. For the last item in the collection, we'd like to make the margin 0, to get rid of extra space. Rails gives you one local variable for free when you render a collection of partials, called {partial_name}_counter. In this case, the name of the counter would be item_counter and it would give you the index in the array for the current item being rendered. Using this variable, you could, in theory, do something like this in your partial:

<!– items/_item.rhtml –>
<div class="item<%= " last" if item_counter + 1 == @items.size %>">
  <%= h item.name %>
  <%= h item.description %>
</div>

That's nice, but it's also pretty ugly. Also, what if you're rendering that partial in another view and you have not declared the @items variable? It's time to add our own auto-generated local variable to the render method. We're basically going to copy and paste Rails' default ActionView::Base.render method, but with one addition. You can put this code in your environment.rb file, if you'd like:

module ActionView
  class Base
    def render(options = {}, old_local_assigns = {}, &block)
      if options.is_a?(String)
        render_file(options, true, old_local_assigns)
      elsif options == :update
        update_page(&block)
      elsif options.is_a?(Hash)
        options[:locals] ||= {}
        options[:use_full_path] = options[:use_full_path].nil? ? true : options[:use_full_path]

        if options[:file]
          render_file(options[:file], options[:use_full_path], options[:locals])
        elsif options[:partial] && options[:collection]
          # This line is what we're concerned with. Note the addition of the 'last_item' local variable.
          render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals].merge(:last_item => options[:collection].last))
        elsif options[:partial]
          render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals])
        elsif options[:inline]
          render_template(options[:type] || :rhtml, options[:inline], nil, options[:locals] || {})
        end
      end
    end
  end
end

Now we get a local variable, for free, called last_item that we ca n use in our view to test for the last item in the collection:

<!– items/_item.rhtml –>
<div class="item<%= " last" if item == last_item %>">
  <%= h item.name %>
  <%= h item.description %>
</div>

Obviously we can name the variable whatever we'd like, in case you happen to have a conflicting local variable called last_item. You could prepend the name of the partial to the variable name just to be safe, but I don't mind it, so I'll leave it as it is.

Implicit exception handling

February 15th, 2007

Ruby does a fantastic job of making code look good, and today's tip is no exception, pun intended. Take this code, for example:

def delete_items(ids)
  begin
    # This could fail if any of the IDs were not found
    items = find(ids)
    items.each do |i|
      i.parent.log("Deleted #{item.name}")
      i.destroy
    end
  rescue
    return false
  end

  return true
end

While a simple example, it gets the point across. But the begin/rescue control loop has a few tricks up its sleeve, namely else and ensure. Adding an else into exception handling code will do just what you would expect: get run in case no exception was thrown. The other term, ensure denotes a block of code that will be run regardless of whether an exception was thrown or not. What we want to focus on here is the else clause, because Ruby has an implicit begin at the beginning of a method, which cleans up our code a tiny bit–but enough to make it worth doing, in my opinion:

def delete_items(ids)
  # This could fail if any of the IDs were not found
  items = find(ids)
  items.each do |i|
    i.parent.log("Deleted #{item.name}")
    i.destroy
  end
rescue
  return false
else
  return true
end

Looking good, Billy Ray.