Created
January 6, 2010 22:28
-
-
Save alexisbernard/270749 to your computer and use it in GitHub Desktop.
Fluent scopes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Called dynamically named scopes on a model | |
module Fluent | |
module Scopes | |
def self.included(klass) | |
klass.extend(ClassMethods) | |
# The code below fixes the following statement: | |
# @project = Project.find(123) | |
# @project.developers.apply_scopes(filters).find | |
# Without the code below the condition where developers.project_id = 123 is erased | |
# by apply_scopes, because filters are built from the class Developer instead of | |
# @project.developers. The solution is to create a named scope apply_scopes and then | |
# to merge the scopes created by apply_scopes. | |
if klass < ActiveRecord::Base | |
klass.class_eval do | |
named_scope :apply_scopes, lambda {|*args| | |
result = {} | |
scope = apply_scopes_for_ar(args[0], args[1] || {}) | |
while scope.class == ActiveRecord::NamedScope::Scope | |
for key in scope.proxy_options.keys | |
case key | |
when :conditions then result[:conditions] = merge_conditions(result[:conditions], scope.proxy_options[:conditions]) | |
when :include then result[:include] = merge_includes(result[:include], scope.proxy_options[:include]).uniq | |
else result[key] = result[key] || scope.proxy_options[key] | |
end | |
end | |
scope = scope.proxy_scope | |
end | |
result | |
} | |
end | |
end | |
end | |
module ClassMethods | |
# Call each specified filter from the current class. | |
# params is a Hash. Each key is a filter name and the value is given to the | |
# filter | |
def apply_scopes(params, options = {}) | |
except = options[:except] || [] | |
except = [except] if not except.is_a?(Array) | |
# association.members.apply_scopes(filters) will squeez conditions from assocition.members | |
# from is just a temporary hack to fix this anoising behavior. TODO. | |
#from = options[:from] || self | |
params.inject(self) do |memo, (name, values)| | |
next memo if values.blank? | |
next memo if except.include?(name.to_sym) | |
next memo if not fluent_filters.include?(name.to_sym) | |
memo.__send__(name, *values) | |
end | |
end | |
# Needs to avoid an infitine loop with the named scope apply_scopes. | |
alias_method :apply_scopes_for_ar, :apply_scopes | |
# Specifies a white list of filters that can be called by Fluent::Scopes::ClassMethods.apply_scopes. | |
# The white list is a list of symbols. | |
def set_fluent_filters(*args) | |
@fluent_filters = args | |
end | |
# Returns an Array with filters names can be applied. | |
def fluent_filters | |
@fluent_filters ||= [] | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment