Adam MilliganAdam Milligan
Rake test error due to --trace argument
edit Posted by Adam Milligan on Friday October 31, 2008 at 06:10PM

We've had some trouble with test task errors causing failing builds on our continuous integration boxes ever since the release of the version 0.8.3 rake gem. Sound familiar? Read on!

Rajan AgaskarRajan Agaskar
Standup 10/31/08
edit Posted by Rajan Agaskar on Friday October 31, 2008 at 04:27PM

Interesting Things

  • Aliasing ActiveRecord reader methods

    ActiveRecord reader methods are not eagerly loaded, and as such cannot be aliased using alias_method. There are a number of workarounds to this, those talked about included: calling self.define_read_methods, after which all your read methods will be loaded and available for aliasing, or you can simply define the alias instead of using alias_method.

  • belongs_to and foreign keys.

    If you specify an alternate foreign key when using belongs to, you will have access to that id via the name of the foreign key, and not the name of the belongs_to association. It may be worthwhile allowing access to the id via the belongs_to association in order to keep consistency.

  • boo

    BOOOO!!!!! BOOOOOOOOO!

Rajan AgaskarRajan Agaskar
Standup 10/30/08
edit Posted by Rajan Agaskar on Thursday October 30, 2008 at 04:17PM

Interesting Things

  • Removing class definitions with Object.send(:remove_const, :Foo)

Sometimes it is necessary to reload or replace a stub/test class during testing (apparently rspec is particularly susceptible to this). This can be achieved using Object.send(:remove_const, :Foo) where Foo is the camel-cased name of the class. If your class is defined within a module, it may be necessary to use Module.send(:remove_const, :Foo)

Ask for help

  • foo.bar.reload versus foo.bar(true)

As a point of curiosity, does anybody know when has_many relationship reloading moved from (or to?) foo.bar(true) to foo.bar.reload? The reload syntax seems preferable for readability; will foo.bar(true) continue to work in the future?

Josh SusserJosh Susser
Hacking a subselect in ActiveRecord
edit Posted by Josh Susser on Wednesday October 29, 2008 at 08:08PM

This week, Damon and I were doing a performance optimization for some slow queries. The most performant solution involved denormalizing some data into a join table and doing a subselect to get the ids of the records we wanted. Not rocket science, but also a bit ugly to construct the SQL by hand. Our solution was to cheat a tiny bit and use an ActiveRecord internal method to generate the SQL for us.

def favorite_posts(options={})
  subselect = Favorite.send(
                :construct_finder_sql,
                  :select => "post_id",
                  :conditions => {:blog_id => self.id},
                  :order => "published_at DESC",
                  :limit => options[:limit] || 10, :offset => options[:offset])
  Post.find(:all, :conditions => "posts.id IN (#{subselect})", :order => "published_at DESC")
end

That code uses the private method Favorite.construct_finder_sql to generate the following SQL:

SELECT * FROM posts WHERE posts.id IN (
    SELECT post_id FROM favorites WHERE blog_id = 42 ORDER BY published_at DESC LIMIT 10 OFFSET 10
  ) ORDER BY published_at DESC

The Ruby may look like more code than the SQL, and in that form it is... but if you go the hack up a string route, once you start using string operations or interpolation to deal with the variable parts of the query it gets ugly pretty fast. Using the ActiveRecord code to put it all together keeps it nice and clean, and even makes sure things are sanitized and quoted properly too.

Rajan AgaskarRajan Agaskar
Standup 10/29/08
edit Posted by Rajan Agaskar on Wednesday October 29, 2008 at 04:28PM

Interesting Things

  • has_many_polymorphs preloads models

has_many_polymorphs will scan through the models directory for any files that include the plugin and preload them. This can cause problems if these models depend on other plugins (that have not yet been loaded) to operate correctly. The has_many_polymorphs source mentions this behavior in a comment and includes a fix:

Searches for models that use has_many_polymorphs or acts_as_double_polymorphic_join and makes sure that they get loaded during app initialization. This ensures that helper methods are injected into the target classes. Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_polymorphs_options. For example, if you need an application extension to be required before has_many_polymorphs loads your models, add an after_initialize block in config/environment.rb that appends to the 'requirements' key:
  Rails::Initializer.run do |config|     
    # your other configuration here

    config.after_initialize do
      config.has_many_polymorphs_options['requirements'] << 'lib/my_extension'
    end    
  end

Instead of using config.has_many_polymorphs_options, we were able to achieve the same effect by simply dropping our required plugins into the after_initialize block. If we decide to remove has_many_polymorphs in the future, the config file should still run correctly. It's worth noting that the UltraSphinx search plugin operates in a similar fashion.

  • returning JavaScript in an Ajax IFrame Method (AIM) call

If you are using AIM for file uploads, you may find that any content returned to the IFrame is escaped (as if it were regular HTML). On some browsers, this occurs regardless of what the content-type is set to. A workaround is to embed any content that you don't want escaped into a comment tag; after the request completes, you can use JavaScript to retrieve the contents and optionally eval them.

Ask for help

  • Ajax click_and_wait for Selenium?

assert_text_present offers a simple way to test Ajax behaviors in Selenium, as it will wait 5 seconds (during which the Ajax callback can complete) while looking for the specified text (which can be the body of your Ajax response). Another strategy with which we've had some luck is to write a custom method that will wait a specified amount of time before continuing (particularly useful if your Ajax call takes a lengthy amount of time to complete).

Mike GraftonMike Grafton
New York Standup 10/29/2008
edit Posted by Mike Grafton on Wednesday October 29, 2008 at 01:59PM

Interesting

  • Until a recent commit, Polonium defined a method on Module named deprecate, which (at least in our case) overrode the method of the same name defined in Rails. This caused some code in Rails to blow up at class loading time when trying to call Rails' deprecate method with the wrong number of arguments.

    We changed the name of Polonium's method so it wouldn't clash with Rails, and checked this into the master branch of Polonium on GitHub.

  • As of Rails 2.1, ActiveRecord support partial updates, which means that it's smarter about what fields get updated in the SQL UPDATE statement issued by save. If you haven't updated any fields in the object, no update will happen at all, no AR callbacks will fire, etc. If you depend on these things to happen even when not updating any fields, you can call will_change! on the model object. It was floated that a force_save method might be helpful.

  • It is often claimed that Symbol#to_proc is to slow to use in production code. But a clever Rubyist out there found a way to speed it up by 4x.

  • The test run for one of our projects here runs in 223 seconds on OSX, but in in 157s on Ubuntu. We'd like to figure out why (we're pretty sure we're using the MySQL Gem rather than the built-in MySQL driver that comes with Rails)

  • Git4Idea is now available through the IntelliJ Plugin manager. No more hand installation!

  • ActiveRecord::Base#to_param must return a String if you override it. If you return an Integer you will get a weird "Can't convert Fixnum to String" exception somewhere deep in the routing code. You can't even tell where the exception is coming from due to the routing code's bizarreness.

Rajan AgaskarRajan Agaskar
Standup 10/28/08
edit Posted by Rajan Agaskar on Tuesday October 28, 2008 at 04:44PM

Interesting Things

  • before_save and after_save may not perform as you expect!

Previously, returning false from before or after filters callbacks would halt the chain entirely. This is no longer the case, except with before_save and after_save -- returning false in a before_save will stop the filter callback chain and prevent a save, returning false in an after_save will stop the filter chain silently, and NOT rollback the save. This can be troublesome if you have after_save filters callbacks you expect to execute, especially if you have conditional clauses in an after_save, as they can easily return a false value where you did not intend it.

Please see Brandon Keepers' clarification regarding filters vs. callbacks below -- thanks Brandon!

Ask for help

  • Bootstrapping data into an existing system?

Using migrations for one-time data inserts can be problematic (for example, when changing seed data; additionally, it's advisable to create a database from the schema.rb rather than migrations) , it can be useful to create a class that is responsible for inserting the seed data into the database. This class can be wrapped in a capistrano or rake task. The db-populate plugin is designed to aid in this task.

  • Multiple Routes/One controller

It is possible to point multiple routes at a single controller, however, this situation may suggest a need for multiple controllers, possibly inheriting from a single base controller containing any shared logic. This prevents a excessive switching logic in controllers, which can help minimize the possibility of argument-related bugs.

Brian TakitaBrian Takita
RR 0.6.2 Released
edit Posted by Brian Takita on Tuesday October 28, 2008 at 06:07AM

This release features a sexier Double definition block syntax using instance_eval:

mock(User) do
  find(1) {user_1}
  find(2) {user_2}
end

RR also maintains its non-instance_evaled Double definition block syntax, if the block has an arity of 1:

mock(User) do |expect|
  expect.find(1) {user_1}
  expect.find(2) {user_2}
end

The instance_eval syntax is very useful in the context of Double Definition chaining:

mock.proxy(User).find(1) do
  mock.proxy! do
    blogs do
      mock.proxy!.find_by_id(2) do |actual_blog|
        actual_blog.name.should == "My ranty blog"
        actual_blog
      end
    end

    fans do
      mock.proxy!.thank_everybody
    end

    foes do
      mock.proxy!.ask_for_forgiveness
    end
  end
end

user = User.find(1)
user.blogs.find_by_id(2) # My ranty blog
user.fans.thank_everybody
user.foes.ask_for_forgiveness

Of course the previous example is a complicated case of interaction testing, and a simpler state-based and/or hybrid approach may be better, but it demonstrates how using instance_eval can promote readability.

Here is the non-instance_eval solution:

mock.proxy(User).find(1) do
  mock.proxy! do |expect|
    expect.blogs do
      mock.proxy!.find_by_id(2) do |actual_blog|
        actual_blog.name.should == "My ranty blog"
        actual_blog
      end
    end

    expect.fans do
      mock.proxy!.thank_everybody
    end

    expect.foes do
      mock.proxy!.ask_for_forgiveness
    end
  end
end

instance_eval Controversy

Ola Bini warned against overusing instance_eval. While instance_eval adds beauty, it can also make things more difficult to extend and debug.

In RR, the DoubleDefinitionCreatorProxy (the object that is instance_evaled when defining Doubles using blocks) uses the blank slate pattern, so arbitrary method names can be passed in to define the Double. The Blank Slate implies that the DoubleDefinitionCreatorProxy will not be extended with methods. James Earl Gray explains the pattern that I used for RR.

spec/test helper methods will not be usable within the instance_evaled blocks because the intent of the DoubleDefinitionCreatorProxy object is incompatible with the instance_eval with delegation pattern. DoubleDefinitionCreatorProxy already uses method_missing to create DoubleDefinitions. If you wish to use spec/test helper methods, you will need to memoize it to a variable and use lexical scoping.

Now, one may want to define a helper method in the test/spec that is returned when the Double is invoked.

describe User do
  describe "#fans.thank_everybody" do
    it "thanks all of my lovely fans" do
      user = User.new
      memoized_my_lovely_fans = my_lovely_fans
      mock(user) {fans {memoized_my_lovely_fans}}
      memoized_my_lovely_fans.each {|fan| mock(fan).thank_you}

      user.fans.thank_everybody
    end

    def my_lovely_fans
      [Fan.new, Fan.new]
    end
  end
end

While I think this will be a good addition to RR, I recognize that adding the instance_eval has the possibility of making RR less usable. I'll pay close attention to see how this pans out and am willing to remove it if there are major issues.

Steve ConoverSteve Conover
Better array assertions using collect
edit Posted by Steve Conover on Monday October 27, 2008 at 10:00AM

You could do this:

Person.tall_people.length.should == 3
Person.tall_people[0].should == people(:linda)
Person.tall_people[1].should == people(:dwane)
Person.tall_people[2].should == people(:rick)

This is better, because it's clearer, and because in one stroke you prove bounds, content, and order:

Person.tall_people.should == [
  people(:linda), 
  people(:dwane), 
  people(:rick)
]

I argue that this is best:

Person.tall_people.collect{|p|p.first_name}.should == [
  "Linda", 
  "Dwane", 
  "Rick"
]

Failures messages are a pleasure to read

  expected: ["Linda", "Dwane", "Rick"],
  got: ["Juliette", "Jeanne"] (using ==)

And code is clearer overall (the price is a "collect")

Collecting away from the original object (and into primitives) is not only clearer, in most cases your aim is not to re-prove that the element objects are fully and properly configured. You've already done that elsewhere. You only want to prove, in the simplest possible terms, that the group of things you got is what you expected to get.

Let's say you don't intend to care about order. Sorting on primitives is a snap:

Person.tall_people.collect{|p|p.first_name}.sort.should == [
  "Dwane", 
  "Linda", 
  "Rick"
]

Slightly more controversial:

Person.short_people.collect{|p|p.first_name}.should == []

The collect seems silly at first glance, but you're making present and future assertion failures much friendlier. You'll be happy about brain cycles saved and sanity kept during big refactorings.

Adam MilliganAdam Milligan
Standup 10/24/2008: Floating point number formatting and you
edit Posted by Adam Milligan on Friday October 24, 2008 at 05:58PM

Interesting Things

We have a project that generates a lot of highly precise floating point numbers. However, we primarily want to display these numbers with only two decimal places of precision. In addition, we want to display these numbers with standard comma delimiters to the left of the decimal point.

Sadly, the Ruby #sprintf method provides the former functionality, but not the latter. What to do? Use a Rails helper, of course.

The NumberHelper from ActionView provides some useful functionality, so we used that. As it turns out, we found the best way to get the formatting we want to be using the #number_to_currency function with no denomination.

Also, rather than mixing the entire helper into the Float class for just one method, we chose to mix the helper into a nested class and expose only the functionality that interests us. The result looks something like this:

class Float
  class RailsNumberHelpers
    extend ActionView::Helpers::NumberHelper
  end

  def formatted
    s = Float::RailsNumberHelpers.number_to_currency(self, :unit => '', :precision => 2).chomp('0')
  end
end

Other articles: