mobility_active_storage 0.1.0 → 0.1.2

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
  SHA256:
3
- metadata.gz: d4544d367fbdc080f61260f4706289e6fa009088ab73399ee5ee4efbe1597f2f
4
- data.tar.gz: cb31f79f1ba41e277fe74bd2a707e3a861a756b1e6c4659434ae5dac4312a19c
3
+ metadata.gz: 7ed33baa135ecd69527c111652956b1420c0bce45052b3725cc5d4e55715257e
4
+ data.tar.gz: ff07c4fd501a56b1b57008d7f294517c5159d27ef4c7844984012251b9b49343
5
5
  SHA512:
6
- metadata.gz: 260385aedbb5bf84fa7c244a669b108fa3b6a7671d48228e70f617fa2656c53bf03fc90ee1993ee3d9513b26701226dad5572afdcea6be1dd53e00253eb8c941
7
- data.tar.gz: 8ffb358c2898f8ae304c43f135e97ad4105e9fa97ba419b1c6af823e8afe26f621c85f343b2f092273441f777a1f1bc50d84089ddb440283dc7283005d2337bf
6
+ metadata.gz: 776fef9bd8b7dffb06b3e1b4c9955bb3b5acebec0e601d265df4793dfcb98e5e7f5a12d9aeec8992cfed204b832201cbc38a7bdd5f8894edb8bcd0db418508f7
7
+ data.tar.gz: b62a6b3ae3dad73be4f415f1753fd3af573efb2c0e72b87fd57b09820a8a651f80e041587b95a91c7be3c0756dd3dfe9d605f282a106df4a10702d7cd2813254
data/CHANGELOG.md CHANGED
@@ -1,8 +1,30 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [0.1.2] - 2026-08-11
4
4
 
5
- Pre-release fixes from a security review of the initial commit.
5
+ - `#{attribute}_locales` now answers in one query instead of one per configured locale. It probed
6
+ each locale's attachment proxy in turn, so a model declared for 73 locales issued 73 statements
7
+ every time it was asked -- and any caller that reads it per row (a serializer, a validation) paid
8
+ that per row. Pending attachment changes still take precedence over the stored rows, so a staged
9
+ attach counts before it is saved and a staged purge stops counting straight away.
10
+
11
+ ## [0.1.1] - 2026-08-10
12
+
13
+ - No user-facing changes. Released to verify the trusted-publishing workflow; the packaged files
14
+ are identical to 0.1.0.
15
+
16
+ ## [0.1.0] - 2026-08-10
17
+
18
+ - Initial release.
19
+ - `has_one_translated_attached` and `has_many_translated_attached` macros on Active Record models.
20
+ - `Mobility::Backends` registrations for `:active_storage` and `:active_storage_many`.
21
+ - Per-locale attachments stored under locale-suffixed Active Storage attachment names
22
+ (`document_en`, `document_fr`), requiring no migration.
23
+ - Opt-in per-attribute fallbacks, where reads resolve through the fallback chain while writes
24
+ stay in the current locale.
25
+ - `#{attribute}_locales` and a current-locale `with_attached_#{attribute}` scope.
26
+
27
+ Fixes from a security review of the initial commit, all included in this release:
6
28
 
7
29
  - A `fallback:` read option is now honoured only where the attribute actually configures
8
30
  fallbacks. Previously `document(fallback: :ja)` cross-read another locale even on an attribute
@@ -28,14 +50,3 @@ Pre-release fixes from a security review of the initial commit.
28
50
  - CI runs a Rails 7.2/8.0/latest matrix on Ruby 3.2 through 4.0, plus `bundler-audit`. Actions are
29
51
  pinned by SHA.
30
52
  - README: strong-parameters guidance for the per-locale writers, and Rails version security notes.
31
-
32
- ## [0.1.0] - 2026-08-07
33
-
34
- - Initial release.
35
- - `has_one_translated_attached` and `has_many_translated_attached` macros on Active Record models.
36
- - `Mobility::Backends` registrations for `:active_storage` and `:active_storage_many`.
37
- - Per-locale attachments stored under locale-suffixed Active Storage attachment names
38
- (`document_en`, `document_fr`), requiring no migration.
39
- - Opt-in per-attribute fallbacks, where reads resolve through the fallback chain while writes
40
- stay in the current locale.
41
- - `#{attribute}_locales` and a current-locale `with_attached_#{attribute}` scope.
data/README.md CHANGED
@@ -94,6 +94,10 @@ For `has_one_translated_attached :document`:
94
94
 
95
95
  `has_many_translated_attached :photos` mirrors these with `ActiveStorage::Attached::Many`.
96
96
 
97
+ `document_locales` costs one query however many locales the attribute declares, and counts pending
98
+ changes the way `attached?` does: a staged attach is included before it is saved, a staged purge
99
+ excluded straight away. It does not memoize, so hold the result if you need it more than once.
100
+
97
101
  ### Fallbacks
98
102
 
99
103
  Off by default. Enable per attribute:
@@ -50,6 +50,13 @@ module MobilityActiveStorage
50
50
  normalized_locales.include?(Mobility.normalize_locale(locale))
51
51
  end
52
52
 
53
+ # Every configured locale's attachment name. Memoized per attribute: the locale set is
54
+ # fixed when the class body runs.
55
+ def attachment_names(attribute)
56
+ @attachment_names ||= {}
57
+ @attachment_names[attribute] ||= normalized_locales.map { |locale| "#{attribute}_#{locale}" }
58
+ end
59
+
53
60
  # Mobility's query plugin asks the backend for an Arel node so it can build a predicate.
54
61
  # An attachment is a row in active_storage_attachments, not a comparable column value, so
55
62
  # there is nothing meaningful to compare. Fail with an explanation rather than the
@@ -136,8 +143,24 @@ module MobilityActiveStorage
136
143
  end
137
144
 
138
145
  # Yields each configured locale that actually has an attachment.
146
+ #
147
+ # One query for the whole locale set, not one per locale: every locale is a row in
148
+ # active_storage_attachments under a suffixed name, so which locales are present is a single
149
+ # pluck on that table. Probing each proxy instead costs a query per configured locale, and a
150
+ # model declared for a large locale set pays that on every read -- 73 statements to answer a
151
+ # question one statement answers.
152
+ #
153
+ # Pending changes win over the stored rows, as Active Storage's own +attached?+ does: an
154
+ # attach counts before it is saved, a purge stops counting straight away.
139
155
  def each_locale
140
- options[:locales].each { |locale| yield locale if attached(locale).attached? }
156
+ persisted = persisted_attachment_names
157
+
158
+ options[:locales].each do |locale|
159
+ name = attachment_name(locale)
160
+ # attached? reads the staged change without touching the database.
161
+ present = model.attachment_changes.key?(name) ? attached(locale).attached? : persisted.include?(name)
162
+ yield locale if present
163
+ end
141
164
  end
142
165
 
143
166
  # The Active Storage proxy for +locale+, without any fallback handling.
@@ -149,6 +172,20 @@ module MobilityActiveStorage
149
172
 
150
173
  private
151
174
 
175
+ # Which of this attribute's attachment names have rows. distinct because a collection
176
+ # attachment repeats its name once per file, and polymorphic_name so an STI subclass looks
177
+ # itself up under the type Active Storage actually stored.
178
+ def persisted_attachment_names
179
+ return Set.new if model.new_record?
180
+
181
+ ActiveStorage::Attachment
182
+ .where(record_type: model.class.polymorphic_name, record_id: model.id,
183
+ name: self.class.attachment_names(attribute))
184
+ .distinct
185
+ .pluck(:name)
186
+ .to_set
187
+ end
188
+
152
189
  def attachment_name(locale)
153
190
  self.class.attachment_name_for(attribute, locale)
154
191
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MobilityActiveStorage
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mobility_active_storage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glen Barnes
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 4.0.17
106
+ rubygems_version: 4.0.16
107
107
  specification_version: 4
108
108
  summary: Translated Active Storage attachments for Mobility.
109
109
  test_files: []