vident-view_component-caching 0.1.0
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 +7 -0
- data/README.md +28 -0
- data/Rakefile +3 -0
- data/lib/tasks/vident/view_component/caching_tasks.rake +4 -0
- data/lib/vident/view_component/caching/railtie.rb +8 -0
- data/lib/vident/view_component/caching/version.rb +7 -0
- data/lib/vident/view_component/caching.rb +145 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0c92605001e18a9f49a3ba28db60fc0269bb78f74b3333b2484511dc4d240653
|
4
|
+
data.tar.gz: 4dd98bc48794cd45f023fdb71beb4b0e1035a1e4bbcd5c6397256d20bf5e1e95
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b619b40a8d2ad65ff8bf906cea5b303353de96cd2c7eeef7087d6de439913629e9127dda7e2e8ccf95cfb488af4dc371bcc2ed57f4646f133ca26349d6f7d6f9
|
7
|
+
data.tar.gz: 8a87104ad9b01147cc473dbea7b0e950d66d82be3839a223b6829df48bfe1051ada6ee5b1599901e20c77d520e2c6cdadb4d29a780a95eef9730cbb46e848d22
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Vident::ViewComponent::Caching
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "vident-view_component-caching"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install vident-view_component-caching
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
require "vident/view_component/caching/version"
|
2
|
+
require "vident/view_component/caching/railtie"
|
3
|
+
|
4
|
+
module Vident
|
5
|
+
module ViewComponent
|
6
|
+
# Rails fragment caching works by either expecting the cached key object to respond to `cache_key` or for that object
|
7
|
+
# to be an array or hash.
|
8
|
+
module Caching
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
def inherited(subclass)
|
13
|
+
subclass.instance_variable_set(
|
14
|
+
:@named_cache_key_attributes,
|
15
|
+
@named_cache_key_attributes.clone
|
16
|
+
)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def with_cache_key(*attrs, name: :_collection)
|
21
|
+
raise StandardError, "with_cache_key can only be used on components *without* slots as there is no eary way to track their content changes so too risky" if respond_to?(:slots?) && slots?
|
22
|
+
# Add view file to cache key
|
23
|
+
attrs << :component_modified_time
|
24
|
+
named_cache_key_includes(name, *attrs)
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :named_cache_key_attributes
|
28
|
+
|
29
|
+
# TypedComponents can be used with fragment caching, but you need to be careful! Read on...
|
30
|
+
#
|
31
|
+
# <% cache component do %>
|
32
|
+
# <%= render component %>
|
33
|
+
# <% end %>
|
34
|
+
#
|
35
|
+
# The most important point is that Rails cannot track dependencies on the component itself, so you need to
|
36
|
+
# be careful to be explicit on the attributes, and manually specify any sub Viewcomponent dependencies that the
|
37
|
+
# component has. The assumption is that the subcomponent takes any attributes from the parent, so the cache key
|
38
|
+
# depends on the parent component attributes. Otherwise changes to the parent or sub component views/Ruby class
|
39
|
+
# will result in different cache keys too. Of course if you invalidate all cache keys with a modifier on deploy
|
40
|
+
# then no need to worry about changing the cache key on component changes, only on attribute/data changes.
|
41
|
+
#
|
42
|
+
# A big caveat is that the cache key cannot depend on anything related to the view_context of the component (such
|
43
|
+
# as `helpers` as the key is created before the rending pipline is invoked (which is when the view_context is set).
|
44
|
+
def depends_on(*klasses)
|
45
|
+
@component_dependencies ||= []
|
46
|
+
@component_dependencies += klasses
|
47
|
+
end
|
48
|
+
|
49
|
+
attr_reader :component_dependencies
|
50
|
+
|
51
|
+
def component_modified_time
|
52
|
+
return @component_modified_time if Rails.env.production? && @component_modified_time
|
53
|
+
# FIXME: This could stack overflow if there are circular dependencies
|
54
|
+
deps = component_dependencies&.map(&:component_modified_time)&.join("-") || ""
|
55
|
+
@component_modified_time = deps + sidecar_view_modified_time + rb_component_modified_time
|
56
|
+
end
|
57
|
+
|
58
|
+
def sidecar_view_modified_time
|
59
|
+
return @sidecar_view_modified_time if Rails.env.production? && defined?(@sidecar_view_modified_time)
|
60
|
+
@sidecar_view_modified_time = ::File.exist?(template_path) ? ::File.mtime(template_path).to_i.to_s : ""
|
61
|
+
end
|
62
|
+
|
63
|
+
def rb_component_modified_time
|
64
|
+
return @rb_component_modified_time if Rails.env.production? && defined?(@rb_component_modified_time)
|
65
|
+
@rb_component_modified_time = ::File.exist?(component_path) ? ::File.mtime(component_path).to_i.to_s : ""
|
66
|
+
end
|
67
|
+
|
68
|
+
def template_path
|
69
|
+
File.join components_base_path, "#{virtual_path}.html.erb"
|
70
|
+
end
|
71
|
+
|
72
|
+
def component_path
|
73
|
+
File.join components_base_path, "#{virtual_path}.rb"
|
74
|
+
end
|
75
|
+
|
76
|
+
def components_base_path
|
77
|
+
::Rails.configuration.view_component.view_component_path || "app/components"
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def named_cache_key_includes(name, *attrs)
|
83
|
+
define_cache_key_method unless @named_cache_key_attributes
|
84
|
+
@named_cache_key_attributes ||= {}
|
85
|
+
@named_cache_key_attributes[name] = attrs
|
86
|
+
end
|
87
|
+
|
88
|
+
def define_cache_key_method
|
89
|
+
# If the presenter defines cache key setup then define the method. Otherwise Rails assumes this
|
90
|
+
# will return a valid key if the class will respond to this
|
91
|
+
define_method :cache_key do |n = :_collection|
|
92
|
+
if defined?(@cache_key)
|
93
|
+
return @cache_key[n] if @cache_key.key?(n)
|
94
|
+
else
|
95
|
+
@cache_key ||= {}
|
96
|
+
end
|
97
|
+
generate_cache_key(n)
|
98
|
+
@cache_key[n]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Component modified time which is combined with other cache key attributes to generate cache key for an instance
|
104
|
+
def component_modified_time
|
105
|
+
self.class.component_modified_time
|
106
|
+
end
|
107
|
+
|
108
|
+
def cacheable?
|
109
|
+
respond_to? :cache_key
|
110
|
+
end
|
111
|
+
|
112
|
+
def cache_key_modifier
|
113
|
+
ENV["RAILS_CACHE_ID"]
|
114
|
+
end
|
115
|
+
|
116
|
+
def cache_keys_for_sources(key_attributes)
|
117
|
+
sources = key_attributes.flat_map { |n| n.is_a?(Proc) ? instance_eval(&n) : send(n) }
|
118
|
+
sources.compact.map do |item|
|
119
|
+
next if item == self
|
120
|
+
generate_item_cache_key_from(item)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def generate_item_cache_key_from(item)
|
125
|
+
if item.respond_to? :cache_key_with_version
|
126
|
+
item.cache_key_with_version
|
127
|
+
elsif item.respond_to? :cache_key
|
128
|
+
item.cache_key
|
129
|
+
elsif item.is_a?(String)
|
130
|
+
Digest::SHA1.hexdigest(item)
|
131
|
+
else
|
132
|
+
Digest::SHA1.hexdigest(Marshal.dump(item))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def generate_cache_key(index)
|
137
|
+
key_attributes = self.class.named_cache_key_attributes[index]
|
138
|
+
return nil unless key_attributes
|
139
|
+
key = "#{self.class.name}/#{cache_keys_for_sources(key_attributes).join("/")}"
|
140
|
+
raise StandardError, "Cache key for key #{key} is blank!" if key.blank?
|
141
|
+
@cache_key[index] = cache_key_modifier.present? ? "#{key}/#{cache_key_modifier}" : key
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vident-view_component-caching
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen Ierodiaconou
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-04-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '8'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '7'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '8'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: vident-view_component
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.1.0
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 0.1.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '1'
|
53
|
+
description: Cache key computation for Vident components with ViewComponent
|
54
|
+
email:
|
55
|
+
- stevegeek@gmail.com
|
56
|
+
executables: []
|
57
|
+
extensions: []
|
58
|
+
extra_rdoc_files: []
|
59
|
+
files:
|
60
|
+
- README.md
|
61
|
+
- Rakefile
|
62
|
+
- lib/tasks/vident/view_component/caching_tasks.rake
|
63
|
+
- lib/vident/view_component/caching.rb
|
64
|
+
- lib/vident/view_component/caching/railtie.rb
|
65
|
+
- lib/vident/view_component/caching/version.rb
|
66
|
+
homepage: https://github.com/stevegeek/vident-view_component-caching
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata:
|
70
|
+
homepage_uri: https://github.com/stevegeek/vident-view_component-caching
|
71
|
+
source_code_uri: https://github.com/stevegeek/vident-view_component-caching
|
72
|
+
changelog_uri: https://github.com/stevegeek/vident-view_component-caching/blob/main/CHANGELOG.md
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubygems_version: 3.4.6
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Cache key computation for Vident components with ViewComponent
|
92
|
+
test_files: []
|