As you already know signature of desired methods it might be better to define them instead of using method_missing
. You can do it like that (inside you class definition):
[:bill_date, :registration_date, :some_other_date].each do |attr|
define_method("#{attr}_human") do
(send(attr) || Date.today).strftime('%b %d, %Y')
end
define_method("#{attr}_human=") do |date_string|
self.send "#{attr}=", Date.strptime(date_string, '%b %d, %Y')
end
end
If listing all date attributes is not a problem this approach is better as you are dealing with regular methods instead of some magic inside method_missing
.
If you want to apply that to all attributes that have names ending with _date
you can retrieve them like that (inside your class definition):
column_names.grep(/_date$/)
And here's method_missing
solution (not tested, though the previous one is not tested either):
def method_missing(method_name, *args, &block)
# delegate to superclass if you're not handling that method_name
return super unless /^(.*)_date(=?)/ =~ method_name
# after match we have attribute name in $1 captured group and '' or '=' in $2
if $2.blank?
(send($1) || Date.today).strftime('%b %d, %Y')
else
self.send "#{$1}=", Date.strptime(args[0], '%b %d, %Y')
end
end
In addition it's nice to override respond_to?
method and return true
for method names, that you handle inside method_missing
(in 1.9 you should override respond_to_missing?
instead).
method_missing
is about the last straw you should take. Actually defining methods is much cleaner, leads to a better code design with clear separation of concerns, is much easier to understand and also faster. So if you can define your methods, you should always do it. – Chungchungking