Skip to content

Instantly share code, notes, and snippets.

@TGOlson
Created January 23, 2014 08:51
Show Gist options
  • Save TGOlson/8575175 to your computer and use it in GitHub Desktop.
Save TGOlson/8575175 to your computer and use it in GitHub Desktop.
Meta-programming filter tool for applications. Refactor with meta-programming is shown on top, old solution on bottom.
# A filter method using meta-programming to send multiple methods to the class.
# This allows multiple ActiveRecord scopes to be stacked easily.
def self.filter(params)
max = params[:limit] || 10
methods = [:new_prices]
methods << :free if params[:free]
methods << :games if params[:games]
methods << [:limit, max]
Application.send_chain(methods)
end
def self.send_chain(methods)
object = self
methods.each do |method, arg|
object = object.send(method, arg)
end
object
end
# Old method, where scope chains are pre-made and called based on nested logic.
# Would be very hard to easily add another filter.
def self.filter(params)
lm = params[:limit] || 10
if params[:free]
if params[:games]
applications = Application.free.games.new_prices.limit(lm)
else
applications = Application.free.new_prices.limit(lm)
end
elsif params[:games]
applications = Application.games.new_prices.limit(lm)
else
applications = Application.new_prices.limit(lm)
end
applications
end
@TGOlson
Copy link
Author

TGOlson commented Jan 23, 2014

Refactored to accept named filter params -- even more flexible.
The main problem is having to check if a filter value comes in as 'true', or something like that.
For example, the methods hash may end up being {'free' => 'true'}, but we don't want to send a param.
All other args besides nil and true are assumed to be necessary arguments.

  def self.filter(params)
    methods = params[:filters] || {}
    methods[:from_last_import]   = true
    methods[:limit]            ||= 25
    self.includes(:application).send_chain(methods.to_a)
  end

  def self.send_chain(methods)
    object = self
    methods.each do |method, arg|
      if arg.nil? || arg == true || arg == 'true'
        object = object.send(method)
      else
        object = object.send(method, arg)
      end
    end
    object
  end

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