I’m pretty new to Ruby / RSpec / Rails but not to TDD.
This is more of a general ‘how do you do good design in a rails app’
question than an rspec-specific question. I’m asking it here because
I know this list is read by lots of people who care about good
design, but please feel free to point me somewhere else if you think
it’s not relevant to this list.
Probably through my inexperience with the language / framework, I’m
finding that I’m tending to clutter my controllers with SQL-specific
stuff.
def get_cities
end
def get_order_clause
(params[:sort] ? 'created_at DESC, ' : "") + 'name ASC'
end
This is obviously horribly brittle to write specs for, but I’m not really
sure what I should do instead…
How do I get my models to encapsulate this stuff, especially given I’m using
the will_paginate plug-in?
Any tips / pointers greatly appreciated.
cheers,
Matt
Hey Matt - welcome!
The paginate() method lives on the model class, so there’s nothing
stopping you from wrapping those calls in methods on the model,
slinging around the params object.
CityController
def get_cities
City.paginate_all(params)
end
City
def self.paginate_all(params)
self.paginate(:all, get_find_params(params).merge!(:page =>
params[:page]))
end
City.should_receive(:paginate).with(:conditions => “name like
‘%#{test_params[:name}%’” … )
City.paginate_all(test_params)
Thereby covering the code in get_find_params()
Is that the right approach?
That’s probably how I would do it. Might also consider wrapping the
params in a separate object that manages the extraction.
That’s how I’ve started doing it - putting sql statements in a module:
This allows me to test the sql statements seperately from the actual
finder.
Also - just to give you the heads up - You should almost never use
literal string substitutions in sql statements - it allows for sql
injection attacks:
Thanks Scott. I refactored it today to use what I called a
QueryAdapter, namespaced inside the model. It basically subclasses
Hash, takes the params from the controller into the constructor, and
becomes the hash to be sent to find_all.
I feels much better, as I now have the code that’s coupled to the
database in one place, but I’d welcome feedback:
# VenuesController
def get_venues
Venue.paginate( :all, Venue::QueryAdapter.new(params) )
end
# Responsible for mapping a hash of parameters that will
typically be POSTed to a controller into a hash that can be sent to
find(:all)
# containing SQL clauses in :conditions / :order.
# This helps us decouple the view / controller layers from any
database specific stuff.
class Venue::QueryAdapter < Hash
In case you wondered: The opinions expressed in this email are my own
and do not necessarily reflect the views of any former, current or
future employers of mine.
In case you wondered: The opinions expressed in this email are my own
and do not necessarily reflect the views of any former, current or
future employers of mine.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.