activerecord-cached_at 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf203856f29f1e18a87be4892db7fd3396208cbb
4
- data.tar.gz: 960fc526cd4f5ed35aa6ba3028c8ca367d850ac1
3
+ metadata.gz: 7b3d64e5e2adb795b942f664462d24ed6ed4d7f2
4
+ data.tar.gz: 95bef73c44b5dc5a34d066326a0f143e71a6aed1
5
5
  SHA512:
6
- metadata.gz: 8fe18f63b67fd3b7a3e0159f1a1985670c141511e60dcc5b1ee1d05e9fa8ef81a8d8e4d7f0fda6c16bee4a5fef8e84f22d0f1908a1f22c821d65be29da1aa3fe
7
- data.tar.gz: f6b97535599ac6c02afe3fe63713590065bea24c56e5d6ec7b385e4ad968025c63b75dab3e8ae046a933f972d013ef7dd43911fe9c1868e7b585cbf452e28c11
6
+ metadata.gz: a3cb5c3704956ee085247bbbf12f504feba96eed6604cdf73488055acbf71479d9e91e838433320a22ad14c1cd3b60fade816d7170809036814c7cf4bb60321b
7
+ data.tar.gz: ae7d263524467b04d8d90687f392a2e7db39714282e73f9bd8b89ab69f0b245c9f72c02289d848ba6e523ab8d0ea5d8628b72b09419ea2a4019bd302ba1b121f
@@ -0,0 +1,15 @@
1
+ module CachedAt
2
+ module AssociationExtension
3
+
4
+ def self.build(model, reflection)
5
+ return unless reflection.options[:cached_at]
6
+ end
7
+
8
+ def self.valid_options
9
+ [:cached_at]
10
+ end
11
+
12
+ end
13
+ end
14
+
15
+ ActiveRecord::Associations::Builder::Association.extensions << CachedAt::AssociationExtension
@@ -29,53 +29,38 @@ module CachedAt
29
29
  end
30
30
  end
31
31
  end
32
-
33
- def touch_records_added_cached_at(records, timestamp)
34
- return if owner.new_record? || records.empty?
35
-
36
- if reflection.options[:cached_at]
37
- if reflection.inverse_of.nil?
38
- puts "WARNING: cannot updated cached at for relationship: #{klass.name}.#{name}, inverse_of not set"
39
- return
40
- end
41
-
42
- cache_column = "#{reflection.inverse_of.name}_cached_at"
43
- if loaded?
44
- target.each { |r| r.raw_write_attribute(cache_column, timestamp) }
45
- end
46
-
47
- ids = records.inject([]) { |a, o| a += [o.send(klass.primary_key), o.send("#{klass.primary_key}_was")] }.compact.uniq
48
- query = klass.where(klass.primary_key => ids)
49
- query.update_all({ cache_column => timestamp })
50
- traverse_relationships(klass, reflection.options[:cached_at], query, cache_column, timestamp)
51
- end
52
- end
53
-
54
- def touch_records_removed_cached_at(records, timestamp)
55
- return if owner.new_record? || records.empty?
56
-
32
+
33
+ def touch_records_cached_at(records, timestamp)
57
34
  return unless options[:cached_at]
58
35
 
59
36
  if reflection.inverse_of.nil?
60
- puts "WARNING: cannot updated cached at for relationship: #{klass.name}.#{name}, inverse_of not set"
37
+ puts "WARNING: cannot updated cached at for relationship: #{owner.class.name}.#{name}, inverse_of not set"
61
38
  return
62
39
  end
63
-
40
+
64
41
  cache_column = "#{reflection.inverse_of.name}_cached_at"
65
- ids = records.inject([]) { |a, o| a += [o.send(klass.primary_key), o.send("#{klass.primary_key}_was")] }.compact.uniq
66
- query = klass.where(klass.primary_key => ids)
67
- traverse_relationships(klass, reflection.options[:cached_at], query, cache_column, timestamp)
42
+
43
+ records.each { |r| r.raw_write_attribute(cache_column, timestamp) unless r.destroyed? }
44
+
45
+ query = klass.where({ klass.primary_key => records.map(&:id) })
46
+ query.update_all({ cache_column => timestamp })
47
+ traverse_relationships(klass, options[:cached_at], query, cache_column, timestamp)
68
48
  end
69
-
70
- def concat_records(records, should_raise = false)
49
+
50
+ def add_to_target(record, skip_callbacks = false, &block)
71
51
  value = super
72
- touch_records_added_cached_at(records, Time.now)
52
+ touch_records_cached_at([record], Time.now) if !(instance_variable_defined?(:@caching) && @caching)
73
53
  value
74
54
  end
75
-
76
- def remove_records(existing_records, records, method)
77
- touch_records_removed_cached_at(existing_records, Time.now)
78
- super
55
+
56
+ def replace_records(new_target, original_target)
57
+ @caching = true
58
+ changed_records = (target - new_target) | (new_target - target)
59
+ value = super
60
+ touch_records_cached_at(changed_records, Time.now) unless owner.new_record?
61
+ value
62
+ ensure
63
+ @caching = false
79
64
  end
80
65
 
81
66
  def delete_all(dependent = nil)
@@ -5,97 +5,56 @@ module CachedAt
5
5
  using_reflection = reflection.parent_reflection || reflection
6
6
  return unless using_reflection.options[:cached_at]
7
7
 
8
+ return if method == :create && !using_reflection.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
9
+
8
10
  if using_reflection.inverse_of.nil?
9
11
  puts "WARNING: cannot updated cached at for relationship: #{owner.class.name}.#{using_reflection.name}, inverse_of not set"
10
12
  return
11
13
  end
12
14
 
13
15
  cache_column = "#{using_reflection.inverse_of.name}_cached_at"
14
- ids = [owner.send(using_reflection.association_primary_key), owner.send("#{using_reflection.association_primary_key}_was")].compact.uniq
15
-
16
-
17
- arel_table = klass._reflections[using_reflection.inverse_of.options[:through].to_s].klass.arel_table
18
- query = klass.joins(using_reflection.inverse_of.options[:through])
19
- query = if using_reflection.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
20
- query.where(arel_table[using_reflection.foreign_key].in(ids))
21
- else
22
- query.where(arel_table[using_reflection.inverse_of.foreign_key].in(ids))
23
- end
24
16
 
17
+ query = nil
25
18
  if loaded?
26
19
  target.each { |r| r.raw_write_attribute(cache_column, timestamp) }
20
+ query = klass.where(klass.primary_key => target.map(&:id))
21
+ else
22
+ ids = [owner.send(using_reflection.association_primary_key), owner.send("#{using_reflection.association_primary_key}_was")].compact.uniq
23
+ arel_table = klass._reflections[using_reflection.inverse_of.options[:through].to_s].klass.arel_table
24
+ query = klass.joins(using_reflection.inverse_of.options[:through])
25
+ query = if using_reflection.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
26
+ query.where(arel_table[using_reflection.foreign_key].in(ids))
27
+ else
28
+ query.where(arel_table[using_reflection.inverse_of.foreign_key].in(ids))
29
+ end
27
30
  end
28
-
31
+
29
32
  query.update_all({ cache_column => timestamp })
30
33
  traverse_relationships(klass, options[:cached_at], query, cache_column, timestamp)
31
34
  end
32
35
 
33
- def touch_records_added_cached_at(records, timestamp)
34
- return if owner.new_record? || records.empty?
35
-
36
+ def touch_records_cached_at(records, timestamp)
36
37
  using_reflection = reflection.parent_reflection || reflection
37
-
38
+
38
39
  if using_reflection.options[:cached_at]
39
-
40
40
  if using_reflection.inverse_of.nil?
41
41
  puts "WARNING: cannot updated cached at for relationship: #{klass.name}.#{name}, inverse_of not set"
42
42
  return
43
43
  end
44
44
 
45
45
  cache_column = "#{using_reflection.inverse_of.name}_cached_at"
46
- ids = records.inject([]) { |a, o| a += [o.send(klass.primary_key), o.send("#{klass.primary_key}_was")] }.compact.uniq
47
- query = klass.where(klass.primary_key => ids)
48
46
  records.each { |r| r.raw_write_attribute(cache_column, timestamp) }
47
+ query = klass.where(klass.primary_key => records.map(&:id))
49
48
  query.update_all({ cache_column => timestamp })
50
49
  traverse_relationships(klass, using_reflection.options[:cached_at], query, cache_column, timestamp)
51
50
  end
52
-
51
+
53
52
  if using_reflection.inverse_of&.options.try(:[], :cached_at) || using_reflection.inverse_of&.parent_reflection&.options.try(:[], :cached_at)
54
53
  cache_column = "#{using_reflection.name}_cached_at"
55
54
  owner.update_column(cache_column, timestamp) unless owner.new_record?
56
55
  end
57
56
  end
58
-
59
- def touch_records_removed_cached_at(records, timestamp)
60
- return if records.empty?
61
-
62
- using_reflection = reflection.parent_reflection || reflection
63
- inverse_reflection = using_reflection.inverse_of&.parent_reflection || using_reflection.inverse_of
64
-
65
- if using_reflection.options[:cached_at]
66
- if inverse_reflection.nil?
67
- puts "WARNING: cannot updated cached at for relationship: #{klass.name}.#{name}, inverse_of not set"
68
- return
69
- end
70
-
71
- cache_column = "#{inverse_reflection.name}_cached_at"
72
- ids = records.inject([]) { |a, o| a += [o.send(klass.primary_key), o.send("#{klass.primary_key}_was")] }.compact.uniq
73
- query = klass.where(klass.primary_key => ids)
74
- records.each { |r| r.raw_write_attribute(cache_column, timestamp) }
75
- query.update_all({ cache_column => timestamp })
76
- traverse_relationships(klass, reflection.options[:cached_at], query, cache_column, timestamp)
77
- end
78
-
79
- if !inverse_reflection.nil? && inverse_reflection.options[:cached_at]
80
- cache_column = "#{using_reflection.name}_cached_at"
81
- owner.raw_write_attribute(cache_column, timestamp)
82
- ids = records.inject([]) { |a, o| a += [o.send(klass.primary_key), o.send("#{klass.primary_key}_was")] }.compact.uniq
83
-
84
- arel_table = if inverse_reflection.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
85
- inverse_reflection.klass.const_get(:"HABTM_#{using_reflection.name.to_s.camelize}").arel_table
86
- else
87
- using_reflection.inverse_of.klass._reflections[using_reflection.inverse_of.options[:through].to_s].klass.arel_table
88
- end
89
-
90
- query = using_reflection.inverse_of.klass.where(using_reflection.inverse_of.klass.primary_key => owner.id)
91
- query.update_all({ cache_column => timestamp })
92
- puts "#{owner.class.name}.#{cache_column} = #{timestamp}"
93
- owner.raw_write_attribute(cache_column, timestamp)
94
- traverse_relationships(klass, reflection.options[:cached_at], query, cache_column, timestamp)
95
- end
96
- end
97
57
 
98
-
99
58
  end
100
59
  end
101
60
 
@@ -1,3 +1,4 @@
1
+ require File.expand_path(File.join(__FILE__, '../association_extension'))
1
2
  require File.expand_path(File.join(__FILE__, '../associations/association'))
2
3
  require File.expand_path(File.join(__FILE__, '../associations/has_one_association'))
3
4
  require File.expand_path(File.join(__FILE__, '../associations/belongs_to_association'))
@@ -8,23 +9,11 @@ module CachedAt
8
9
  module Base
9
10
  extend ActiveSupport::Concern
10
11
 
11
- module AssociationExtension
12
-
13
- def self.build(model, reflection)
14
- return unless reflection.options[:cached_at]
15
- end
16
-
17
- def self.valid_options
18
- [:cached_at]
19
- end
20
-
21
- end
22
-
23
12
  included do
24
13
  before_save :update_belongs_to_cached_at_keys
25
14
  before_destroy { update_relations_cached_at(method: :destroy) }
26
- after_touch { update_relations_cached_at_from_cached_at(method: :touch) }
27
15
 
16
+ after_touch { update_relations_cached_at_from_cached_at(method: :touch) }
28
17
  after_save :update_relations_cached_at_from_cached_at
29
18
  end
30
19
 
@@ -38,23 +27,45 @@ module CachedAt
38
27
  end
39
28
 
40
29
  def update_relations_cached_at(timestamp: nil, method: nil)
41
- return if (method == nil && changes.empty?) && method != :destroy && method != :touch
30
+ method = instance_variable_defined?(:@new_record_before_save) && @new_record_before_save ? :create : :update if method.nil?
31
+
32
+ return if method == :create && changes.empty?
33
+ return if method == :update && changes.empty?
34
+
42
35
  timestamp ||= current_time_from_proper_timezone
43
36
 
44
37
  self._reflections.each do |name, reflection|
45
- begin
46
- association(name.to_sym).touch_cached_at(timestamp, method)
47
- rescue ActiveRecord::HasManyThroughAssociationNotFoundError,
48
- ActiveRecord::HasOneAssociationPolymorphicThroughError,
49
- ActiveRecord::HasManyThroughAssociationPolymorphicThroughError,
50
- ActiveRecord::HasManyThroughSourceAssociationNotFoundError,
51
- ActiveRecord::HasManyThroughAssociationPointlessSourceTypeError,
52
- ActiveRecord::HasManyThroughAssociationPolymorphicSourceError,
53
- ActiveRecord::HasOneThroughCantAssociateThroughCollection
54
- # these error get raised if the reflection is invalid... so we'll
55
- # skip them. Should warn the user, but this casuse the Rails test
56
- # to fail....
38
+
39
+ through_connections = if reflection.polymorphic?
40
+ []
41
+ else
42
+ reflection.klass._reflections.values.select do |r|
43
+ r.options[:cached_at] && r.options[:through] == reflection.inverse_of&.name
44
+ end
45
+ end
46
+
47
+
48
+ next unless reflection.options[:cached_at] || reflection&.parent_reflection&.class == ActiveRecord::Reflection::HasAndBelongsToManyReflection || !through_connections.empty?
49
+ next if instance_variable_defined?(:@relationships_cached_at_touched) && (!@relationships_cached_at_touched.nil? && @relationships_cached_at_touched[reflection.name])
50
+ next if reflection.is_a?(ActiveRecord::Reflection::HasManyReflection) && method == :create
51
+
52
+ assoc = association(name.to_sym)
53
+ assoc.touch_cached_at(timestamp, method)
54
+
55
+ through_connections.each do |r|
56
+ #TODO: move into association
57
+ cache_column = "#{r.inverse_of.name}_cached_at"
58
+
59
+ r.klass.where(r.association_primary_key => self.send(r.foreign_key)).update_all({
60
+ cache_column => timestamp
61
+ })
62
+
63
+ source_assoc = association(r.source_reflection_name.to_sym)
64
+ if source_assoc.loaded?
65
+ source_assoc.target.raw_write_attribute(cache_column, timestamp)
66
+ end
57
67
  end
68
+
58
69
  end
59
70
  end
60
71
 
@@ -69,13 +80,12 @@ module CachedAt
69
80
  elsif (self.changes[reflection.foreign_key] || self.new_record? || (self.association(reflection.name).loaded? && self.send(reflection.name) && self.send(reflection.name).id.nil?)) && self.send(reflection.name).try(:cached_at)
70
81
  self.assign_attributes({ cache_column => self.send(reflection.name).cached_at })
71
82
  end
72
-
73
83
  end
84
+
74
85
  end
75
86
  end
76
87
 
77
88
  end
78
89
  end
79
90
 
80
- ActiveRecord::Associations::Builder::Association.extensions << CachedAt::Base::AssociationExtension
81
91
  ActiveRecord::Base.include(CachedAt::Base)
@@ -1,3 +1,3 @@
1
1
  module CachedAt
2
- VERSION = '2.0.4'
2
+ VERSION = '2.0.5'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-cached_at
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Bracy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-05 00:00:00.000000000 Z
11
+ date: 2017-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -135,6 +135,7 @@ files:
135
135
  - ext/active_record/connection_adapters/abstract/schema_definitions.rb
136
136
  - ext/active_record/connection_adapters/abstract/schema_statements.rb
137
137
  - lib/cached_at.rb
138
+ - lib/cached_at/association_extension.rb
138
139
  - lib/cached_at/associations/association.rb
139
140
  - lib/cached_at/associations/belongs_to_association.rb
140
141
  - lib/cached_at/associations/collection_association.rb