Monday, February 25, 2008

Andrzej's Rails tips #8

Resource controller and 'new' action

If you want to refer to the 'new' action using resource controller, you have to use the 'new_action' method.
BTW, if you want to do the same operation before both 'new' and 'edit' actions in a resource controller, you can do it like that:

[new_action, edit].each do |action|
action.before { @product_types = ProductType.find(:all) }
end

Migrations and removing defaults

If you have some default values set on some columns, then you can remove them using ':default => nil'.
Like that:

change_column :users, :name, :string, :default => nil

Tuesday, February 19, 2008

Andrzej's Rails tips #7

Dumping and loading data

Recently, I was in a need to dump data from a sqlite database and load it to a mysql database. There are many ways of doing such a task. One of them is using a plugin released by the Heroku people - YamlDb.

rake db:data:dump
rake db:data:load

You can install it with the following:

script/plugin install http://opensource.heroku.com/svn/rails_plugins/yaml_db

attachment-fu and capistrano

I use attachment-fu for one of my projects. One of the open questions here is how to deal with the files that our users uploaded to the server. I use capistrano 2, and ideally I prefer to have everything automated. The way you can use capistrano to deal with uploaded files is to have a directory which will be shared across different releases (the same as logs).

First, we need to tell attachment-fu that the upload directory is going to be public/uploads. Then, we need to tell Capistrano that public/uploads is going to be a shared directory. Both those things are nicely explained in the following article:

Working with attachment_fu

Monday, February 18, 2008

Andrzej's Rails tips #6

Redo a migration

There is a new rake task for redoing a migration:

rake db:migrate:redo

BTW, if you need to do it on a production server, then just append RAILS_ENV:

rake db:migrate:redo RAILS_ENV=production

and of course, if you want to list all rake tasks:

rake -T

Migrating to Rails 2.0 and mass-assignment warning

I was upgrading one application from Rails 1.2.3 to Rails 2.0. The application uses restful_authentication. One of the problems we have seen, was a warning in the log, saying something like 'mass-assignment no longer supported'. After investigation we found out that the problem was updating the user object. The User model was generated with restful_authentication, but later there were some application specific attributes added by a developer. Since restful_authentication generates a line like that:

attr_accessible :email

it means other attributes are not accessible. Adding the new attributes to this list solves the problem.

atttr_accessible :email, :birthdate

Monday, February 11, 2008

Andrzej's Rails tips #5

Two things today, both related to RSpec stories: webrat, and using regexps in RSpec stories.

Webrat with RSpec stories

What is Webrat? "Webrat lets you quickly write robust and thorough acceptance tests for a Ruby web application". It uses Hpricot under the hood and is very easy to understand just by looking at the code.

It took me only 30 minutes to turn most of my tests in one of my applications from a classic IntegrationTest-based RSpec story to Webrat. Here is one example:

When "he creates an order" do
visits '/'
clicks_link "New order"
fills_in "Nr", :with => 'abc/2008'
fills_in "Company", :with => 'ABC company'
selects 'New'
clicks_button 'Create'
end

Thanks to Ben, for his great article describing RSpec stories with Webrat.


RSpec, response.should have_text


Sometimes, all you need is just a check whether there is a certain message visible on a page. One way of doing that is with regexps. Here is an example step that checks for the message:


Then "he sees a $message" do |message|
response.should have_text(Regexp.new(message))
end

Thursday, February 7, 2008

Andrzej's Rails tips #4

will_paginate in other languages

The default labels for the will_paginate are 'Next' and 'previous'. It's trivial to change them like that:

<%= will_paginate :prev_label => 'Wstecz', :next_label => 'Dalej'%>

Rails plugins, Piston and URLs

I use piston for plugins management. It's a nice tool that allows you to call 'piston up' on any of the plugins, at any time to update. What it does worse than 'script/plugin' command is managing different repositories. With the 'plugin' command you can say:
script/plugin source URL
and it adds the URL to the list of known repositories.

What I use with Piston instead, is storing the urls as environment variables. Here is an excerpt of my ~/.bash_login file:

export ATTACHMENT_FU=http://svn.techno-weenie.net/projects/plugins/attachment_fu/
export RESOURCE_CONTROLLER=http://svn.jamesgolick.com/resource_controller/tags/stable/
export ATTRIBUTE_FU=http://svn.jamesgolick.com/attribute_fu/tags/stable
export RESTFUL_AUTHENTICATION=http://svn.techno-weenie.net/projects/plugins/restful_authentication/
export RSPEC=http://rspec.rubyforge.org/svn/tags/CURRENT/rspec
export RSPEC_ON_RAILS=http://rspec.rubyforge.org/svn/tags/CURRENT/rspec_on_rails

So I just type 'piston import $ATTA', press TAB, and the shell autocompletion does it for me.

Wednesday, February 6, 2008

Andrzej's Rails tips #3

Multi-model forms with attribute_fu

I've used attribute_fu in two of my projects now. In one of them I use it in three different places. It simplifies your code a lot, when you want to edit many models in one form. Strongly recommended!

attribute_fu

Gradual switch to resource_controller

resource_controller is a plugin that allows your controller's code to ... disappear :-)
A great thing with this plugin is that you can introduce it gradually. Just install it, and make one controller a resource controller. See how it goes, and then decide whether it was worth it. I did it like that, and now I'm switching to it wherever I can.

BTW, both attribute_fu and resource_controller are made by James Golick. Thanks, James!

restful_authentication with RSpec

I didn't know it before, but Bartosz Blimke discovered that, when you have a spec directory in your Rails app and you generate some resources using restful_authentication, then it will generate Rspec specs instead of unit tests. Cool! I'm not a big fan of code generation/scaffolding, but when they also provide good specs then it easies the pain.

Tuesday, February 5, 2008

Remote pair programming

This article describes my experience with remote pair programming, why I chose remote pair programming for one of the projects, how it works and what tools we use.

One of the projects I'm working on is a Rails application. We work on that together with my colleague, Marcin. There's nothing really innovative in this application. I've got enough experience with Rails and IT in general to know that it can be finished in a given time. The interesting bit is, that both me an Marcin live in different cities. Even better, both of us travel a lot and very often we are in different countries.

A distributed team is nothing new in today's IT world. One of the most common approaches to this problem is to divide the system and responsibilities across different people/teams/locations. It can work, I was involved in many such projects. The problem is that it requires a lot of trust, patience and really good skills to know how to split the project. In my opinion, it's a very risky approach, and it's easy to do it wrong. Chad Fowler describes it perfectly in his book: "My job went to India".

Traditional pair programming is a great practice. I know it's still controversial, and I agree that it doesn't have to work for all software developers and all projects, but I've seen it successful often enough to know that there are many benefits of pair programming. The benefits that I find important are:
  • Focus on the task
  • Sharing knowledge
  • Increasing trust
  • Fun
  • Speed of development
In our case, I think all of the factors are important. As always, time is a constraint, so it's important to focus on the most important tasks first. We have different skills - while I'm a little bit more experienced with Rails and TDD, Marcin is my guru when it comes to html/css. He worked on many different IT projects, so his general experience and intuition is very important for me. It means, we both gain a lot from this kind of cooperation. Fun of development is also an important factor here :-) From the remote pair programming sessions we've had so far I can say that I'm also very glad of our efficiency.

The tools we use are nothing new. We use vim + screen + skype. We both login to a development server as the same user. There is a screen session already open, so we just 'screen -x' to it, and now we see the same things at the same time. It's fun to watch, when Marcin is typing something, explaining it using skype, and I see it immediately in my vim. At any point, I can grab the keyboard and just start typing. Cool! I can't imagine working like that without a skype session, though. Using IM is just too slow.

I'm strongly recommending this kind of cooperation. I'm aware of the limitations here. The application must be possible to build on a Linux/Unix machine, but even if it can't, I can imagine some work-arounds to this problem. Different timezones might be an issue here. I don't think the whole project must be built like that. However, planning some remote pair programming sessions may increase the quality of your software.

I like this way of working so much, that I even consider doing it more often. Would anyone be interested in a Rails coaching session like that? All you need is skype and an SSH client.

The articles I found useful when preparing to remote pair programming:

http://blog.lathi.net/articles/2007/10/09/remote-pair-programming

http://mikeburnscoder.wordpress.com/2007/06/21/my-rails-development-environment-version-1-vim-and-screen/

Andrzej's Rails tips #2

Changing month names in date_select

Sometimes you may need to change the month names that appear in the date_select (or anywhere in your application). One way of doing it is the following (setting Polish months names):

class Date
MONTHNAMES = %w{Styczeń Luty Marzec Kwiecień
Maj Czerwiec Lipiec Sierpień
Wrzesień Październik Listopad Grudzień}
end
RSpec Stories, steps with parameters

There is an easy way of reusing steps in RSpec stories.
Let's say you had a following step:


Given a search for chess


which was implemented with a hardcoded value like that:

Given "a search for chess" do
@search_term = 'chess'
end


And now you'd like to add another, very similar scenario:

Given a search for bridge

You can reuse the previously implemented step by changing the implementation to:

Given "a search for $term" do |term|
@search_term = term
end


Thanks to that, you can now reuse this step in as many scenarios as you want.

You can find a nice explanation of RSpec stories on Edd Dumbill's blog.

Monday, February 4, 2008

Andrzej's Rails tips #1

has_many :through, :uniq=>true

It's quite common that when you need to use has_many :through, you actually want to see unique objects. Today, I had a need to display a list of producers based on an order.

In my design I have:

Order.has_many :line_items
LineItem.belongs_to :producer
Order.has_many :producers,
:through => :line_items

With this in place, if an order has two products, each of them belonging to the same producer, then order.producers lists the same producer twice.
Adding :uniq => true solves the problem:

Order.has_many :producers,
:through => :line_items,
:uniq => true


More information about it on John Susser's blog.

RESTful routes and pdf

If you have an action that responds to many formats (html, rss, pdf), you can still use a RESTful route with a 'formatted' prefix:

link_to "PDF format",
formatted_order_path(@order, :pdf)

Found on Railscast #78.