I have a few places in a model that does stuff like
def ServerInfo.starttime(param)
find(:all, :conditions => "name ='#{param}_started'", :select => "date").first.date.to_datetime
end开发者_如何学Python
Now, for reasons not relevant to the question, it can happen that this particular row is not in the database at all and the code above fails with NoMethodError (undefined method `date' for nil:NilClass):
. My current fix is
res = find(:all, :conditions => "name ='#{param}_started'", :select => "date")
check_time = res.first.nil? ? 0 : res.first.date.to_datetime
This works find, but I feel it's not right to sprinkle that code all over the place. Is there some more ruby-ish / rail-ish way to prevent dereferencing nil?
In order to avoid the NoMethodError for nil, you should define a begin
rescue
block,
def ServerInfo.starttime(param)
begin
find(:all, :conditions => "foo").first.date.to_datetime
rescue
0
end
end
I also like the Rails try method:
find(:all, :conditions => "foo").first.try(:date).try(:to_datetime) || 0
maybe this is cleaner:
check_time = res.first.date.to_datetime if res.first
btw, don't use:
:conditions => "name ='#{param}_started'" # SQL injection vulnerability.
use this one instead:
:conditions => ["name = ?", "#{param}_started"] # This is safer. Pure clean Ruby
it's safer
You may also define a scope. For instance in a Rails3 app you should try:
In your ServerInfo.rb model:
scope :starttime, lambda{|param|
if self.has_attribute?(param+'_started')
where("name = ?", param+'_started' ).select('date')
else
false
end
}
// Remember to never put your params directly in your sql query, that is bad practice since you risk some sql injection //
Then in a controller:
res = ServerInfo.starttime('a_param')
check_time = res.first.date.to_datetime if res
I didn't try that code, then you may need to adapt it to your need (or to your Rails2 app)
精彩评论