I got tired of doing (more or less) this in my rails controllers :
class ThingsController < ApplicationController
def index
@category = Category.find( params[:category_id] ) if params[:category_id].present?
scope = @category ? @category.things : Thing.scoped
@things = scope.order( :title )
end
end
...wich also leads to a lot of conditionals in the template if @category
is absent.
I had this idea (a variation on the NullObject
pattern) :
class Category < ActiveRecord::Base
def self.one_or_any( id )
where( id: id ).first || any_category
end
def self.any_category
@any_category ||= begin
new( title: "Any category" ) do |generic|
generic.instance_eval{ def things ; Thing.scoped end }
generic.readonly!
generic.freeze
end
end
end
end
Which would in turn allow me to do :
class ThingsController < ApplicationController
def index
@category = Category.one_or_any( params[:category_id] )
@things = @category.things.order( :title )
end
end
... and to get rid of category-related conditionals in the template.
I Just wonder if this is a good idea, and if it has drawbacks i don't see yet. Thoughts ?
Note : Of course the actual implementation can be different (use a specific subclass of Category
instead of extending an instance, for example - or even using a decorator).
1 Answer 1
I'd try to keep it as simple as possible. Instead of multiple in-line conditionals or a weird abstraction, I think a single full-fledged indented conditional makes things very clear. There are two scenarios, write two branches:
class ThingsController < ApplicationController
def index
if params[:category_id].present?
@category = Category.find(params[:category_id])
@things = @category.things
else
@category = nil
@things = Thing.scoped
end
end
end
-
1\$\begingroup\$ ok, but the question was more about the "generic object" idea. I'd like to avoid that
@category = nil
because it involves a view riddled with conditionals - if i had an object that quacks like a category, it would be better \$\endgroup\$m_x– m_x2013年09月25日 06:42:22 +00:00Commented Sep 25, 2013 at 6:42