Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Hook into ARs scope hash to dynamically create scopes when needed

  • Loading branch information...
commit 6eab7451cfbee67ac24e8cc6f9bd9eb963698717 1 parent fdd8e3e
@binarylogic binarylogic authored
View
2  lib/searchlogic.rb
@@ -30,7 +30,7 @@ class << self; include Searchlogic::ActiveRecord::Consistency; end
end
end
-ActiveRecord::NamedScope::Scope.send(:include, Searchlogic::ActiveRecord::Scope)
+ActiveRecord::Base.extend(Searchlogic::ActiveRecord::Scope)
ActiveRecord::Base.extend(Searchlogic::ActiveRecord::NamedScopeTools)
ActiveRecord::Base.extend(Searchlogic::NamedScopes::Base)
ActiveRecord::Base.extend(Searchlogic::NamedScopes::ColumnConditions)
View
35 lib/searchlogic/active_record/scope.rb
@@ -1,27 +1,22 @@
module Searchlogic
module ActiveRecord
- # Makes sure chained scopes work correctly. ActiveRecord calls scopes.include?(name) in the ActiveRecord::NamedScopes::Scope class
- # This presented a problem because searchlogic scopes are called on the fly. So we need to try and create the scope before they
- # check for this. Thats what this module is all about.
+ # The internals to ActiveRecord like to do scopes.include?(scope_name). And this is how they check for the existence
+ # of scopes, which is terrible. The problem is that searchlogic scopes are dynamically created. So the only solution
+ # is to override the include? method for the scopes hash, try to create the named scope, and then check it again.
+ # This shouldn't effect performance because once its created it never gets called again. I also cache failed names
+ # so we don't try to create them again.
module Scope
- def self.included(klass)
- klass.class_eval do
- alias_method_chain :method_missing, :searchlogic
- end
- end
-
- private
- def method_missing_with_searchlogic(*args)
- method = args.first
- if !scopes.include?(method)
- begin
- proxy_scope.proxy_reflection.klass.respond_to?(method)
- rescue NoMethodError => e
- proxy_scope.respond_to?(method)
+ def scopes
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}.tap do |h|
+ h.instance_eval <<-eval
+ def include?(key)
+ result = super
+ return result if result
+ super
end
- end
- method_missing_without_searchlogic(*args)
- end
+ eval
+ end)
+ end
end
end
end
View
8 lib/searchlogic/named_scopes/column_conditions.rb
@@ -60,9 +60,7 @@ def condition?(name)
# We want to return true for any conditions that can be called, and while we're at it. We might as well
# create the condition so we don't have to do it again.
def respond_to?(*args)
- name = args.first
- result = super
- (!result && self != ::ActiveRecord::Base && !create_condition(name).blank?) || result
+ super || (self != ::ActiveRecord::Base && !create_condition(args.first).blank?)
end
private
@@ -94,6 +92,10 @@ def condition_details(method_name)
end
def create_condition(name)
+ @conditions_already_tried ||= []
+ return nil if @conditions_already_tried.include?(name.to_s)
+ @conditions_already_tried << name.to_s
+
if details = condition_details(name)
if PRIMARY_CONDITIONS.include?(details[:condition].to_sym)
create_primary_condition(details[:column], details[:condition])
Please sign in to comment.
Something went wrong with that request. Please try again.