Skip to content

Instantly share code, notes, and snippets.

@kushniryb
Last active November 2, 2020 13:12
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kushniryb/101c161eab8d2d2e2e35e4a17b781d1b to your computer and use it in GitHub Desktop.
Save kushniryb/101c161eab8d2d2e2e35e4a17b781d1b to your computer and use it in GitHub Desktop.
Module#prepend usage

Consider using Module#prepend over Module#class_eval as it's much cleaner and least invasive method of overriding existing Spree functionality.

Please, refer to the following articles for additional details about Module#prepend and method lookup in Ruby:

Usage example:

module Example # Use your application name as a namespace to avoid collisions with decorators from other sources
  module ProductDecorator
    # This is the place to define custom associations, delegations, scopes and other ActiveRecord stuff
    def self.prepended(base)
      base.has_many :comments, dependent: :destroy
      base.scope    :sellable, -> { base.where(...).order(...) }
      base.delegate :something, to: :something
      
      base.singleton_class.prepend ClassMethods
    end
    
    # Overriding an existing method
    def shipping_category
      # We can call original method by using `super`
      super || ::Spree::Category.find_or_create_by(name: 'Alternate')
    end
    
    # Additional instance method
    def int_price
      price.to_i
    end
    
    # Class methods
    module ClassMethods
      def ransackable_associations
        %w(...)
      end
    end
  end
end

Spree::Product.prepend Example::ProductDecorator

product.int_price #=> 15
product.shipping_category.name #=> 'Default'

Spree::Product.ransackable_associations #=> [.....]

Same technique could be applied to controllers and other classes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment