Adventures with Ruby

Basic Named Scopes

View Comments

Cal it tiny, I don’t care. I’ve made a gem named BasicNamedScopes.

Basic Usage

I was fed up with writing:

Post.all(:conditions => { :published => true }, :select => :title, :include => :author)

So with BasicNamedScopes, you can now write:

Post.conditions(:published => true).select(:title).with(:author)

All named scopes are called the same, except for include, which is now called with, because include is a reserved method.

Reuse them by making class methods:

class Post < ActiveRecord::Base
  def self.published
    conditions(:published => true)
  end

  def self.visible
    conditions(:visible => true)
  end

  def self.index
    published.visible
  end
end

Also, the all-method is a named scope now, so you can chain after callling all, for greater flexibility.

Post.all.published

Arrays can be used as multple parameters too, sparing you some brackets.

Post.with(:author, :comments).conditions("name LIKE ?", query)

The read_only and lock scopes default to true, but can be adjusted.

Post.readonly         # => same as Post.all(:readonly => true)
Post.readonly(false)  # => same as Post.all(:readonly => false)

Why?

NamedScopes are really handy and they should play a more central theme in ActiveRecord. While I heard that Rails 3 will support similar syntax, there is no reason to wait any longer.

I find defining named scopes very ugly, especially when dealing with parameters. Just compare the amount of curly braces!

# Using normal named scope:
named_scope :name_like, lambda { |query| { :conditions => ["name LIKE ?", query] } }

# Using BasicNamedScopes
def self.name_like(query)
  conditions("name LIKE ?", query)
end

Also, regular named scopes don’t support using other named scopes at all!

I found myself implementing these named scopes (mostly conditions, but others too) so often, that a little gem like this would be the obvious choice. Use it if a gem like searchlogic is overkill for your needs.

Installing

The gem is called “basic_named_scopes”. You know how to install it.

gem install basic_named_scopes

Use it in Rails:

config.gem "basic_named_scopes"

Update

The syntax is fully compatible with ActiveRecord 3, and if you’re using ActiveRecord 3, you don’t need to use this gem.

Written by Iain Hecker

December 22nd, 2009 at 6:26 pm

Posted in iain.nl

Cucumber 0.5 and my little commit

View Comments

The strangest thing happened to me this week. I was working on a little side project at work. It seemed like a nice time to try out some new gems (Bundler and Devise: love it! InheritedResources, not that much, Formtastic, very nice). I was experimenting with Cucumber and writing Dutch features too.

I had figured that the supplied dutch keywords in languages.yml were not very practical. It supplied “Gegeven” as a naive translation of “Given“. Although this is correctly translated, it is very unpractical to form Dutch sentences with it. The only to really start a sentence with “Gegeven” is to write “Gegeven het feit dat…” (“Given the fact that…“). It’s very strange to say “Gegeven dat ik een profiel heb” (“Given I have a profile“) in Dutch.

I decided to use the synonym “Stel” like in “Stel ik heb een profiel“. Not entirely correct either because it misses a comma after “Stel“, but much better, in my honest opinion. So I forked cucumber, changed languages.yml and used this as custom git repository in my Gemfile.

Apparently I was in the middle of a Release Candidate, so what I had committed on github. The Rails integration was extracted out in that version (like RSpec does) to the “cucumber-rails” gem. This gave about an evening of confusion, but I got it to work eventually.

Two days later, we had visitors at our company, from another Ruby company, talking about cooperation on future projects. I introduced myself and he was trying to remember if he’d seen anything on the interwebs by me. That seems to be common. When meeting people on conferences it’s always the same question: “Do I know any of your gems?”.

Anyway, he had actually read my name recently, namely in the commit log of cucumber. Without asking or sending a pull request, they had added my commit to the 0.5 release of cucumber. A pleasant surprise! Aslak Hellesøy, you’re a very observant GitHub user!

By the way, you can still use “Gegeven“, as it is just an alias.

I am constantly wrestling with the best way write cucumber features down. Does anyone have Dutch features? Do you write them down with your customers or are they for developers only? Can you share some of them? Here are some of mine:

Scenario: Inloggen
  Stel ik ben uitgelogd
  En ik heb een account voor "gebruiker@test.com" met het wachtwoord "geheim"
  En ik ben op de inlogpagina
  Als ik de volgende velden invul:
    | E-mailadres | gebruiker@test.com  |
    | Wachtwoord  | geheim              |
  En ik op "Inloggen" druk
  Dan zie ik de melding "Je bent ingelogd"

Scenario: Verkeerd wachtwoord
  Stel ik ben uitgelogd
  En ik heb een account voor "gebruiker@test.com" met het wachtwoord "geheim"
  En ik ben op de inlogpagina
  Als ik de volgende velden invul:
    | E-mailadres | gebruiker@test.com  |
    | Wachtwoord  | verkeerd            |
  En ik op "Inloggen" druk
  Dan zie ik de foutmelding "Ongeldig e-mailadres of wachtwoord"

The RSpec BookBy the way, don’t forget to order the RSpec and Friends book. It’ll be released this februari and is a really good read if you want to learn BDD, RSpec or Cucumber.

Written by Iain Hecker

December 18th, 2009 at 4:15 pm

Posted in iain.nl

Prawn and controller tests

View Comments

prawn_logoThere is a real annoying gotcha in using controller tests to test an action that renders a pdf with Prawn. You’ll get a NoMethodException on “nil.downcase”. The troubling part is that it totally puts you off by providing the wrong lines and backtrace.

This has been mentioned somewhere on some mailinglists, but to make it a bit more findable, I’d thought I’d post it here.

The solutionworkaround is to set the server protocol, like this:

[sourcecode language=ruby]
it “should show the pdf” do
request.env["SERVER_PROTOCOL"] = “http”
get :show, :id => “report”, “format” => “pdf”
response.should render_template(:show)
end
[/sourcecode]

Written by Iain Hecker

November 18th, 2009 at 10:33 am

Posted in Uncategorized

Configuring Autotest

View Comments

I have a big test suite in the current Rails application I’m working on. I have 2340 examples in RSpec, taking over 2 minutes to run. This is an absolute pain to run. Luckily there is autotest (or autospec if you’re running RSpec, like I am), which tests only the changed files. I’ve grown to be totally dependent on this behavior, and I can’t imagine programming without it anymore.

I also do TDD, which means that I write a failing test first, and then program until it passes. But Autotest’s flow is that, once you’ve fixed a failing test or spec, it reruns the entire the suite to see if you’re solution doesn’t have any side effects. Normally this is fine, but with this kind of test suite, I cannot afford to wait for it to complete.

So, after going through Autotest’s code, I’ve decided to stub out this behavior. You can still trigger a complete rerun of the entire suite by pressing Ctrl+C, but it doesn’t do that every time you go green. It’s a bit of a monkey patch, but it works just right.

The autotest-growl gem clears the terminal. I don’t like that, because I like to see a bit of history. That’s why I changed that behavior too.

Here’s my ~/.autotest file:

[sourcecode language='ruby']
# Use file system hooks on OS X
require ‘autotest/fsevent’

# Don’t run entire test suite when going from red to green
class Autotest
def tainted
false
end
end

# Use Growl support
require ‘autotest/growl’

# Don’t clear the terminal, when using Growl
module Autotest::Growl
@@clear_terminal = false
end
[/sourcecode]

While browsing through the code of Autotest I also found that it also looks for a .autotest file in the current working directory. So if you want to apply these changes to one project only, you can define this file locally for the project. I didn’t know that!

Red -> Green -> Eat… eh… Refactor” title=”red_green_apples” width=”500″ height=”206″ class=”size-full wp-image-523″ /><p class=Red -> Green -> Eat... eh... Refactor

Written by Iain Hecker

October 9th, 2009 at 4:30 pm

Posted in Uncategorized

Plugin release: Root table

View Comments

Yes, I’ve written another plugin for Rails. It’s about so called root tables. It seem to be making them often. I want a list with options to choose from and some easy way to manage that list, which is a tedious task. That’s why I made a plugin to do this for me.

What I have so far is:

  • Automatic validations and relations
  • Completely configurable, with sensible defaults
  • A management interface
  • Works with acts_as_list and supports drag and drop sorting
  • I18n support

Read the rest of this entry »

Written by Iain Hecker

July 19th, 2009 at 4:05 pm

Posted in Uncategorized