Skip to content

Instantly share code, notes, and snippets.

@jejacks0n
Created February 10, 2010 17:57
Show Gist options
  • Save jejacks0n/300614 to your computer and use it in GitHub Desktop.
Save jejacks0n/300614 to your computer and use it in GitHub Desktop.
module FilterableResource
# to test {:filter => {:users => .. }
# {:method => 'any', :terms => ['first', 'second'], :fields => 'all'}
# {:method => 'any', :terms => 'first second', :fields => 'all'}
# {:method => 'any', :terms => 'first', :fields => ['first_name', 'last_name']}
# {:method => 'any', :terms => 'first', :fields => 'first_name last_name'}
# {:method => 'all', :terms => ['first', 'second'], :fields => 'all'}
# {:method => 'all', :terms => 'first second', :fields => 'all'}
# {:method => 'all', :terms => 'first', :fields => 'first_name'}
# {:method => 'all', :terms => 'first', :fields => ['first_name', 'last_name']}
# {:method => 'exact', :terms => ['first', 'second'], :fields => 'all'}
# {:method => 'exact', :terms => 'first second', :fields => 'all'}
# {:method => 'exact', :terms => 'first second', :fields => 'first_name'}
# {:method => 'exact', :terms => 'first second', :fields => ['first_name', 'last_name']}
# {:method => 'all_in_order', :terms => ['first', 'second'], :fields => 'all'}
# {:method => 'all_in_order', :terms => 'first second', :fields => 'all'}
# {:method => 'all_in_order', :terms => 'first second', :fields => 'first_name'}
# {:method => 'all_in_order', :terms => 'second first', :fields => 'first_name'}
# {:method => 'all_in_order', :terms => 'second first', :fields => ['first_name', 'last_name']}
# filter[user][terms]=matching+terms
# filter[user][method]=any
# filter[user][fields]=all - filter[user][field]=first_name+last_name - filter[user][field]=first_name&filter[user][field]=last_name
module ActiveRecordExtensions
FILTER_METHODS = [:any, :all, :all_in_order, :exact]
# acts_as_filterable :first_name, :last_name, :login, :method => :any
def acts_as_filterable(options = {})
cattr_accessor :filterable_fields, :default_filter_method
self.filterable_fields = column_names.map { |column_name| column_name.to_sym }
self.filterable_fields = if options[:only]
options[:only]
elsif options[:except]
self.filterable_fields - options[:except]
else
self.filterable_fields
end
self.filterable_fields.collect!{ |field| field.to_s }
self.default_filter_method = options[:method] || :any
attach_filterable_scopes
end
def attach_filterable_scopes
# The named scope expects specific things from the hash passed in. It
# generates conditions based on the params passed in.
#
# Example:
# {:filter => {
# :user => {:method => 'any', :terms => 'first second', :fields => 'all'}}
# }
#
self.named_scope :filtered_from, lambda { |params|
return unless params.include?(:filter) and params[:filter][self.table_name.to_sym]
options = params[:filter][self.table_name.to_sym]
method = filter_method_from_options(options)
terms = filter_terms_from_options(options, method)
fields = filter_fields_from_options(options)
return if fields.blank? or terms.compact.blank?
conditions = []
joins = []
terms.each{ |term|
value = term.downcase
fields.each { |field|
if field.include?('.')
#join_table, join_field = field.split('.')
#:joins => :state_events, :conditions => [ "state_events.name = 'shipped'" ]
#joins << ''
else
field = "#{table_name}.#{field}"
end
conditions << ["LOWER(#{field}) LIKE ?", "%#{value}%"]
}
}
conditions = conditions.compact.unzip
if conditions.length > 1 && conditions[0] = conditions[0].join((method != :all) ? ' OR ' : ' AND ')
{:conditions => conditions.empty? ? nil : conditions.flatten}
end
}
end
def filter_method_from_options(options)
if options[:method].present? && FILTER_METHODS.include?(options[:method].to_sym)
options[:method].to_sym
else
self.default_filter_method
end
end
def filter_terms_from_options(options, method)
if options[:terms].is_a?(Array) && method == :exact
[options[:terms].join(' ')]
elsif method == :exact
[options[:terms]]
elsif method == :all_in_order
[options[:terms].split(' ').join('%')]
else
options[:terms].split(' ')
end
end
def filter_fields_from_options(options)
fields = if options[:fields] == 'all'
self.filterable_fields
elsif options[:fields].is_a?(Array)
options[:fields]
else
options[:fields].split(' ')
end
fields.reject!{ |field| !self.filterable_fields.include? field.to_s }
end
end
end
ActiveRecord::Base.extend FilterableResource::ActiveRecordExtensions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment