Class: ReactiveRecord::ScopeDescription
- Defined in:
- lib/reactive_record/scope_description.rb
Overview
Keeps track of the details (client side) of a scope. The main point is to provide knowledge of what models the scope is joined with, and the client side filter proc
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Class Method Summary collapse
Instance Method Summary collapse
- #build_error(path, model, attribute) ⇒ Object
- #build_joins(joins_list) ⇒ Object
- #collector? ⇒ Boolean
- #crawl(item, method = nil, *vector) ⇒ Object
- #filter? ⇒ Boolean
-
#filter_proc(opts) ⇒ Object
private methods.
- #filter_records(related_records, args) ⇒ Object
- #get_joins(klass) ⇒ Object
-
#initialize(model, name, opts) ⇒ ScopeDescription
constructor
A new instance of ScopeDescription.
- #joins_with?(record) ⇒ Boolean
- #map_joins_path(paths) ⇒ Object
- #related_records_for(record) ⇒ Object
Constructor Details
#initialize(model, name, opts) ⇒ ScopeDescription
Returns a new instance of ScopeDescription.
7 8 9 10 11 12 13 14 15 16 |
# File 'lib/reactive_record/scope_description.rb', line 7 def initialize(model, name, opts) sself = self @filter_proc = filter_proc(opts) @name = name model.singleton_class.send(:define_method, "_#{@name}_synchromesh_scope_description_") do sself end @model = model build_joins opts[:joins] end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
18 19 20 |
# File 'lib/reactive_record/scope_description.rb', line 18 def name @name end |
Class Method Details
.find(target_model, name) ⇒ Object
20 21 22 23 24 25 |
# File 'lib/reactive_record/scope_description.rb', line 20 def self.find(target_model, name) name = name.gsub(/!$/, '') target_model.send "_#{name}_synchromesh_scope_description_" rescue nil end |
Instance Method Details
#build_error(path, model, attribute) ⇒ Object
104 105 106 107 |
# File 'lib/reactive_record/scope_description.rb', line 104 def build_error(path, model, attribute) "Could not find joins association '#{model.name}.#{attribute}' "\ "for '#{path}' while processing scope #{@model.name}.#{@name}." end |
#build_joins(joins_list) ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/reactive_record/scope_description.rb', line 76 def build_joins(joins_list) if !@filter_proc || joins_list == [] @joins = { all: [] } elsif joins_list.nil? klass = @model < ActiveRecord::Base ? @model.base_class : @model @joins = { klass => [[]], all: [] } elsif joins_list == :all @joins = { all: [[]] } else joins_list = [joins_list] unless joins_list.is_a? Array map_joins_path joins_list end end |
#collector? ⇒ Boolean
31 32 33 |
# File 'lib/reactive_record/scope_description.rb', line 31 def collector? @is_collector end |
#crawl(item, method = nil, *vector) ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/reactive_record/scope_description.rb', line 109 def crawl(item, method = nil, *vector) if !method && item.is_a?(Collection) item.all elsif !method item elsif item.respond_to? :collect item.collect { |record| crawl(record.send(method), *vector) } else crawl(item.send(method), *vector) end end |
#filter? ⇒ Boolean
27 28 29 |
# File 'lib/reactive_record/scope_description.rb', line 27 def filter? @filter_proc.respond_to?(:call) end |
#filter_proc(opts) ⇒ Object
private methods
68 69 70 71 72 73 74 |
# File 'lib/reactive_record/scope_description.rb', line 68 def filter_proc(opts) return true unless opts.key?(:client) || opts.key?(:select) client_opt = opts[:client] || opts[:select] @is_collector = opts.key?(:select) return client_opt if !client_opt || client_opt.respond_to?(:call) raise 'Scope option :client or :select must be a proc, false, or nil' end |
#filter_records(related_records, args) ⇒ Object
58 59 60 61 62 63 64 |
# File 'lib/reactive_record/scope_description.rb', line 58 def filter_records(, args) if collector? Set.new(.to_a.instance_exec(*args, &@filter_proc)) else Set.new(.select { |r| r.instance_exec(*args, &@filter_proc) }) end end |
#get_joins(klass) ⇒ Object
44 45 46 47 48 |
# File 'lib/reactive_record/scope_description.rb', line 44 def get_joins(klass) joins = @joins[klass] if @joins.key? klass joins ||= @joins[klass.base_class] if @joins.key?(klass.base_class) joins || @joins[:all] end |
#joins_with?(record) ⇒ Boolean
35 36 37 38 39 40 41 42 |
# File 'lib/reactive_record/scope_description.rb', line 35 def joins_with?(record) @joins.detect do |klass, vector| # added klass < record.class to handle STI case... should check to see if this could ever # cause a problem. Probably not a problem. next unless vector.any? (klass == :all || record.class == klass || record.class < klass || klass < record.class) end end |
#map_joins_path(paths) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/reactive_record/scope_description.rb', line 90 def map_joins_path(paths) @joins = Hash.new { |h, k| h[k] = Array.new }.merge(@model => [[]]) paths.each do |path| vector = [] path.split('.').inject(@model) do |model, attribute| association = model.reflect_on_association(attribute) raise build_error(path, model, attribute) unless association vector = [association.inverse_of, *vector] @joins[association.klass] << vector association.klass end end end |
#related_records_for(record) ⇒ Object
50 51 52 53 54 55 56 |
# File 'lib/reactive_record/scope_description.rb', line 50 def (record) ReactiveRecord::Base.catch_db_requests([]) do get_joins(record.class).collect do |vector| crawl(record, *vector) end.flatten.compact end end |