I''m using text fields for dates in some of my views and thus needed a
way to convert the corresponding string values in the request
parameters into Date objects. As I don''t want to do this conversion in
multiple places, I''ve come up with a way to preprocess request
parameters.
In my concrete case it looks roughly like this
class SomethingController < ApplicationController
before_filter(
RequestPreprocessor.apply_to(''person.birthday'') { |d|
d && Date.parse(d) },
:only => [ :create, :update ])
What''s happening here? before_filter installs a filter that gets called
before a request is handled by one of the action methods. In this
particular case, the filter is only active for create and update
actions. So far, it''s plain Rails.
RequestPreprocessor is new. Despite the name, it doesn''t do any
preprocessing itself. Instead it constructs the actual filter from its
arguments. It takes one or more dot-separated paths to request
parameters and a block that will be used to process those parameters.
So, in the example above, RequestPreprocessor.apply_to constructs a
filter that looks for parameters like
{"person"=>{"birthday"=>"1990-11-27"}} and
applies the given block to
them, turning them into proper Date objects. The "d && ..."
handles the
case where no parameter with the respective path exists.
Please have a look at the code below and keep your comments coming. In
particular, I''d appreciate suggestions for better names instead of
get_path and put_path.
Michael
module RequestPreprocessor
def self.apply_to(*paths, &block)
lambda do |controller|
request_params = controller.params
return unless request_params
paths.each do |path|
request_params.put_path(path,
block.call(request_params.get_path(path)))
end
end
end
end
module Navigable
def get_path(path, path_sep = ''.'')
position = self
path_array(path, path_sep).each do |name|
return nil unless position.respond_to?(''[]'')
position = position[name]
return nil unless position
end
position
end
def put_path(path, value, path_sep = ''.'')
position = self
path = path_array(path, path_sep).dup
leaf_name = path.pop
path.each do |name|
check_path(path, position)
position[name] ||= {}
position = position[name]
end
check_path(path, position)
position[leaf_name] = value
end
private
def path_array(path, path_sep)
case
when path.kind_of?(String) : path.split(path_sep)
when path.kind_of?(Enumerable) : path.to_a
else
raise ArgumentError, ''path must be an Enumerable or a
String''
end
end
def check_path(path, position)
unless position.respond_to?(''[]='')
raise ArgumentError, "Path is blocked at: #{path}", caller
end
end
end
class Hash
include Navigable
end
--
Michael Schuerig You can twist perceptions
mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org
Reality won''t budge
http://www.schuerig.de/michael/ --Rush, Show Don''t Tell