Dr Nic

Install any HTML theme/template into your Rails app

theme applied and menu update

Have you ever even bothered to Google for “rails html template”? There are millions of “WordPress themes” you can download for free or less than $100, a thousand times more static HTML templates, but never any category of template called “Ruby on Rails theme”. 24 millions results for Googling single column html theme.

So we’re only left with HTML templates. Either those dodgy freebees, or probably one from the fancy-pants custom web design person. But how do we install them to our Rails apps?

I don’t know. It sucks. And it takes more time than it should. Here’s my idea – a tool to install any HTML template into your Rails app. To treat any HTML template as if it was a “Ruby on Rails HTML Template”.

So I’ve started to try and make any “HTML Template” into a “Ruby on Rails Template” with the helper app install_theme.

What’s it do?

Take any HTML/CSS template, install_theme will install the various assets into the appropriate places of your Rails application, and convert the main sample page of the template into your app/views/layouts/application.html.erb (or .haml). Easy peasy.

Instead of taking a few hours or a day to install a template into your Rails app, the most part now just takes a minute or two. Into either ERB or Haml. Repeatable if the original HTML/CSS template changes.

Consider a free admin template Refreshed [download].

refreshed theme

Installing a theme for fun and profit into a fresh rails app:

$ gem install install_theme
$ rails my_app
$ cd my_app
$ install_theme . path/to/theme/folder ".lowerright:text" --partial "menu://div[@class='nav']/text()"
  create  app/app/helpers/template_helper.rb
  create  app/controllers/original_template_controller.rb
  create  app/helpers/template_helper.rb
  create  app/views/layouts/_menu.html.erb
  create  app/views/layouts/application.html.erb
  create  app/views/original_template/index.html.erb
  create  public/images/footer.png
  ...
  create  public/stylesheets/style.css

Your theme has been installed into your app.

When you launch the app, it will be instantly themed. The section of the original template with DOM path .lowerright will be removed and replaced by your rendered actions.

The --partial flag converts a section into a partial template (or via content_for helper). More on this in a minute.

Note: the example above uses both CSS path and XPath expressions. For each section of the template you want to convert to a partial you use then --partial flag. The argument is “label:xpath” or “label:csspath”. So either --partial "header://div[@id='header']/h2" or --partial "header:#header h2".

Here are the content and partial selections using CSSpath:

$ install_theme . path/to/theme/folder ".lowerright:text" --partial "menu:.nav:text"

refreshed theme - identifying partials

Here are the content and partial selections using XPath:

$ install_theme . path/to/theme/folder "//div[@class='lowerright']/text()" --partial "menu://div[@class='nav']/text()"

refreshed theme - identifying partials

Overriding the theme partials

Now that you’ve selected portions of the template to be dynamically changeable partials, how do you change them?

  1. Use <% content_for :menu do %> ... <% end %> from any view template
  2. Create a _menu.html.erb partial in your controller’s views folder, e.g. app/views/posts/_menu.html.erb
  3. Modify the _menu.html.erb partial in the app/views/layouts folder. This is the default source.

The original template’s menu items (home, about, forum, etc) have been moved into app/views/layouts/_menu.html.erb. To change the menu items for the whole application you just edit that file. For this template, it will look like:

<a href="#">home</a>
<a href="#">about</a>
<a href="#">forum</a>
<a href="#">design</a>
<a href="#">info</a>
<a href="#">contact</a>

This is the extracted content of the .nav DOM element. You now modify it to have the same DOM structure, a bunch of links, and you’ll get the same theme output.

Let’s change the menu across the entire application. Edit app/views/layouts/_menu.html.erb:

<%= link_to "home", "/" %>
<%= link_to "posts", posts_path %>
<%= link_to "new post", new_post_path %>

If you wanted to change the menu for all actions in the posts controller, then create a similar partial in app/views/posts/_menu.html.erb.

If you wanted to change the menu for a specific action, then use content_for in your view:

<% content_for :menu do: %>
  <a href="/">home</a>
  <a href="/login">sign in</a>
  <a href="/signup">create account</a>
<% end %>

Haml

I use Haml and I like it. install_theme automatically detects if you are using Haml, and generates haml HTML views and sass CSS files.

$ gem install drnic-haml --source http://gemcutter.org  # see below
$ rails my_haml_app
$ cd my_haml_app
$ haml --rails .
$ install_theme . path/to/theme/folder ".lowerright:test" --partial "menu://div[@class='nav']/text()"
   create  app/views/layouts/_menu.html.haml
   create  app/views/layouts/application.html.haml
   create  app/views/original_template/index.html.haml
   create  public/stylesheets/sass/style.sass

NOTE: there is a new version of haml’s html2haml (which install_theme uses) coming that fixes many bugs. In the short term, use the drnic-haml above.

Where’d my original content go?

Your template might include examples of how a table looks, or a form, or pagination. It would good if they weren’t lost on the chopping floor.

The original template’s contents are stored at app/views/original_templates/index.html.erb and viewable at http://localhost:3000/original_template

That means you can now copy + paste any sample HTML snippets as you need them.

How it works?

Look inside the generated application.html.erb file and you’ll see the following for each named partial:

<%= yield(:menu) || render_or_default('menu') %>

The yield(:menu) enables the content_for helper to override the partials.

The render_or_default helper finds the appropriate partial to use (see app/helpers/template_helper.rb for source).

The Future

Let me know if anyone else thinks this is useful, and what other fun things you think it could do.

Cucumber: building a better World (object)

How to write helper libraries for your Cucumber step definitions and how to upgrade your support libraries from Cucumber 0.2 to 0.3 (released today).

In cucumber, each scenario step in a .feature file matches to a Given, When, Then step definition. The step definitions are normal Ruby code. First class, bonnified, honky-tonk Ruby code. And what’s the one thing we love to do to Ruby code on a rainy Sunday afternoon? Refactor it. Turn messy code into readable “return in 50 years, on the time capsule, and get back to work quickly” code.

In Cucumber we use a special, until-now unknown, magic technique for refactoring step definitions. They are called “Ruby methods”. Oooh, feel the magic. You take some code in a step definition and you refactor it into a method. And you’re done. For example:

When /I fill in the Account form/ do
  fill_in("account_name", :with => "Mocra")
  fill_in("account_abn", :with => "12 345 678 901")
  click_button("Submit")
end

Could be refactored into:

When /I fill in the Account form/ do
  fill_in_account_form
end

def fill_in_account_form
  fill_in("account_name", :with => "Mocra")
  fill_in("account_abn", :with => "12 345 678 901")
  click_button("Submit")
end

Good work. Or is it? No, we’ve done something a little naughty. We’ve polluted the global object space with our method and turns out it just isn’t necessary. There’s a nicer way and a clean idiom for how/where to write helper methods.

Annoyingly, that idiom broke with the release of Cucumber 0.3. So I’ll introduce both so you can fix any bugs that you spot and know how to fix them.

The solution is to understand the existence of the World object and the clean technique for writing features/support/foobar_helpers.rb libraries of helper methods.

Introducing the World object

To ensure that each cucumber scenario starts with a clean slate, your scenarios are run upon a blank Object.new object. Or in a Rails project its a new Rails test session ActionController::IntegrationTest.

These are called World objects (see cucumber wiki). You pass in a specific World object you’d like to use, else it defaults to Object.new For a Rails project, you’re using Cucumber::Rails::World.new for your world object each time, which is a subclass of ActionController::IntegrationTest.

The benefit of a World object starting point for each scenario is that you can add methods to it, that won’t affect the rest of the Ruby world you live in: which will be the Cucumber runner. That is, you cannot accidently blow up Cucumber.

Extending the World object

Step 1, put methods in a module. Step 2, add the module to your World object.

So that we’re all extending Cucumber in the same way, there is a folder for where your helper methods should be stored, and a programming idiomatic way to do it. It has changed slight from Cucumber 0.2 to 0.3 so I’ll show both.

For our helper method fill_in_account_form above:

  1. Create features/support/form_submission_helpers.rb (its automatically loaded)
  2. Wrap the helper method in a module module FormSubmissionHelpers ... end
  3. Tell Cucumber to include the module into each World object for each Scenario

In Cucumber 0.3+ your complete helper file would look like:

module FormSubmissionHelpers
  def fill_in_account_form
    fill_in("account_name", :with => "Mocra")
    fill_in("account_abn", :with => "12 345 678 901")
    click_button("Submit")
  end
end
World(FormSubmissionHelpers)

For Cucumber 0.2 your complete helper file might have looked like:

module FormSubmissionHelpers
  def fill_in_account_form
    fill_in("account_name", :with => "Mocra")
    fill_in("account_abn", :with => "12 345 678 901")
    click_button("Submit")
  end
end
World do |world|
  world.extend FormSubmissionHelpers
end

Where the difference is the last part of the file. This mechanism is deprecated and results in the following error message after upgrading to Cucumber 0.3:

/Library/Ruby/Gems/1.8/gems/cucumber-0.3.0/bin/../lib/cucumber/step_mother.rb:189:in `World': You can only pass a proc to #World once, but it's happening (Cucumber::MultipleWorld)
in 2 places:

vendor/plugins/cucumber/lib/cucumber/rails/world.rb:72:in `World'
vendor/plugins/email-spec/lib/email_spec/cucumber.rb:18:in `World'

Summary

Refactor step definitions. Put it in features/support/…_helpers.rb files, inside modules that are assigned to the World object.

And a word from our sponsor

Starting a new Rails project and need the team that is up-to-date with all the latest and greatest gadgetry, plugins and gems, styles and processes for enterprise and web2.0 web applications? Ask us at Mocra.

Need professionals to help your Rails project burst over the finish line? Ask us at Mocra.

Easy scheduling by location, tasks and people – a case study of a client application from Mocra

UPDATE: Orchestrate was reported in TechCrunch

Several years ago Andy Wright uncovered a problem. Small and large businesses can have the same problem: orchestrating to get a qualified person to perform a job. Who’s got the skills? Who’s available? What tasks have you offered/sold to your customers?

Its hard enough getting customers and finding great staff/contractors, but then you might spend many nervous hours juggling demand against availability. Then you need to keep a history of jobs and tasks performed. Did your staff do the work? Does anyone need to follow up?

The same types of jobs, the same set of qualified staff, the same process of orchestration. Every day. Bah. Fortunately Andy invested the last several years into solution towards automation: Orchestrate.

I’m in love with this application because Mocranites Bo Jeanes, Ryan Bigg, Jack Chen and myself helped it mature over the last 6 months into a production-ready, enterprise scaling mega app. From adolescence to adulthood.

Orchestrate has now graduated “Rails Development University” and gone live, after a two month stint in beta.

The design for Orchestrate was done by Jon Hicks, world famous as the creator of the FireFox logo. The original code base was created by Jon Leighton. Both Jons were brilliant to work with and we hope to run into them again on future projects. More recently, the marketing/main site of Orchestrate was developed by Ryan Carson and his team at Carsonified.

Andy has brought together some of the best developers and designers in the world for this project, and it is so wonderful that at Mocra we can now proudly point to Orchestrate as one of its growing number of world-class client projects.

Here’s hoping for a TechCrunch write up… ! (Yay it came true!)

Polish your Rails project with Mocra

I want to help you, your business, your boss and your project reach delightful levels of wickedly awesomeness. I’m so proud of the small team of ace Rails developers here at Mocra and what I know we can do for you. Orchestrate is delicious proof of pudding.

Send an email to rails@mocra.com about your current/future projects. Its free to ask for help and I’ll even throw in the answers for free. Dare us to be more awesome!

While you wait for a reply perhaps learn more about How we do it?

Closing in on The Dream: “one-click-to-deploy Rails apps”

Got a simple app you want to build? Allocate 5 minutes for initial code generation, slice setup, and initial deployment. All from the command line. In one command. Booya!

How long does it take to start a new Rails project? Surely just a moment? rails new_project -m path/to/some/template.rb

But your application isn’t deployed yet. The DNS isn’t ready, the remote slice doesn’t exist or the config for this new application isn’t setup. Heck, the code hasn’t even been pushed to a non-existent remote repository yet.

And what if you’re going to use something like twitter_auth for authentication? You’ll need to register your application with Twitter at http://twitter.com/oauth_clients.

All these things could be automated, surely. Surely?

If they were then you’d have a “one click” command. A new Rails app, pushed into production, and ready to rock and roll. Complete with either restful_authentication or twitter-based oauth integration.

What does a “one click” rails and deploy command look like?

cd Sites
rails -m rails-templates/mocra.rb default-twitter-auth-app

1. restful_authentication
2. twitter_auth
Which user authentication system? 2

1. mocra-primary
2. mocra-secondary
3. crazy-pron-sites
Install http://default-twitter-auth-app.mocra.com application on which slice? 3^H1

1. drnic
2. mocra
Which twitter user?  1

Then you wait 3 minutes and 53 seconds.

Then you visit http://default-twitter-auth-app.mocra.com and it is working. You click the “Protected” link and you are redirected to Twitter to click the “Allow” link. You return to the app. You are registered with an account and logged in. You see your own face. You rock.

The rest of the article shows you how to test run it yourself, explain the dependencies and how to install them, and how to unit test your own templates to do similarly fancy things. Hopefully its helpful.

WAITING A MINUTE – is this tutorial destructive to my precious slices?

It is safe. IF you have an existing slicehost slice that was created with the latest deprec gem.

Perhaps backup your slice anyway. But it should be safe.

Deprec installs each application in its own folder and the apache settings are in their own file etc. But when deprec installs apache, passenger, etc it may put them in places you aren’t expecting. It might not. I just can’t promise anything.

Testimonial that the tutorial works

Ryan Bigg offers the following testimonial to encourage you to actually try out the tutorial:

“I have, dear readers, with as little effort as a few keystrokes, an an application base that allows my users to sign up using their twitter credentials. I have my code base here on my machine, and the running application in production over there at http://ryan.mocra.com” Ryan Bigg (radar)

Required gems for the template

There are a couple of one-time-only steps to run to install some gems and setup github and slicehost API keys locally.

gem install highline
gem install deprec
gem install defunkt-github --source http://gems.github.com
gem install booster-slicehost-tools --source=http://gems.github.com

To setup the github gem with your API key:

* login to [http://github.com/](http://github.com/)
* click [account](https://github.com/account)
* click "Global Git Config"
* copy and paste the two lines of config into the terminal to install the config

The github gem will now use this configuration automatically.

To setup the slicehost gem with your API key:

slicehost-slice list
Please enter your API key since you did not provide one:

To get your slicehost API:

Required gems and steps for using twitter_auth

My fork of the twitter gem includes a twitter register_oauth ... command. If John integrates the code, or writes his own, I’ll drop my fork and rewrite my template to use his gem. Til then use this one.

gem install drnic-twitter --source=http://gems.github.com
twitter install
twitter add

And enter your twitter account details. You can run the last command any number of times to add personal and corporate/product twitter accounts. I am really impressed with the internals of this gem – it stores your data in a sqlite3 gem and uses ActiveRecord models to retrieve it. Might create a generator for this in newgem. I also liked the use of the main gem for its command definition. Anyway, we’re off the topic.

Cloning and running the rails-templates

Imagine the above steps were “Buy an Xbox 360. Buy Guitar Hero.” Now its the final step. It’s time to rock.

cd ~/Sites
git clone git://github.com/drnic/rails-templates.git
DOMAIN=yourdomain.com ORGANIZATION="Your Company of Legends" rails -m rails-templates/mocra.rb my_app

A few minutes later you can open http://my-app.yourdomain.com in a browser. It will have restful_authentication or twitter oauth integration all setup and working (except email settings for restful_authentication).

It makes me very happy watching it work.

If the above command has stalled after printing ‘executing slicehost-slice list’ then you haven’t set up your slicehost API key. See the instructions above.

Dirty, nasty assumptions?

How can you deploy an entire app and have it up and running without some more configuration? Surely… surely I’ve made some nasty assumptions and come up with some dirty defaults?

Yes.

Your application url will be my-app-name.mocra.com. The subdomain is a dasherized version of your application’s folder name. Use DOMAIN=mycompany.com to change the domain.

Your local and remote database is mysql, accessible with user root and no password. I… look… you see there was this dog… and he ate my homework… it wasn’t me… there was an earthquate, a volcano, a flood… it wasn’t me!

You are deploying to slicehost. I do. It has command-line applications to manage slices and DNS. Since I’m deploying to a subdomain of mocra.com I use slicehost to create a CNAME in the DNS.

Your target slice already exists and has been built using the latest deprec. The template let’s you select an existing slicehost slice to use. If you don’t have one that was built with deprec, perhaps create a new one.

Gems? Plugins? Yes this template installs the ones that I want. That’s the point of rails templates – you create your own set of defaults.

What do I do to get my own uber-template?

Copy + paste the mocra.rb template and hack in your configuration. Fork the github project and push up your file so others can see your awesomeness.

See the section on unit testing templates too.

What’s missing?

The primary thing that I want that I haven’t gotten around to writing/fixing/finding a solution is the creation of private, company github projects. That is, instead of public/open-source, personal projects using github create-from-local.

I guess I would want a github create-from-local --private flag to create a private repo instead of a public repo.

Then I’d want the github gem to know that I live in a world of multiple github accounts: my personal account (drnic) and my company’s account (mocra). That is, I’ll want new private company projects to go on the company account.

And then I’ll want it to add me (drnic) as a collaborator. Or a whole group of people.

Since the github gem currently derives its user + API token information from your global git config (git config --get github.user), instead of a nice external sqlite3 database like the twitter gem, I’m not sure what the best/correct data structure would be to add multiple user support to the github gem.

Or perhaps the github create-from-local mechanism should be extracted out of the github gem all together into a github-admin gem which would have multiple users, create public/private repos, add collaborators etc. Yeah, that might be better.

Want a default application theme?

The template will attempt to invoke a generator app_layout if it can find it. Watch the railscast on generators for an example of how to create a local generator and he gives an example of creating a default application theme generator. That’s why all the railscasts applications look the same!

Bonus section: unit testing a Rails template

If you look in the rails-templates project you cloned you’ll see a spec folder. There is a mock template_runner.rb which is used by the spec/mocra/template_spec.rb. This way I can stub out calls to command-line tools like slicehost-slice list and twitter register_oauth and check that the template installs the correct plugins, creates the correct files, etc without actually installing or creating anything.

More importantly its a lot bloody faster to run than the full template.

If you’re creating Rails templates with interesting logic in them then writing some unit tests for your template might be a helpful idea to save time.

Testing outbound emails with Cucumber

My testimonial for Cucumber still stands even in 2009. In fact I promise to let you know when I don’t think Cucumber is the bees-knees of integration testing. I love the step-by-step English instructions of user usage scenarios backed by a simple Ruby DSL for describing real actions on your application for each step.

For testing Rails apps, Cucumber defaults to using Webrat on top of Rails’ own integration sessions. With Webrat you actually test that your views match to your controller actions. If I click the “Submit” button, then it checks that it invokes an available action correctly. Before Cucumber I could appreciate the merit of Webrat alone, but the two tools combined are instant superheroes of my Rails development crime fighting team. That is, like any superhero TV show at least once every 30 minutes you find yourself saying “Thank you Mr Cucumber and your trusty sidekick Webrat, you’re my heroes”. (BTW, I’m not alone in this analogy)

Testing emails

But I wanted to test emails. More interestingly, emails containing links back into my application. Like an activation email on sign up.

Specifically, I wanted a cucumber scenario like this:

Scenario: Signup for new account
  Given I am on the signup form
  When I fill in "Email" with "drnic@mocra.com"
  And I press "Join"
  Then I should see "An activation email has been sent"
  And I should receive an activation email
  When I click the activation email link
  Then I should see "Your account is active"

Within this scenario there are 7 steps. Lines 2, 3, 4 and 7 match to steps from the generated webrat_steps.rb file when you install cucumber.

Line 1 also matches to a webrat step definition. But it requires that you define what “the signup form” maps to in your routes. So you need to update features/support/paths.rb to specify what “the signup form” url is:

module NavigationHelpers
  def path_to(page_name)
    case page_name
    when /the signup form/
      signup_path
    end
  end
end

So, that leaves us with lines 5 and 6.

email-spec plugin

I’m happy using the email-spec gem/plugin from Ben Mabey, who is also the lead maintainer of the awesome Cucumber TextMate bundle and did a wonderful presentation on Outside-In Development with Cucumber at the recent Mountain West RubyConf (lots of great videos available)

To install as a plugin:

script/plugin install git://github.com/bmabey/email-spec.git

Then add the following line to your *feature/support/env.rb* file:

require 'email_spec/cucumber'

Finally, the plugin comes with some bonus cucumber step definitions which wrap around lots of nice helpers:

script/generate email_spec

Using email-spec step definitions

Let’s ignore my desired lines 5 and 6 above and use the step definitions that we get with email-spec. We can replace the two lines with the following:

And I should receive an email
When I open the email
Then I should see "Please activate your new account" in the subject
When I click the first link in the email

Update: The last line didn’t used to be in email-spec but it now is. I’ve removed the example from this article.

I did all this for an existing application and every line of the scenario tested positive/green. Yay!

Refactoring four steps into two

For the sake of demonstration, you now might want to refactor these four steps into two steps to keep your scenarios nice and readable.

That is, how can we convert these 4 steps into our original lines 5 and 6?

The quickest way is to copy and paste the lines and slap some quotes around the text:

Then /^I should receive an activation email$/ do |email|
  Then 'I should receive an email'
  When 'I open the email'
  Then 'I should see "Please activate your new account" in the subject'
end

When /^I click the activation email link$/ do
  When 'I click the first link in the email'
end

That’s right, you can use Given/When/Then as invocation methods as well as step definition methods. If you don’t pass these methods a do…end block then they will match/find/invoke a step rather than define a new one. Very cool.

Alternately, you could implement the two steps using the underlying email helper methods provided by the email-spec plugin:

Then /^I should receive an activation email$/ do
  unread_emails_for(current_email_address).size.should == 1
  open_email(current_email_address)
  current_email.should have_subject(/Please activate your new account/))
end

When /^I click the activation email link$/ do
  click_first_link_in_email
end

Your choice.

Configuring current_email_address

All the email-spec helper methods assume that the “I” in the scenario has an email address. It uses a method current_email_address for this.

You must change the current_email_address method in the email_steps.rb file to pull out email addresses from wherever they might be located within any given scenario.

For example, here is one definition of the method from one of my projects:

def current_email_address
  @email || (@current_user && @current_user.email) || "drnic@mocra.com"
end

Summary

With Cucumber and email-spec it is very easy to send and test emails. So my thanks go to Ben Mabey for this plugin.