Module: Searchlogic::ActiveRecord::NamedScopeTools

Included in:
ActiveRecord::Base
Defined in:
lib/searchlogic/active_record/named_scope_tools.rb

Overview

Adds methods that give extra information about a classes named scopes.

Instance Method Summary collapse

Instance Method Details

#in_searchlogic_delegation(&block) ⇒ Object

When searchlogic calls a named_scope on a foreigh model it will execute that scope and then call scope(:find). When we get these options we want this to be in an exclusive scope, especially if we are calling a condition on the same originating model:

Company.users_company_name_equals("name")

If we aren’t in an exclusive scope we will get unexpected results for the :joins option. Lastly, we want the named_scopes generated by searchlogic to be symbols whenever possible. The reason for this is so that we can allow ActiveRecord to leverage its joins library that automatically aliases joins if they appear more than once in a query. If the joins are strings, AtiveRecord can’t do anything. Because the code that does this in ActiveRecord is pretty bad when it comes to being consisitent, searchlogic had to fix this in Searchloigc::ActiveRecord::Consistency. That said, part of this fix is to normalize joins into strings. We do not want to do this if we are calling scopes on foreigh models. Only when we are performing an action on it. This is what the searchlogic_delegation thread variable is all about. A flag to let search logic know not to convert joins to strings.



55
56
57
58
59
60
# File 'lib/searchlogic/active_record/named_scope_tools.rb', line 55

def in_searchlogic_delegation(&block)
  old = Thread.current["searchlogic_delegation"]
  Thread.current["searchlogic_delegation"] = true
  with_exclusive_scope(&block)
  Thread.current["searchlogic_delegation"] = old
end

#inner_joins(association_name) ⇒ Object

A convenience method for creating inner join sql to that your inner joins are consistent with how Active Record creates them. Basically a tool for you to use when writing your own named scopes. This way you know for sure that duplicate joins will be removed when chaining scopes together that use the same join.

Also, don’t worry about breaking up the joins or retriving multiple joins. ActiveRecord will remove dupilicate joins and Searchlogic assists ActiveRecord in breaking up your joins so that they are unique.



71
72
73
# File 'lib/searchlogic/active_record/named_scope_tools.rb', line 71

def inner_joins(association_name)
  ::ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, association_name, nil).join_associations.collect { |assoc| assoc.association_join }
end

#inner_polymorphic_join(target, options = {}) ⇒ Object

A convenience methods to create a join on a polymorphic associations target. Ex:

Audit.belong_to :auditable, :polymorphic => true User.has_many :audits, :as => :auditable

Audit.inner_polymorphic_join(:user, :as => :auditable) # =>

"INNER JOINER users ON users.id = audits.auditable_id AND audits.auditable_type = 'User'"

This is used internally by searchlogic to handle accessing conditions on polymorphic associations.



85
86
87
88
89
90
91
92
93
# File 'lib/searchlogic/active_record/named_scope_tools.rb', line 85

def inner_polymorphic_join(target, options = {})
  options[:on] ||= table_name
  options[:on_table_name] ||= connection.quote_table_name(options[:on])
  options[:target_table] ||= connection.quote_table_name(target.to_s.pluralize)
  options[:as] ||= "owner"
  postgres = ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
  "INNER JOIN #{options[:target_table]} ON #{options[:target_table]}.id = #{options[:on_table_name]}.#{options[:as]}_id AND " +
    "#{options[:on_table_name]}.#{options[:as]}_type = #{postgres ? "E" : ""}'#{target.to_s.camelize}'"
end

#left_outer_joins(association_name) ⇒ Object

See inner_joins. Does the same thing except creates LEFT OUTER joins.



96
97
98
# File 'lib/searchlogic/active_record/named_scope_tools.rb', line 96

def left_outer_joins(association_name)
  ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, association_name, nil).join_associations.collect { |assoc| assoc.association_join }
end

#named_scope_arity(name) ⇒ Object

The arity for a named scope’s proc is important, because we use the arity to determine if the condition should be ignored when calling the search method. If the condition is false and the arity is 0, then we skip it all together. Ex:

User.named_scope :age_is_4, :conditions => {:age => 4}
User.search(:age_is_4 => false) == User.all
User.search(:age_is_4 => true) == User.all(:conditions => {:age => 4})

We also use it when trying to “copy” the underlying named scope for association conditions. This way our aliased scope accepts the same number of parameters for the underlying scope.



36
37
38
39
# File 'lib/searchlogic/active_record/named_scope_tools.rb', line 36

def named_scope_arity(name)
  options = named_scope_options(name)
  options.respond_to?(:arity) ? options.arity : nil
end

#named_scope_options(name) ⇒ Object

Retrieves the options passed when creating the respective named scope. Ex:

named_scope :whatever, :conditions => {:column => value}

This method will return:

:conditions => {:column => value}

ActiveRecord hides this internally in a Proc, so we have to try and pull it out with this method.



15
16
17
18
19
20
21
22
23
# File 'lib/searchlogic/active_record/named_scope_tools.rb', line 15

def named_scope_options(name)
  key = scopes.key?(name.to_sym) ? name.to_sym : condition_scope_name(name)
  
  if key
    eval("options", scopes[key].binding)
  else
    nil
  end
end