Thursday, August 23, 2012

A JRuby, Rails, RSpec, Spork, and an error walk in to a bar...

I was running a specific rspec over and over during a tight development cycle. The way our system was set up it was taking 30+ sec to run a single spec file, which made running them onerous.

We had Spork running at one point, but it wasn't working for me, with a "undefined method 'flush' for nil:NilClass" error (and a couple of others depending on the incantation):

After upgrading Spork (we had been running an older version), setting the JRUBY_OPTS environment variable, and restarting Spork, the spec time dropped to ~8 sec. Still not particularly fast, but faster-enough to make it worth it.

Not currently running Guard. Not sure if the upgrade or opts made it start working.

This post is a work-in-progress.

Wednesday, August 08, 2012

RSpec Error With Implicit Subject

Ever write a trivial spec like this:

And get something totally baffling back, like this?

Backstory: Refactoring some pre-written classes to use metaprogramming to create some methods and values. I wanted specs in place before starting the metaprogramming to avoid breaking things.
In retrospect, I should have figured this out sooner. In my defense, I love the Olympics and was distracted. The constructor of the model gives it away:

A parameterized constructor, no default value: rspec couldn't instantiate the implicit subject.

Silly mistake, exacerbated by magic, hidden functionality–it's one of the greatest things about Ruby, but can occasionally lead to opaque behavior, especially during the Olympics.

Saturday, November 12, 2011

Testing singletons while avoiding their constructors

Singletons are evil, and here's why.

Fair enough. Yet they exist, and they're not intrinsically evil--just misused. Can we mock enough to make testing them feasible? Yep, and here's a Contrived Example™ that shows how (and why we might want to).

"Embedded" singletons or utility classes can make testing is problematic. Injected singletons are different; then it's an issue of whether or not it should be a singleton at all--different discussion.

"Embedded" singletons look like this. (Utility classes are essentially the same, minus an instance.)


Let's say (a) we need to test this code, (b) we cannot modify this code, and (c) the singleton's constructor is long-running, but required for fetch() execution. For testing, then, we need to (a) avoid the constructor for speed reasons, and (b) mock the fetch() method to return known data for the test. We can't just mock fetch(), because the constructor would still run.

Here's our (contrived) singleton class; we sleep() in the constructor to pretend it's doing something interesting like caching data from a web service, to be returned by fetch().


The undecorated test does what you'd expect, and takes as much time as you'd expect.


Now, with a combination of PowerMock and EasyMock, we'll put the kibosh on that, eliminate the constructor, and return the data we want. (PowerMock sits on top of EasyMock or Mockito. (Both are great, although I tend towards Mockito.)


Most of the test class is self-explanatory. The nutshell version is that we annotate the test class itself and tell it to run with the PowerMock runner (@RunWith), and that we're going to be messing with LongRunningCtor's innards (@PrepareForTest).

Inside the test itself, we tell it to suppress LongRunningCtor's constructor (before mocking, otherwise the constructor will fire during the createPartialMock() call). We also prepare for mayhem by calling mockStatic(). (This mocks all the class's static methods; we could also choose specific static methods to mock using mockStaticPartial().)

Our test now takes a fraction of the time because we're skipping the slow constructor, and our mock returns known data so we can exercise only the calling code.

Ideally, code is structured so this kind of byte-code treachery is unnecessary--it's a great reason for dependency injection/inversion of control. In the real world, technical and timing constraints don't always allow the kind of restructuring we'd like.

With the aid of some tools that do the low-level dirty work for us, we have a relatively clean way to work around some types of system limitations, and still write tests that can execute quickly.

The gist used in this post also includes the relevant Maven dependencies.

Thursday, November 10, 2011

A trip to the Rake-track.

(Because it's like "racetrack", and it makes Rake tasks faster, and... oh, never mind.)

Tired of waiting for Ruby to spin up just so you can run a "routes" command, or your latest "db:migrate"?

Use rake-sh and start up a rake console for running tasks without the initial spin up. It'll take a "rake routes" from four seconds down to under a second. Rake task completion? Naturally. Use "t" for tasks, "! " (note there's a space after the bang) to run a shell command.

If you get a message about an "uninitialized constant Rake::DSL" when you run rake-sh, no sweat: add require 'rake/dsl_definition' to the top of your Rakefile.

Breaking flow sucks for developers: a few seconds doesn't sound like much. In actual time, it isn't much--but it's the distractions that kill, the times-between-doing. Keep them to a minimum by fully exploiting your tools.

Thursday, September 15, 2011

Rails 3 Custom Validator Quandary -- Solution Step One

Remember when I had a Rails 3 custom validator quandary? My bottom-line question was "how should I access a specific error condition, cleanly, in both an action, and a template?" I sketched a few solutions, ranging from checking for a specific error message to providing a function that indicates if the error has occurred.

For now, I want simple boolean methods on the model to encapsulate the error condition. I don't want to write them by hand; I want the validator itself to dictate the interface. For example, if I'm validating an "email" property that can only repeat n times on a given day, I'd like to have an email_repeats_error? method available in the model, returning what we'd expect.

This will be developed in two steps: first, as a simple library (makes tweaking easier, at least for me). Second, as a standalone gem (the way it should be). Naturally, this led to a brief WTF spike as I couldn't figure out how to get the library to expose the validator properly.

Loading the Library

Rails 3.0 changed how libraries are loaded, at least a little bit. I did two things to get things loading from an arbitrarily-named file in the /lib directory. First in my application.rb file, I added the /lib directory to the autoload path.

module RepeatsValidatorWork
  class Application < Rails::Application
    config.autoload_paths += %W(#{config.root}/lib)
    # auto-require; see next code fragment.
    # ... etc ...

Second, I require the library manually since... well, I'm not 100% sure I understand why, although this blog entry pointed me in the right direction. For testing purposes, this is fine--it might not be a great idea in general. Once it's in a gem, it won't matter anyway.

    config.autoload_paths.each do |path|
      Dir["#{path}/*.rb"].each do |file|
        puts "Auto-requiring #{file}..."
        require file
      end
    end

The Validator Proper

We'll work a bit backwards to get to the final implementation--starting with the familiar and common, ending with tasty snacks.

I'd like to configure the validator as below. For now, we'll just use a lambda to determine how to count the repeats--in the future we might want shortcuts for common use cases. All mine have been different so far, so a lambda it is. We'll pass it the same things a custom validator normally gets (see next code block).

class Item < ActiveRecord::Base
  validates :name,
            :presence => true,
            :repeats => {
              :upto => 2,
              :how_count => lambda { |rec, attr, val|
                Item.count(:conditions => ['name=?', val])
              }
            }
end

The validator is an ActiveModel::EachValidator subclass. We'll save the "upto" and "how_count" options in the class's initialize method. Since we'll care which model attributes are using the validator, we'll save that before calling super: Rails initializes that option, and plucks it out again in the base class. If we want 'em, we gotta act fast.

      def initialize(options)
        @attributes = options[:attributes]
        super
        @how_count = options[:how_count]
        @upto = options[:upto]
      end

The validate_each method uses a saved copy of the "upto" option, runs the "how_count" lambda, and compares the values.

      def validate_each(record, attr, value)
        err = false
        if @how_count.call(record, attr, value) >= @upto
          record.errors[attr] << (options[:message] \
                                  || "repeats too much")
          err = true
        end
        record.instance_variable_set \
            "@#{attr}_repeats_error", err
      end

The last line of the method is important: it sets an instance property to true or false depending on whether or not we had a repeats violation. Now we just need to access that in an attribute-specific method for every attribute that uses this validator.

The final bit of pseudo-magic occurs in our class's setup method. Turns out that Rails validation internals call a setup method in each of the registered validators that defines one. (Discovered while looking through Rails source--I can't emphasize the usefulness of reading through source code.) The argument is the class of the model--if that sounds handy, you're on to something.

      def setup(clazz)
        clazz.class_eval @attributes.inject("") {|s, attr| s += <<END
          def #{attr}_repeats_error?
            @#{attr}_repeats_error
          end
END
      end

This code is less-dense than it seems (it seems dense to me, I guess). In a nutshell, we're looping over our saved attributes (in @attributes) and using inject to build up a string containing everything between the two upper-case ENDs (except for the closing bracket). (Didn't know that was legal syntax.) If it makes it easier to visualize, think of it like this:

      def plain_ol_setup(clazz)
        s = ""
        @attributes.each do |attr|
          s += """
          def #{attr}_repeats_error?
            @#{attr}_repeats_error
          end
          """
        end
        clazz.class_eval s
      end

If it didn't make sense before, does it now? We're adding a method

The only thing left to do is to tell Rails that our validator is alive and we wants me some; this is just a single line at the bottom of our library file. (The validator code above lives in some nested modules.)

ActiveModel::Validations.__send__(:include, Newton::Validator)

Here's the complete code in a gist (also appended at the bottom of the post).

So, does it work?

pry(main)> i = Item.new(:name => 'wat!')
=> #
pry(main)> i.name_repeats_error?
=> nil

Huh? Oh, right--the model hasn't been validated yet. Remember, as it stands right now, the method is added during validation.

(This may be a Bad Idea--it might be better to add the method to the model in some other way, but unless we add it manually, or add it to all our models, create a method our models can use to get the method from the same module our validator is in, or...? this (for now!) seems the way most-tied-to-the-validator, which was one of the things I wanted.)

We'll use create instead for illustration and keep creating items with the same name. Once we have two with the same name, additional items with the same name should have a validation error.

pry(main)> i = Item.create(:name => 'wat!')
=> #<Item id: 7, name: "wat!", ...>
pry(main)> i.name_repeats_error?
=> false
pry(main)> i = Item.create(:name => 'wat!')
=> #<Item id: 8, name: "wat!", ...>
pry(main)> i.name_repeats_error?
=> false
pry(main)> i = Item.create(:name => 'wat!')
=> #<Item id: nil, name: "wat!", ...>
pry(main)> i.name_repeats_error?
=> true

That, as they say, is that.

For now.

Tuesday, September 06, 2011

Simple Ajax property toggle in Rails 3.0

Entry-level overview of one way to add trivial Ajax functionality to a Rails 3.0 app, originally written for a specific audience. The repository is on github.

Let's say we have an Article model with an "approved" flag. We need to be able to toggle this flag. Normal scaffolding would have us view the article, click a checkbox, and submit. We'll keep that functionality, but add a simple Ajax-based toggle on the articles index page.

Model Generation
rails g scaffold Article name:string approved:boolean

Original Model Index View

The default scaffolding includes the following chunk, repeated for each article.
 <td><%= article.name %></td>
 <td><%= article.approved %></td>
  ...

An Approving Helper
"True" and "false" are a yucky user experience, what we really want is "approved" and "un-approved". We'll think ahead, and turn it instead into text suitable for a command link. We could also use images, but we'll stick with text for now.
def approve_link_text(approvable)
  approvable.approved? ? 'Un-approve' : 'Approve'
end

Two quick things about how this was written.

1) It's not tied to articles; it'll quack at anything with an "approved?" method.
2) The parameter is named something that provides a hint to future devs, more useful in an IDE that provides popup help.

Add a Method to the ArticlesController to Toggle Approval Status
Two-step process: first, add a method to the articles resources routing.
resources :articles do
  get 'toggle_approve', :on => :member
end

Then the method itself (this is not the final version).
def toggle_approve
  @a = Article.find(params[:id])
  @a.toggle!(:approved)
  render :nothing => true
end

Update the Template
Our first step will just toggle the attribute without any feedback. It's actually a one-liner, just make the true/false "approved" text from before be a link to our new action.
<%= link_to approve_link_text(article), 
            toggle_approve_article_path(article), 
            :remote => true %>

The :remote => true turns it into an Ajax request. Not too shabby.

If we refresh the page after clicking the link we'll see that the text has changed. Approved articles will have an "Un-approve" link, un-approved articles an "Approve" link. Clicky-clicky, it does what we expect.

But refreshing is deeply unsatisfying.

Dynamic Feedback, Part 1

Remember when fadey-yellow things were cool? Yeah, we're all about that.

In order to change stuff on our page, we have to be able to access the appropriate DOM elements. Let's say we'd like to highlight the entire row when we toggle an article's approval status, and change the link text.

We'll use "article_n" for the article rows, and "approval_link_n" for the links.

<% @articles.each do |article| %>
  <%= article.name %>
    <%= link_to approve_link_text(@article), toggle_approve_article_path(@article), :remote => true, :id => "approve_link_#{@article.id}" %>

Dynamic Feedback, Part 2

Now we can access the DOM elements we care about on a per-article basis. How do we make them change? By creating a JavaScript template for our action, just like we usually create HTML templates. Rails will execute the returned JavaScript. The JavaScript template can contain ERb constructs, also just like HTML templates.

Note that some people don't like creating JavaScript this way. An alternative is to create DOM elements that our JavaScript can pull from. That's fine, but honestly, for simple things like this, I don't have a big problem with doing it the "old-fashioned way".

Our action is called "toggle_approve". We name JavaScript templates the same way we do ERb templates, so we'll create a toggle_approve.js.erb.
$("#approve_link_<%= @article.id %>").text("<%= approve_link_text(@article) %>");
$("#article_<%= @article.id %>").effect("highlight");

Line 1 sets the link text to Approve/Un-approve using the same helper we used in the HTML template.
Line 2 highlights the row we just updated.

That's it--we no longer have to refresh our page--the text of our link changes after the property is toggled, the row is highlighted, and we're all set!

Monday, September 05, 2011

Example app test failures from authlogic user sessions

This question on stackoverflow led me to believe that if I actually ran rake test that my example app's tests would fail--and they did, with the same error. (Why I wasn't running tests from the beginning? Meh!) The tests throw up wads of stack trace, headed with this:

SQLException: no such table: user_sessions: DELETE FROM "user_sessions" WHERE 1=1

What's causing this error? We created our user session object like this:

rails g authlogic:session UserSession

Unfortunately, this created a fixture file as well. During testing, fixture files normally map to tables, from which all data is deleted before subsequent reloading of the fixture.

But authlogic user sessions aren't ActiveRecord models, they're AR-like, and are actually authlogic-derived classes. No table: they serve as a link between users (which are in a table) and their authlogic sessions. My takeaway? Authlogic sessions should be created without a fixture file.

rails g authlogic:session UserSession --skip-fixture # Or --fixture=false

The file has been removed from the example app's github repository.

Two other minor changes were made to get the tests to pass (w/o any care to what they're testing). First, the user fixture file was tweaked (replace the old "login" property with the new "nickname" property, make the persistence tokens unique). Second, the HomeControllerTest stub was tweaked to expect a 302 when hitting the index page, which is the redirect encountered when the user isn't logged in.