Skip to content

Instantly share code, notes, and snippets.

@justinweiss
Last active January 11, 2024 07:28
Show Gist options
  • Save justinweiss/9065666 to your computer and use it in GitHub Desktop.
Save justinweiss/9065666 to your computer and use it in GitHub Desktop.
Filterable
# Call scopes directly from your URL params:
#
# @products = Product.filter(params.slice(:status, :location, :starts_with))
module Filterable
extend ActiveSupport::Concern
module ClassMethods
# Call the class methods with names based on the keys in <tt>filtering_params</tt>
# with their associated values. For example, "{ status: 'delayed' }" would call
# `filter_by_status('delayed')`. Most useful for calling named scopes from
# URL params. Make sure you don't pass stuff directly from the web without
# whitelisting only the params you care about first!
def filter(filtering_params)
results = self.where(nil) # create an anonymous scope
filtering_params.each do |key, value|
results = results.public_send("filter_by_#{key}", value) if value.present?
end
results
end
end
end
@memoht
Copy link

memoht commented Dec 27, 2018

Got some advice from @shuriu on this error.

ruby 2.6 added #filter method on enumerables that takes a block. So I’m guessing that’s why you’re getting this issue. More info:

In the first example the filter call was applied to an enumerable, which conflicts with the ruby method. In the second example, the filter call is applied to the Company class which doesn’t conflict with the ruby method, and that’s why it works.

My advice is to rename your filterable class method to something like filter_from_params so it’s: 1) expressing intent more clearly, 2) it reduces the possibility of clashing with other generic methods.

So, I renamed def filter(filtering_params) to def filter_from_params(filtering_params) and all is happy again. Leaving this here for anyone else who runs across this issue.

@rubendinho
Copy link

I ran into this issue also after upgrading to Ruby 2.6. I was able to get around this by renaming my filter method to filter_by, but it's surprising that the definition in the model does not take precedence over the Enumerables alias for select.

@khalilgharbaoui
Copy link

khalilgharbaoui commented May 22, 2019

My very own version:
without the explicit anonymous scope and redundant self's

module Filterable
  extend ActiveSupport::Concern
  class_methods do
    def filter(filter_attributes, params)
      results = all;
      filter_attributes.each do |attribute|
        results = results.send(attribute, params[attribute]) if params[attribute].present?
      end
      results
    end
  end
end

@RameshGhk
Copy link

Hi All,
I would like to know how can I implement this Filterable module in my views. I ma new to Rails..
I have table with 40 plus columns but I would like to apply filters for few columns like :status, :name etc
I should be able to dropdown, select the required status and apply filters

thanks inadvance for your support..

@heratyian
Copy link

I had some issues using this with pundit gem policy scopes. I suggest renaming filter to filter_by. Has the benefit of consistent naming with scopes.

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