2011-04-11 16:04:31 +00:00
|
|
|
require 'ransack/visitor'
|
2014-11-21 19:03:20 +00:00
|
|
|
|
|
|
|
if defined?(::ActiveRecord::Base)
|
|
|
|
require 'ransack/adapters/active_record/ransack/visitor'
|
|
|
|
end
|
|
|
|
|
|
|
|
if defined?(::Mongoid)
|
|
|
|
require 'ransack/adapters/mongoid/ransack/visitor'
|
|
|
|
end
|
2011-04-11 16:04:31 +00:00
|
|
|
|
2011-03-31 00:31:39 +00:00
|
|
|
module Ransack
|
|
|
|
class Context
|
2014-08-01 06:36:12 +00:00
|
|
|
attr_reader :search, :object, :klass, :base, :engine
|
2014-08-13 21:03:33 +00:00
|
|
|
attr_reader :object, :klass, :base, :engine, :arel_visitor
|
2012-04-11 15:58:27 +00:00
|
|
|
attr_accessor :auth_object, :search_key
|
2011-03-31 00:31:39 +00:00
|
|
|
|
|
|
|
class << self
|
|
|
|
|
2014-08-01 06:36:12 +00:00
|
|
|
def for_class(klass, options = {})
|
|
|
|
raise "not implemented"
|
|
|
|
end
|
|
|
|
|
|
|
|
def for_object(object, options = {})
|
|
|
|
raise "not implemented"
|
|
|
|
end
|
|
|
|
|
2011-09-03 19:37:02 +00:00
|
|
|
def for(object, options = {})
|
2013-12-10 18:06:07 +00:00
|
|
|
context = Class === object ?
|
|
|
|
for_class(object, options) :
|
|
|
|
for_object(object, options)
|
|
|
|
context or raise ArgumentError,
|
|
|
|
"Don't know what context to use for #{object}"
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
|
2014-08-01 06:36:12 +00:00
|
|
|
end # << self
|
2011-03-31 00:31:39 +00:00
|
|
|
|
2011-09-03 19:37:02 +00:00
|
|
|
def initialize(object, options = {})
|
2014-08-01 06:36:12 +00:00
|
|
|
raise "not implemented"
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
|
2013-05-23 11:33:00 +00:00
|
|
|
def klassify(obj)
|
2014-08-01 06:36:12 +00:00
|
|
|
raise "not implemented"
|
2013-05-23 11:33:00 +00:00
|
|
|
end
|
|
|
|
|
2011-03-31 00:31:39 +00:00
|
|
|
# Convert a string representing a chain of associations and an attribute
|
|
|
|
# into the attribute itself
|
|
|
|
def contextualize(str)
|
2011-04-10 00:55:28 +00:00
|
|
|
parent, attr_name = @bind_pairs[str]
|
|
|
|
table_for(parent)[attr_name]
|
|
|
|
end
|
|
|
|
|
2014-06-22 09:15:10 +00:00
|
|
|
def chain_scope(scope, args)
|
|
|
|
return unless @klass.method(scope) && args != false
|
|
|
|
@object = if scope_arity(scope) < 1 && args == true
|
|
|
|
@object.public_send(scope)
|
|
|
|
else
|
|
|
|
@object.public_send(scope, *args)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def scope_arity(scope)
|
|
|
|
@klass.method(scope).arity
|
|
|
|
end
|
|
|
|
|
2011-04-10 00:55:28 +00:00
|
|
|
def bind(object, str)
|
|
|
|
object.parent, object.attr_name = @bind_pairs[str]
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def traverse(str, base = @base)
|
2014-11-21 19:03:20 +00:00
|
|
|
str ||= Constants::EMPTY
|
2011-03-31 00:31:39 +00:00
|
|
|
|
|
|
|
if (segments = str.split(/_/)).size > 0
|
2011-10-14 15:33:19 +00:00
|
|
|
remainder = []
|
2011-03-31 00:31:39 +00:00
|
|
|
found_assoc = nil
|
2011-10-14 15:33:19 +00:00
|
|
|
while !found_assoc && segments.size > 0 do
|
2011-05-30 17:00:59 +00:00
|
|
|
# Strip the _of_Model_type text from the association name, but hold
|
|
|
|
# onto it in klass, for use as the next base
|
2014-11-21 19:03:20 +00:00
|
|
|
assoc, klass = unpolymorphize_association(
|
|
|
|
segments.join(Constants::UNDERSCORE)
|
|
|
|
)
|
2011-04-08 15:33:10 +00:00
|
|
|
if found_assoc = get_association(assoc, base)
|
2014-10-06 21:27:55 +00:00
|
|
|
base = traverse(
|
2014-10-09 21:48:38 +00:00
|
|
|
remainder.join(
|
2014-11-21 19:03:20 +00:00
|
|
|
Constants::UNDERSCORE), klass || found_assoc.klass
|
2014-10-09 21:48:38 +00:00
|
|
|
)
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
2011-10-14 15:33:19 +00:00
|
|
|
|
|
|
|
remainder.unshift segments.pop
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
2013-12-10 18:06:07 +00:00
|
|
|
raise UntraversableAssociationError,
|
|
|
|
"No association matches #{str}" unless found_assoc
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
klassify(base)
|
|
|
|
end
|
|
|
|
|
|
|
|
def association_path(str, base = @base)
|
|
|
|
base = klassify(base)
|
2014-11-21 19:03:20 +00:00
|
|
|
str ||= Constants::EMPTY
|
2011-03-31 00:31:39 +00:00
|
|
|
path = []
|
|
|
|
segments = str.split(/_/)
|
|
|
|
association_parts = []
|
|
|
|
if (segments = str.split(/_/)).size > 0
|
2014-10-09 21:48:38 +00:00
|
|
|
while segments.size > 0 &&
|
2014-11-21 19:03:20 +00:00
|
|
|
!base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
|
2013-12-10 18:06:07 +00:00
|
|
|
association_parts << segments.shift do
|
2014-10-06 21:27:55 +00:00
|
|
|
assoc, klass = unpolymorphize_association(
|
2014-11-21 19:03:20 +00:00
|
|
|
association_parts.join(Constants::UNDERSCORE)
|
2014-10-06 21:27:55 +00:00
|
|
|
)
|
2011-04-08 15:33:10 +00:00
|
|
|
if found_assoc = get_association(assoc, base)
|
2011-03-31 00:31:39 +00:00
|
|
|
path += association_parts
|
|
|
|
association_parts = []
|
2011-04-08 15:33:10 +00:00
|
|
|
base = klassify(klass || found_assoc)
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-11-21 19:03:20 +00:00
|
|
|
path.join(Constants::UNDERSCORE)
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
|
2011-04-08 15:33:10 +00:00
|
|
|
def unpolymorphize_association(str)
|
2011-08-04 21:10:33 +00:00
|
|
|
if (match = str.match(/_of_([^_]+?)_type$/))
|
2011-04-08 15:33:10 +00:00
|
|
|
[match.pre_match, Kernel.const_get(match.captures.first)]
|
|
|
|
else
|
|
|
|
[str, nil]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-30 17:00:59 +00:00
|
|
|
def ransackable_attribute?(str, klass)
|
2013-12-07 00:51:55 +00:00
|
|
|
klass.ransackable_attributes(auth_object).include?(str) ||
|
2013-12-10 18:06:07 +00:00
|
|
|
klass.ransortable_attributes(auth_object).include?(str)
|
2011-05-30 17:00:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def ransackable_association?(str, klass)
|
|
|
|
klass.ransackable_associations(auth_object).include? str
|
|
|
|
end
|
|
|
|
|
2014-06-22 09:15:10 +00:00
|
|
|
def ransackable_scope?(str, klass)
|
|
|
|
klass.ransackable_scopes(auth_object).any? { |s| s.to_s == str }
|
|
|
|
end
|
|
|
|
|
2014-11-21 19:03:20 +00:00
|
|
|
def searchable_attributes(str = Constants::EMPTY)
|
2011-04-12 00:07:23 +00:00
|
|
|
traverse(str).ransackable_attributes(auth_object)
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
|
2014-11-21 19:03:20 +00:00
|
|
|
def sortable_attributes(str = Constants::EMPTY)
|
2013-12-10 18:06:07 +00:00
|
|
|
traverse(str).ransortable_attributes(auth_object)
|
2011-05-30 17:00:59 +00:00
|
|
|
end
|
2013-02-20 03:45:02 +00:00
|
|
|
|
2014-11-21 19:03:20 +00:00
|
|
|
def searchable_associations(str = Constants::EMPTY)
|
2011-05-30 17:00:59 +00:00
|
|
|
traverse(str).ransackable_associations(auth_object)
|
|
|
|
end
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
2013-05-23 09:59:32 +00:00
|
|
|
end
|