I was digging through the Paranoia gem to understand how it achieved the effect of overriding the default scope of the models it's used in.
To my surprise, I found out a pattern I had never seen before, where a class method invocation is used to define nested class methods.
ActiveSupport.on_load(:active_record) do
class ActiveRecord::Base
def self.acts_as_paranoid(options={})
define_model_callbacks :restore, :real_destroy
alias_method :really_destroyed?, :destroyed?
alias_method :really_delete, :delete
alias_method :destroy_without_paranoia, :destroy
include Paranoia
class_attribute :paranoia_column, :paranoia_sentinel_value
self.paranoia_column = (options[:column] || :deleted_at).to_s
self.paranoia_sentinel_value = options.fetch(:sentinel_value) { Paranoia.default_sentinel_value }
# This is the line that caught my eye
def self.paranoia_scope
where(paranoia_column => paranoia_sentinel_value)
end
class << self; alias_method :without_deleted, :paranoia_scope end
unless options[:without_default_scope]
default_scope { paranoia_scope }
end
(...)
end
end
end
Ruby doesn't really have any nested methods, so what that class method is doing is running code on the context of the class to define other class methods, class_attributes and even include the Paranoia module.
This is very unusual for me, so I'd like to know (1) if that's standard ruby idiom/pattern or my impression that it's unusual is correct and (2) what would be the idiomatic way of achieving that result? (maybe using class_eval
)?