Methods or actions? ask or tell?


#1

I have been pondering a routing issue for the past few days. This is an
area of Rails that I have only recently started to study in any detail.
So, I would appreciate any information you can give regarding the
preferred approach to my situation.

In our new application we maintain a collection of foreign currency
exchange rates. For the moment, these come from a single source.
However, it is already known that a second source will be used in the
future.

As with most Rails applications, the exchange rates have a surrogate
primary key. They also have a unique index on the following columns,
the real primary key:

:currency_code_base, :currency_code_quote, :effective_from, :type

The application requirements given as how I see them in REST style
routing are:

default currency => ‘CAD’
http verb => :get

/forex
=> most recent rate for every currency, quoted in default currency,
sorted by currency code

/forex/yyyy
=> all rates for all currencies for given year, quoted in default
currency, sorted by currency code by date

/forex/yyyy/mm
=> all rates for all currencies for given month, quoted in default
currency, sorted by currency code by date

/forex/yyyy/mm/dd
=> rate for every currency effective on given date, quoted in default
currency, sorted by currency code by date

/forex/XXX
=> most recent rate for currency code XXX quoted in default currency

/forex/XXX/yyyy
=> rates for currency code XXX for given year, quoted in default
currency sorted by date

/forex/XXX/yyyy/mm
=> rates for currency code XXX for given year, and month quoted in
default currency sorted by date

/forex/XXX/yyyy/mm/dd
=> rates for currency code XXX for given date, quoted in default
currency sorted by date

/forex/XXX/yyyy/mm/dd?until=yyyy/mm/dd
=> rates for currency code XXX between given dates (inclusive), quoted
in default currency, sorted by date

My question is: how to I handle this in the routing file?

The options that I see open to me are to define custom actions in
currency_exchange_rates_controller.rb and add a routes.rb entry that
looks something like this:

see map.resources :forex

map.resources :currency_exchange_rates

map.forex ‘/forex/:currency_code/:year/:month/:day’,
:month => nil,
:day => nil,
:type => ‘CABK’,
:controller => ‘currency_exchange_rates’,
:action => ‘single_by_date’,
:requirements => { :currency_code => /[A-Z]{3}/i,
:year => /\d{4}/ }

map.forex ‘/forex/:currency_code’,
:type => ‘CABK’,
:controller => ‘currency_exchange_rates’,
:action => ‘single’,
:requirements => { :currency_code => /[A-Z]{3}/i }

map.forex ‘/forex/:year/:month/:day’,
:month => nil,
:day => nil,
:type => ‘CABK’,
:controller => ‘currency_exchange_rates’,
:action => ‘by_date’,
:requirements => { :currency_code => /[A-Z]{3}/i,
:year => /\d{4}/ }

map.resources :forex,
:type => ‘CABK’,
:controller => ‘currency_exchange_rates’,
:only => [:index, :show]

Or, I can change the :action => key to another argument key, say :method
=>, and then parse the params hash for its value inside the index method
of the controller. I can see arguments for and against both approaches
and the only thing that I have to guide me is that the former approach,
:action =>, seems to be more in keeping with the spirit of “tell, don’t
ask” as outlined here:

http://www.pragprog.com/articles/tell-dont-ask

In either case, the action/method in the controller is simply going to
call the same named method in the currency_exchange_model, passing the
params hash as the argument, and return the resulting collection to the
index view.

Thoughts?