activerecord-cached_at 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
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