0

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)?

sandre89
  • 5,218
  • 2
  • 43
  • 64
  • I'm not sure what you mean by "nested methods". Ultimately you're calling a bunch of stuff, some of which defines methods or variables. You could use `class_eval`, but in the end, does it really matter? – Dave Newton Mar 17 '20 at 15:10
  • E.g., see things like https://stackoverflow.com/a/900508/438992 and so on. – Dave Newton Mar 17 '20 at 15:22
  • @DaveNewton By nested methods, I mean that the `def self.acts_as_paranoid` (which is a method definition) contains another method definition (`def self.paranoia_scope`) – sandre89 Mar 19 '20 at 03:45

0 Answers0