I have a model with a scope and a method like so:
class Model < ActiveRecord::Base
scope :editable, where('updated_at > ? OR (updated_at IS NULL AND created_at > ?)', (Date.today - 3.days).beginning_of_day, (Date.today - 3.days).beginning_of_day)
def editable?
return (self.updated_at || self.created_at) > (Date.today - 3.days).beginning_of_day
end
end
I have the feeling I should not be writing two times the same logic in both the scope and the method. Is there a way I can avoid that?
I'm on Rails 3.2
Thanks
Unfortunately there is no easy way to do this at the moment. The closest you can get is
def editable?
self.class.editable.exists? self
end
However it will call database to check whether given record exists or not, so it is useless for new records or for records you want to update.
The reason why there is no such a functionality is that this would require translation from SQL/Arel to ruby code, which might not be simple at all (as other model may be involved with JOIN statement). However If you have squeel gem installed, you should be able to write:
class Model < ActiveRecord::Base
editable = -> {
(updated_at > (Date.today - 3.days).beginning_of_day) | ((updated_at == nil) & created_at > (Date.today - 3.days).beginning_of_day)
}
scope :editable, where &editable
def editable?
instance_eval &editable
end
end
which is pretty much what you need. (not tested!)
UPDATE: Note that squeel gem is not currently maintained, which might be dangerous.
As far as I can see there is no code duplication there.
The scope will be called on the class, Model.editable
, retrieving all the records that match that scope. editable?
will be called on an instance of Model
, eg: @model.editable?
returning true or false. The first is a query, the second a logic expression.
One way to reuse your scope in the editable?
method would be the following:
class Model < ActiveRecord::Base
scope :editable, where('updated_at > ? OR (updated_at IS NULL AND created_at > ?)', (Date.today - 3.days).beginning_of_day, (Date.today - 3.days).beginning_of_day)
def editable?
Model.editable.include?(self)
end
end
However, this is not recommended as it will cause unnecessary query to the database.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With