mongoid initialized
This commit is contained in:
parent
e5b6014a53
commit
d16c8b0c1b
|
@ -20,9 +20,11 @@ end
|
|||
|
||||
require 'ransack/translate'
|
||||
require 'ransack/adapters/active_record/ransack/translate' if defined?(::ActiveRecord::Base)
|
||||
require 'ransack/adapters/mongoid/ransack/translate' if defined?(::Mongoid)
|
||||
require 'ransack/search'
|
||||
require 'ransack/ransacker'
|
||||
require 'ransack/adapters/active_record' if defined?(::ActiveRecord::Base)
|
||||
require 'ransack/adapters/mongoid' if defined?(::Mongoid)
|
||||
require 'ransack/helpers'
|
||||
require 'action_controller'
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
require 'ransack/adapters/mongoid/base'
|
||||
Mongoid::Document.extend Ransack::Adapters::Mongoid::Base
|
||||
|
||||
case Mongoid::VERSION::STRING
|
||||
when /^3\.2\./
|
||||
require 'ransack/adapters/mongoid/3.2/context'
|
||||
else
|
||||
require 'ransack/adapters/mongoid/context'
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
module Ransack
|
||||
module Adapters
|
||||
module Mongoid
|
||||
module Base
|
||||
|
||||
def self.extended(base)
|
||||
alias :search :ransack unless base.respond_to? :search
|
||||
base.class_eval do
|
||||
class_attribute :_ransackers
|
||||
self._ransackers ||= {}
|
||||
end
|
||||
end
|
||||
|
||||
def ransack(params = {}, options = {})
|
||||
params = params.presence || {}
|
||||
Search.new(self, params ? params.delete_if {
|
||||
|k, v| v.blank? && v != false } : params, options)
|
||||
end
|
||||
|
||||
def ransacker(name, opts = {}, &block)
|
||||
self._ransackers = _ransackers.merge name.to_s => Ransacker
|
||||
.new(self, name, opts, &block)
|
||||
end
|
||||
|
||||
def ransackable_attributes(auth_object = nil)
|
||||
column_names + _ransackers.keys
|
||||
end
|
||||
|
||||
def ransortable_attributes(auth_object = nil)
|
||||
# Here so users can overwrite the attributes
|
||||
# that show up in the sort_select
|
||||
ransackable_attributes(auth_object)
|
||||
end
|
||||
|
||||
def ransackable_associations(auth_object = nil)
|
||||
reflect_on_all_associations.map { |a| a.name.to_s }
|
||||
end
|
||||
|
||||
# For overriding with a whitelist of symbols
|
||||
def ransackable_scopes(auth_object = nil)
|
||||
[]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,231 @@
|
|||
require 'ransack/context'
|
||||
require 'polyamorous'
|
||||
|
||||
module Ransack
|
||||
module Adapters
|
||||
module Mongoid
|
||||
class Context < ::Ransack::Context
|
||||
|
||||
# Because the AR::Associations namespace is insane
|
||||
JoinDependency = ::Mongoid::Associations::JoinDependency
|
||||
JoinPart = JoinDependency::JoinPart
|
||||
|
||||
def initialize(object, options = {})
|
||||
super
|
||||
@arel_visitor = @engine.connection.visitor
|
||||
end
|
||||
|
||||
def relation_for(object)
|
||||
object.all
|
||||
end
|
||||
|
||||
def type_for(attr)
|
||||
return nil unless attr && attr.valid?
|
||||
name = attr.arel_attribute.name.to_s
|
||||
table = attr.arel_attribute.relation.table_name
|
||||
|
||||
schema_cache = @engine.connection.schema_cache
|
||||
raise "No table named #{table} exists" unless schema_cache.table_exists?(table)
|
||||
schema_cache.columns_hash(table)[name].type
|
||||
end
|
||||
|
||||
def evaluate(search, opts = {})
|
||||
viz = Visitor.new
|
||||
relation = @object.where(viz.accept(search.base))
|
||||
if search.sorts.any?
|
||||
relation = relation.except(:order)
|
||||
.reorder(viz.accept(search.sorts))
|
||||
end
|
||||
opts[:distinct] ? relation.distinct : relation
|
||||
end
|
||||
|
||||
def attribute_method?(str, klass = @klass)
|
||||
exists = false
|
||||
if ransackable_attribute?(str, klass)
|
||||
exists = true
|
||||
elsif (segments = str.split(/_/)).size > 1
|
||||
remainder = []
|
||||
found_assoc = nil
|
||||
while !found_assoc && remainder.unshift(
|
||||
segments.pop) && segments.size > 0 do
|
||||
assoc, poly_class = unpolymorphize_association(
|
||||
segments.join('_')
|
||||
)
|
||||
if found_assoc = get_association(assoc, klass)
|
||||
exists = attribute_method?(remainder.join('_'),
|
||||
poly_class || found_assoc.klass
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
exists
|
||||
end
|
||||
|
||||
def table_for(parent)
|
||||
parent.table
|
||||
end
|
||||
|
||||
def klassify(obj)
|
||||
if Class === obj && ::Mongoid::Base > obj
|
||||
obj
|
||||
elsif obj.respond_to? :klass
|
||||
obj.klass
|
||||
elsif obj.respond_to? :base_klass
|
||||
obj.base_klass
|
||||
else
|
||||
raise ArgumentError, "Don't know how to klassify #{obj}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_parent_and_attribute_name(str, parent = @base)
|
||||
attr_name = nil
|
||||
|
||||
if ransackable_attribute?(str, klassify(parent))
|
||||
attr_name = str
|
||||
elsif (segments = str.split(/_/)).size > 1
|
||||
remainder = []
|
||||
found_assoc = nil
|
||||
while remainder.unshift(
|
||||
segments.pop) && segments.size > 0 && !found_assoc do
|
||||
assoc, klass = unpolymorphize_association(segments.join('_'))
|
||||
if found_assoc = get_association(assoc, parent)
|
||||
join = build_or_find_association(found_assoc.name, parent, klass)
|
||||
parent, attr_name = get_parent_and_attribute_name(
|
||||
remainder.join('_'), join
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[parent, attr_name]
|
||||
end
|
||||
|
||||
def get_association(str, parent = @base)
|
||||
klass = klassify parent
|
||||
ransackable_association?(str, klass) &&
|
||||
klass.reflect_on_all_associations.detect { |a| a.name.to_s == str }
|
||||
end
|
||||
|
||||
def join_dependency(relation)
|
||||
if relation.respond_to?(:join_dependency) # Squeel will enable this
|
||||
relation.join_dependency
|
||||
else
|
||||
build_join_dependency(relation)
|
||||
end
|
||||
end
|
||||
|
||||
# Checkout mongoid/relation/query_methods.rb +build_joins+ for
|
||||
# reference. Lots of duplicated code maybe we can avoid it
|
||||
def build_join_dependency(relation)
|
||||
buckets = relation.joins_values.group_by do |join|
|
||||
case join
|
||||
when String
|
||||
'string_join'
|
||||
when Hash, Symbol, Array
|
||||
'association_join'
|
||||
when JoinDependency, JoinDependency::JoinAssociation
|
||||
'stashed_join'
|
||||
when Arel::Nodes::Join
|
||||
'join_node'
|
||||
else
|
||||
raise 'unknown class: %s' % join.class.name
|
||||
end
|
||||
end
|
||||
|
||||
association_joins = buckets['association_join'] || []
|
||||
|
||||
stashed_association_joins = buckets['stashed_join'] || []
|
||||
|
||||
join_nodes = buckets['join_node'] || []
|
||||
|
||||
string_joins = (buckets['string_join'] || [])
|
||||
.map { |x| x.strip }
|
||||
.uniq
|
||||
|
||||
join_list = relation.send :custom_join_ast,
|
||||
relation.table.from(relation.table), string_joins
|
||||
|
||||
join_dependency = JoinDependency.new(
|
||||
relation.klass, association_joins, join_list
|
||||
)
|
||||
|
||||
join_nodes.each do |join|
|
||||
join_dependency.alias_tracker.aliases[join.left.name.downcase] = 1
|
||||
end
|
||||
|
||||
if ::Mongoid::VERSION::STRING >= '4.1'
|
||||
join_dependency
|
||||
else
|
||||
join_dependency.graft(*stashed_association_joins)
|
||||
end
|
||||
end
|
||||
|
||||
if ::Mongoid::VERSION::STRING >= '4.1'
|
||||
|
||||
def build_or_find_association(name, parent = @base, klass = nil)
|
||||
found_association = @join_dependency.join_root.children
|
||||
.detect do |assoc|
|
||||
assoc.reflection.name == name &&
|
||||
(@associations_pot.nil? || @associations_pot[assoc] == parent) &&
|
||||
(!klass || assoc.reflection.klass == klass)
|
||||
end
|
||||
|
||||
unless found_association
|
||||
jd = JoinDependency.new(
|
||||
parent.base_klass,
|
||||
Polyamorous::Join.new(name, @join_type, klass),
|
||||
[]
|
||||
)
|
||||
found_association = jd.join_root.children.last
|
||||
associations found_association, parent
|
||||
|
||||
# TODO maybe we dont need to push associations here, we could loop
|
||||
# through the @associations_pot instead
|
||||
@join_dependency.join_root.children.push found_association
|
||||
|
||||
# Builds the arel nodes properly for this association
|
||||
@join_dependency.send(
|
||||
:construct_tables!, jd.join_root, found_association
|
||||
)
|
||||
|
||||
# Leverage the stashed association functionality in AR
|
||||
@object = @object.joins(jd)
|
||||
end
|
||||
found_association
|
||||
end
|
||||
|
||||
def associations(assoc, parent)
|
||||
@associations_pot ||= {}
|
||||
@associations_pot[assoc] = parent
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
def build_or_find_association(name, parent = @base, klass = nil)
|
||||
found_association = @join_dependency.join_associations
|
||||
.detect do |assoc|
|
||||
assoc.reflection.name == name &&
|
||||
assoc.parent == parent &&
|
||||
(!klass || assoc.reflection.klass == klass)
|
||||
end
|
||||
unless found_association
|
||||
@join_dependency.send(
|
||||
:build,
|
||||
Polyamorous::Join.new(name, @join_type, klass),
|
||||
parent
|
||||
)
|
||||
found_association = @join_dependency.join_associations.last
|
||||
# Leverage the stashed association functionality in AR
|
||||
@object = @object.joins(found_association)
|
||||
end
|
||||
found_association
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
require 'ransack/visitor'
|
||||
|
||||
module Ransack
|
||||
class Context
|
||||
attr_reader :arel_visitor
|
||||
|
||||
class << self
|
||||
|
||||
def for_class(klass, options = {})
|
||||
if klass < ActiveRecord::Base
|
||||
Adapters::ActiveRecord::Context.new(klass, options)
|
||||
end
|
||||
end
|
||||
|
||||
def for_object(object, options = {})
|
||||
case object
|
||||
when ActiveRecord::Relation
|
||||
Adapters::ActiveRecord::Context.new(object.klass, options)
|
||||
end
|
||||
end
|
||||
|
||||
end # << self
|
||||
|
||||
def initialize(object, options = {})
|
||||
@object = relation_for(object)
|
||||
@klass = @object.klass
|
||||
@join_dependency = join_dependency(@object)
|
||||
@join_type = options[:join_type] || Arel::OuterJoin
|
||||
@search_key = options[:search_key] || Ransack.options[:search_key]
|
||||
|
||||
if ::ActiveRecord::VERSION::STRING >= "4.1"
|
||||
@base = @join_dependency.join_root
|
||||
@engine = @base.base_klass.arel_engine
|
||||
else
|
||||
@base = @join_dependency.join_base
|
||||
@engine = @base.arel_engine
|
||||
end
|
||||
|
||||
@default_table = Arel::Table.new(
|
||||
@base.table_name, :as => @base.aliased_table_name, :engine => @engine
|
||||
)
|
||||
@bind_pairs = Hash.new do |hash, key|
|
||||
parent, attr_name = get_parent_and_attribute_name(key.to_s)
|
||||
if parent && attr_name
|
||||
hash[key] = [parent, attr_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def klassify(obj)
|
||||
if Class === obj && ::ActiveRecord::Base > obj
|
||||
obj
|
||||
elsif obj.respond_to? :klass
|
||||
obj.klass
|
||||
elsif obj.respond_to? :active_record # Rails 3
|
||||
obj.active_record
|
||||
elsif obj.respond_to? :base_klass # Rails 4
|
||||
obj.base_klass
|
||||
else
|
||||
raise ArgumentError, "Don't know how to klassify #{obj.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
module Ransack
|
||||
module Nodes
|
||||
class Condition
|
||||
|
||||
def arel_predicate
|
||||
predicates = attributes.map do |attr|
|
||||
attr.attr.send(
|
||||
arel_predicate_for_attribute(attr),
|
||||
formatted_values_for_attribute(attr)
|
||||
)
|
||||
end
|
||||
|
||||
if predicates.size > 1
|
||||
case combinator
|
||||
when 'and'
|
||||
Arel::Nodes::Grouping.new(Arel::Nodes::And.new(predicates))
|
||||
when 'or'
|
||||
predicates.inject(&:or)
|
||||
end
|
||||
else
|
||||
predicates.first
|
||||
end
|
||||
end
|
||||
|
||||
end # Condition
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
module Ransack
|
||||
module Translate
|
||||
|
||||
def self.i18n_key(klass)
|
||||
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
|
||||
klass.model_name.i18n_key.to_s.tr('.', '/')
|
||||
else
|
||||
klass.model_name.i18n_key.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
module Ransack
|
||||
class Visitor
|
||||
def visit_and(object)
|
||||
nodes = object.values.map { |o| accept(o) }.compact
|
||||
return nil unless nodes.size > 0
|
||||
|
||||
if nodes.size > 1
|
||||
Arel::Nodes::Grouping.new(Arel::Nodes::And.new(nodes))
|
||||
else
|
||||
nodes.first
|
||||
end
|
||||
end
|
||||
|
||||
def quoted?(object)
|
||||
case object
|
||||
when Arel::Nodes::SqlLiteral, Bignum, Fixnum
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,5 +1,6 @@
|
|||
require 'ransack/visitor'
|
||||
require 'ransack/adapters/active_record/ransack/visitor' if defined?(::ActiveRecord::Base)
|
||||
require 'ransack/adapters/mongoid/ransack/visitor' if defined?(::Mongoid)
|
||||
|
||||
module Ransack
|
||||
class Context
|
||||
|
|
|
@ -4,5 +4,6 @@ require 'ransack/nodes/attribute'
|
|||
require 'ransack/nodes/value'
|
||||
require 'ransack/nodes/condition'
|
||||
require 'ransack/adapters/active_record/ransack/nodes/condition' if defined?(::ActiveRecord::Base)
|
||||
require 'ransack/adapters/mongoid/ransack/nodes/condition' if defined?(::Mongoid)
|
||||
require 'ransack/nodes/sort'
|
||||
require 'ransack/nodes/grouping'
|
|
@ -1,6 +1,7 @@
|
|||
require 'ransack/nodes'
|
||||
require 'ransack/context'
|
||||
require 'ransack/adapters/active_record/ransack/context' if defined?(::ActiveRecord::Base)
|
||||
require 'ransack/adapters/mongoid/ransack/context' if defined?(::Mongoid)
|
||||
require 'ransack/naming'
|
||||
|
||||
module Ransack
|
||||
|
|
Loading…
Reference in New Issue