Class: RecordCollection::Base

Inherits:
Object
  • Object
show all
Includes:
ActiveAttr::Model, Enumerable
Defined in:
lib/record_collection/base.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(collection = [], params = {}) ⇒ Base



81
82
83
84
# File 'lib/record_collection/base.rb', line 81

def initialize(collection = [], params = {})
  super(params) # active attr initialize with params
  @collection = collection
end

Instance Attribute Details

#collectionObject (readonly)

Returns the value of attribute collection.



6
7
8
# File 'lib/record_collection/base.rb', line 6

def collection
  @collection
end

Class Method Details

.after_record_update(&blk) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/record_collection/base.rb', line 38

def after_record_update(&blk)
  if blk
    @after_record_update = blk
  else
    @after_record_update
  end
end

.all(*args) ⇒ Object



76
77
78
# File 'lib/record_collection/base.rb', line 76

def all(*args)
  self.new(record_class.all(*args))
end

.before_record_update(&blk) ⇒ Object



30
31
32
33
34
35
36
# File 'lib/record_collection/base.rb', line 30

def before_record_update(&blk)
  if blk
    @before_record_update = blk
  else
    @before_record_update
  end
end

.find(ids) ⇒ Object

FINDERS



56
57
58
59
60
61
62
63
64
# File 'lib/record_collection/base.rb', line 56

def find(ids)
  raise "Cannot call find on a collection object if there is no record_class defined" unless respond_to?(:record_class) && record_class
  collection = case ids.presence
    when String then record_class.find(ids.split(RecordCollection.ids_separator))
    when nil then []
    else record_class.find(Array.wrap(ids))
  end
  self.new(collection)
end

.human_attribute_name(*args) ⇒ Object



14
15
16
17
# File 'lib/record_collection/base.rb', line 14

def human_attribute_name(*args)
  raise "No record_class defined and could not be inferred based on the inheritance namespace. Please define self.record_clas = ClassNameOfIndividualRecords in the collection" unless record_class.present?
  record_class.human_attribute_name(*args)
end

.joins(*args) ⇒ Object

Create a new collection with the scope set to the result of the query on the record_class



72
73
74
# File 'lib/record_collection/base.rb', line 72

def joins(*args)
  self.new(record_class.joins(*args))
end

.model_nameObject



10
11
12
# File 'lib/record_collection/base.rb', line 10

def model_name
  RecordCollection::Name.new(self)
end

.old_validatesObject



46
# File 'lib/record_collection/base.rb', line 46

alias_method :old_validates, :validates

.record_classObject

GETTER



20
21
22
23
# File 'lib/record_collection/base.rb', line 20

def record_class
  return @record_class if defined?(@record_class)
  @record_class = name.deconstantize.safe_constantize
end

.record_class=(klass) ⇒ Object

SETTER



26
27
28
# File 'lib/record_collection/base.rb', line 26

def record_class=(klass)
  @record_class = klass
end

.validates(attr, options) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/record_collection/base.rb', line 47

def validates(attr, options)
  # Collection nil attributes mean they do not play a role for the collection.
  # So validating when the value is nil is not the default behaviour. I to be turned on explicitly
  # by specifying allow_nil: false
  options[:allow_nil] = true unless options.has_key?(:allow_nil)
  old_validates attr, options
end

.where(*args) ⇒ Object

Create a new collection with the scope set to the result of the query on the record_class



67
68
69
# File 'lib/record_collection/base.rb', line 67

def where(*args)
  self.new(record_class.where(*args))
end

Instance Method Details

#changed_attributesObject

Return a hash of the changed attributes of the collection:

{
  name: 'Ben',
  ....etc...
}


136
137
138
# File 'lib/record_collection/base.rb', line 136

def changed_attributes
  @changed_attributes ||= attributes.reject{|attr, val| val.nil? }
end

#each(&block) ⇒ Object

implement enumerable logic for collection



87
88
89
90
91
92
93
94
95
# File 'lib/record_collection/base.rb', line 87

def each(&block)
  collection.each do |record|
    if block_given?
      block.call record
    else
      yield record
    end
  end
end

#idsObject



173
174
175
# File 'lib/record_collection/base.rb', line 173

def ids
  @ids ||= map{|record| record.try(:id) }.compact
end

#model_nameObject

delegate model name to class



178
179
180
# File 'lib/record_collection/base.rb', line 178

def model_name
  self.class.model_name
end

#not(*args) ⇒ Object

update existing scope with new one having applied not clause if possible



189
190
191
192
# File 'lib/record_collection/base.rb', line 189

def not(*args)
  @collection = @collection.not(*args)
  self
end

#persisted?Boolean



140
141
142
143
# File 'lib/record_collection/base.rb', line 140

def persisted?
  # Behave like an update in forms, this triggers plural routes
  false
end

#saveObject



97
98
99
# File 'lib/record_collection/base.rb', line 97

def save
  valid? && update_collection_attributes!
end

#to_aryObject



145
146
147
# File 'lib/record_collection/base.rb', line 145

def to_ary(*)
  self
end

#uniform_collection_attribute(attr, options = {}) ⇒ Object

This method returns nil when the values of attr in the collection are mixed. Otherwise the value itself. For boolean attributes the check is wether the values are truthy or falsy. If the

set_if_nil: true

option is given, a uniform value will be set as the collection value if it is not already set. This is important since there might be a uniform value in the collection, but the values of the collection are a result of an invalid form submission. In this case you want to keep the values of the submitted form as collection values, not the current uniform attribute.



158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/record_collection/base.rb', line 158

def uniform_collection_attribute(attr, options = {})
  attribute_spec = self.class.attributes[attr]
  raise "Attribute #{attr} not defined on collection" unless attribute_spec
  if attribute_spec[:type] == Boolean
    # For boolean attributes presence is the true or false difference
    # not the value itself
    results = map{|r| r.public_send(attr).present? }.uniq
  else
    results = map{|r| r.public_send(attr) }.uniq
  end
  return nil unless results.size == 1 # one value found
  public_send("#{attr}=", results.first) if options[:set_if_nil] and public_send(attr).nil? # set value on the object if it is uniform and not yet set
  results.first
end

#update(attributes) ⇒ Object



101
102
103
104
# File 'lib/record_collection/base.rb', line 101

def update(attributes)
  self.attributes = attributes
  save
end

#update_collection_attributes!Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/record_collection/base.rb', line 106

def update_collection_attributes!
  after_blk = self.class.after_record_update
  before_blk = self.class.before_record_update
  each do |record|
    if before_blk
      #before_blk = before_blk.to_proc unless before_blk.is_a?(Proc) # Allow symbol to proc without cumbersome notation
      if before_blk.arity.zero?
        record.instance_eval(&before_blk)
      else
        before_blk.call(record)
      end
    end
    record.update changed_attributes
    if after_blk
      #after_blk = after_blk.to_proc unless after_blk.is_a?(Proc) # Allow symbol to proc without cumbersome notation
      if after_blk.arity.zero?
        record.instance_eval(&after_blk)
      else
        after_blk.call(record)
      end
    end
  end
  self
end

#where(*args) ⇒ Object

update existing scope with new one having applied where clause if possible



183
184
185
186
# File 'lib/record_collection/base.rb', line 183

def where(*args)
  @collection = @collection.where(*args)
  self
end