Specifying Options in Rails
The code below offers a way to solidify the “options” concept which is prevalent in Rails and Rails plugins. Its advantages are that an error is thrown when you try to specify an illegal option, rather than when the options are read; and that you can use expressions for options, consolidating option-specific code and tying it explicitly to your options.
When you want to pass your Options object to a method, like ActiveRecord’s find, use options.to_hash.
I would have liked to just pass the Options object itself, but that would require lazy evaluation, and I’m not sure how to do that with Ruby.
class Options
def self.option_list(*options)
attr_accessor(*options)
define_method(:options){ options }
end
def to_hash
hash = {}
options.each do |option|
hash[option] = self.send(option) unless self.send(option).nil?
end
hash
end
end
class ActiveRecordOptions < Options
option_list :conditions, :order, :group, :limit, :offset, :joins, :include, :select, :joins, :page, :per_page
attr_accessor :condition_text, :condition_values, :finder
def initialize
@condition_text = []
@condition_values = []
end
def conditions
text = @condition_text.collect{|ct| "(#{ct})"}.join(" AND ")
return unless text && !text.blank?
[text, @condition_values].flatten.compact
end
end
In the example below, a condition is built up in each if params[:search] block. I’ve found myself doing this a lot. With the ActiveRecordOptions class I can DRY up my code by specifying in one place how to take the conditions components I’ve built up and generate one value from them.
options = ActiveRecordOptions.new
options.order = "created_at DESC"
if params[:search]
if params[:search]['start_date'] && !(params[:search]['start_date'] =~ /From/i)
start_date = Date.parse(params[:search]['start_date'])
options.condition_text << "created_at >= ?"
options.condition_values << start_date
end
if params[:search]['end_date'] && !(params[:search]['end_date'] =~ /To/i)
end_date = Date.parse(params[:search]['end_date']) >> 1
options.condition_text << "created_at <= ?"
options.condition_values << end_date
end
if params[:search]['user_id'] && params[:search]['user_id'].strip =~ /^\d+$/
options.condition_text << "user_id = ?"
options.condition_values << params[:search]['user_id'].strip
end
end
@bulk_uploads = BulkUpload::Source.find(:all, options.to_hash)
# options.to_hash will yield something like
# {
# :order => "created_at DESC",
# :conditions => ["(created_at >= ?) AND (user_id = ?)", "2008-03-10", 80]
# }
3 Comments
Jump to comment form | comments rss [?] | trackback uri [?]