validation_hints 6.2.1 → 6.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99fb1203ae7e46c6f7df8edf84c00a7b55c6901a0dbd43dcfd9eb2b96acbd9dc
4
- data.tar.gz: c83cbcab470dba35e53f2d991f5b219e4be2ef33b453649df2498f65b1c4f654
3
+ metadata.gz: 21e36d4cd0b2d29b1bb47f2ea106c3e97fb346ee797676287ae8375d756d371b
4
+ data.tar.gz: ccffeccb5f502cb2fd0f9ace62642f3d540702c6046df47fc81b23ce24cb80ff
5
5
  SHA512:
6
- metadata.gz: 81b2faea546b51aa257ebb9776993ea9598a8754534deb6f1cce220eb97e9ccb2828bb8eed1d75f11c32073d47d53d20cd4e5685fe2314c34534bbf5f7725454
7
- data.tar.gz: 67012560801eb03bc7aef5617c04296d518636ab46973a8edb36ae73178765deb347ec36a503c9b7f58be5637345b17d9c4bca5375db42d9f713afc215321193
6
+ metadata.gz: 349c4c319b3d5a52889e76c54528e96caac992956f32607a3561e2dc1bdacba108e571b0705b47a9250d531b044eb7394ec5bd0669bc09fa5c5a3f16aafbec60
7
+ data.tar.gz: 4f1e2a360b4c3974e07270033dcb87c4ca2e2226afb9433991cbd217ef81d6d2d4d9ea89779983c9b120eafb3703a37bb8da2ae0bf71d1ce3887fe7caabb0cf0
data/CHANGELOG.md CHANGED
@@ -2,6 +2,58 @@
2
2
 
3
3
  All notable changes to this project are documented here.
4
4
 
5
+ ## 6.4.0
6
+
7
+ ### Added
8
+
9
+ - **Format validator hints:** `validates …, format: { with: … }` now emits `hints.messages.format` (was empty).
10
+ - **Custom EachValidator hints:** lookup via `hints.messages.<validator_key>` (e.g. `email_format`).
11
+ - **Tests:** format, custom EachValidator, `validates_with` class validator does not crash.
12
+
13
+ ### Changed
14
+
15
+ - **`attribute_names_for_hints`:** skip validators without an `attributes` list (`validates_with` class validators).
16
+
17
+ ### Added (docs)
18
+
19
+ - README: conditional validators, custom/`validates_with` validators, format I18n conventions.
20
+
21
+ ## 6.3.0
22
+
23
+ ### Changed
24
+
25
+ - **Rails 7.1:** runtime `activerecord` `>= 7.1.5`, `< 7.2` (was 7.0.x).
26
+ - **Dev deps:** dropped full `rails` gem; use `activerecord`, `activemodel`, `rake`, `sqlite3`, `minitest` only.
27
+
28
+ ### Added
29
+
30
+ - **README:** security / `bundler-audit` section.
31
+
32
+ ### Verified
33
+
34
+ - **`bundle exec rake test`** — **21 runs, 44 assertions, 0 failures** on Rails 7.1.
35
+
36
+ ## 6.2.3
37
+
38
+ ### Added
39
+
40
+ - **`stuff/smoke_test.sh`** — rake test + in-memory SQLite console smoke (`Widget.new.hints[:name]`).
41
+
42
+ ### Changed
43
+
44
+ - **`stuff/analysis.md`** — updated for 6.2.x, inline_forms 7.9.x Tippy integration, API table.
45
+
46
+ ## 6.2.2
47
+
48
+ ### Added
49
+
50
+ - **Tests:** `confirmation` validator hint; custom `message:` as Symbol (with I18n override).
51
+ - **README:** inline_forms integration note; expanded `bundle exec rake test` instructions.
52
+
53
+ ### Fixed
54
+
55
+ - **Custom `message:` Symbol:** strip `:message` from options before `generate_message` so lookup uses `presence.required` (not bare `required`).
56
+
5
57
  ## 6.2.1
6
58
 
7
59
  ### Fixed
data/Gemfile.lock CHANGED
@@ -1,78 +1,24 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- validation_hints (6.2.1)
5
- activerecord (>= 7.0, < 7.1)
4
+ validation_hints (6.4.0)
5
+ activerecord (>= 7.1.5, < 7.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- actioncable (7.0.10)
11
- actionpack (= 7.0.10)
12
- activesupport (= 7.0.10)
13
- nio4r (~> 2.0)
14
- websocket-driver (>= 0.6.1)
15
- actionmailbox (7.0.10)
16
- actionpack (= 7.0.10)
17
- activejob (= 7.0.10)
18
- activerecord (= 7.0.10)
19
- activestorage (= 7.0.10)
20
- activesupport (= 7.0.10)
21
- mail (>= 2.7.1)
22
- net-imap
23
- net-pop
24
- net-smtp
25
- actionmailer (7.0.10)
26
- actionpack (= 7.0.10)
27
- actionview (= 7.0.10)
28
- activejob (= 7.0.10)
29
- activesupport (= 7.0.10)
30
- mail (~> 2.5, >= 2.5.4)
31
- net-imap
32
- net-pop
33
- net-smtp
34
- rails-dom-testing (~> 2.0)
35
- actionpack (7.0.10)
36
- actionview (= 7.0.10)
37
- activesupport (= 7.0.10)
38
- racc
39
- rack (~> 2.0, >= 2.2.4)
40
- rack-test (>= 0.6.3)
41
- rails-dom-testing (~> 2.0)
42
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
43
- actiontext (7.0.10)
44
- actionpack (= 7.0.10)
45
- activerecord (= 7.0.10)
46
- activestorage (= 7.0.10)
47
- activesupport (= 7.0.10)
48
- globalid (>= 0.6.0)
49
- nokogiri (>= 1.8.5)
50
- actionview (7.0.10)
51
- activesupport (= 7.0.10)
52
- builder (~> 3.1)
53
- erubi (~> 1.4)
54
- rails-dom-testing (~> 2.0)
55
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
56
- activejob (7.0.10)
57
- activesupport (= 7.0.10)
58
- globalid (>= 0.3.6)
59
- activemodel (7.0.10)
60
- activesupport (= 7.0.10)
61
- activerecord (7.0.10)
62
- activemodel (= 7.0.10)
63
- activesupport (= 7.0.10)
64
- activestorage (7.0.10)
65
- actionpack (= 7.0.10)
66
- activejob (= 7.0.10)
67
- activerecord (= 7.0.10)
68
- activesupport (= 7.0.10)
69
- marcel (~> 1.0)
70
- mini_mime (>= 1.1.0)
71
- activesupport (7.0.10)
10
+ activemodel (7.1.6)
11
+ activesupport (= 7.1.6)
12
+ activerecord (7.1.6)
13
+ activemodel (= 7.1.6)
14
+ activesupport (= 7.1.6)
15
+ timeout (>= 0.4.0)
16
+ activesupport (7.1.6)
72
17
  base64
73
18
  benchmark (>= 0.3)
74
19
  bigdecimal
75
20
  concurrent-ruby (~> 1.0, >= 1.0.2)
21
+ connection_pool (>= 2.2.5)
76
22
  drb
77
23
  i18n (>= 1.6, < 2)
78
24
  logger (>= 1.4.2)
@@ -83,89 +29,14 @@ GEM
83
29
  base64 (0.3.0)
84
30
  benchmark (0.5.0)
85
31
  bigdecimal (4.1.2)
86
- builder (3.3.0)
87
32
  concurrent-ruby (1.3.6)
88
- crass (1.0.6)
89
- date (3.5.1)
33
+ connection_pool (3.0.2)
90
34
  drb (2.2.3)
91
- erubi (1.13.1)
92
- globalid (1.3.0)
93
- activesupport (>= 6.1)
94
35
  i18n (1.14.8)
95
36
  concurrent-ruby (~> 1.0)
96
37
  logger (1.7.0)
97
- loofah (2.25.1)
98
- crass (~> 1.0.2)
99
- nokogiri (>= 1.12.0)
100
- mail (2.9.0)
101
- logger
102
- mini_mime (>= 0.1.1)
103
- net-imap
104
- net-pop
105
- net-smtp
106
- marcel (1.1.0)
107
- method_source (1.1.0)
108
- mini_mime (1.1.5)
109
38
  minitest (5.27.0)
110
39
  mutex_m (0.3.0)
111
- net-imap (0.6.4)
112
- date
113
- net-protocol
114
- net-pop (0.1.2)
115
- net-protocol
116
- net-protocol (0.2.2)
117
- timeout
118
- net-smtp (0.5.1)
119
- net-protocol
120
- nio4r (2.7.5)
121
- nokogiri (1.19.3-aarch64-linux-gnu)
122
- racc (~> 1.4)
123
- nokogiri (1.19.3-aarch64-linux-musl)
124
- racc (~> 1.4)
125
- nokogiri (1.19.3-arm-linux-gnu)
126
- racc (~> 1.4)
127
- nokogiri (1.19.3-arm-linux-musl)
128
- racc (~> 1.4)
129
- nokogiri (1.19.3-arm64-darwin)
130
- racc (~> 1.4)
131
- nokogiri (1.19.3-x86_64-darwin)
132
- racc (~> 1.4)
133
- nokogiri (1.19.3-x86_64-linux-gnu)
134
- racc (~> 1.4)
135
- nokogiri (1.19.3-x86_64-linux-musl)
136
- racc (~> 1.4)
137
- racc (1.8.1)
138
- rack (2.2.23)
139
- rack-test (2.2.0)
140
- rack (>= 1.3)
141
- rails (7.0.10)
142
- actioncable (= 7.0.10)
143
- actionmailbox (= 7.0.10)
144
- actionmailer (= 7.0.10)
145
- actionpack (= 7.0.10)
146
- actiontext (= 7.0.10)
147
- actionview (= 7.0.10)
148
- activejob (= 7.0.10)
149
- activemodel (= 7.0.10)
150
- activerecord (= 7.0.10)
151
- activestorage (= 7.0.10)
152
- activesupport (= 7.0.10)
153
- bundler (>= 1.15.0)
154
- railties (= 7.0.10)
155
- rails-dom-testing (2.3.0)
156
- activesupport (>= 5.0.0)
157
- minitest
158
- nokogiri (>= 1.6)
159
- rails-html-sanitizer (1.7.0)
160
- loofah (~> 2.25)
161
- nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
162
- railties (7.0.10)
163
- actionpack (= 7.0.10)
164
- activesupport (= 7.0.10)
165
- method_source
166
- rake (>= 12.2)
167
- thor (~> 1.0)
168
- zeitwerk (~> 2.5)
169
40
  rake (13.4.2)
170
41
  securerandom (0.4.1)
171
42
  sqlite3 (1.7.3-aarch64-linux)
@@ -173,15 +44,9 @@ GEM
173
44
  sqlite3 (1.7.3-arm64-darwin)
174
45
  sqlite3 (1.7.3-x86_64-darwin)
175
46
  sqlite3 (1.7.3-x86_64-linux)
176
- thor (1.5.0)
177
47
  timeout (0.6.1)
178
48
  tzinfo (2.0.6)
179
49
  concurrent-ruby (~> 1.0)
180
- websocket-driver (0.8.0)
181
- base64
182
- websocket-extensions (>= 0.1.0)
183
- websocket-extensions (0.1.5)
184
- zeitwerk (2.7.5)
185
50
 
186
51
  PLATFORMS
187
52
  aarch64-linux
@@ -196,64 +61,29 @@ PLATFORMS
196
61
  x86_64-linux-musl
197
62
 
198
63
  DEPENDENCIES
64
+ activemodel (>= 7.1.5, < 7.2)
65
+ activerecord (>= 7.1.5, < 7.2)
199
66
  bundler (>= 2.0)
200
67
  minitest (~> 5.0)
201
- rails (>= 7.0, < 7.1)
68
+ rake (~> 13.0)
202
69
  sqlite3 (~> 1.4)
203
70
  validation_hints!
204
71
 
205
72
  CHECKSUMS
206
- actioncable (7.0.10) sha256=7aa02ea26d6cc21c33e604bb28a0759c5212653311bc42105f96f709e507afab
207
- actionmailbox (7.0.10) sha256=1236f472d86db056f97b3602391becab69c84d9f79d963b9c9b50056e213c1e6
208
- actionmailer (7.0.10) sha256=53bc7aac1659ef97a216c43002ea8286931d7b97f252b27152ac15de1b2585ef
209
- actionpack (7.0.10) sha256=4c524b3b401cc828efb3fcd6f3de56ac1ec0180843b74f54357f58b0256f9509
210
- actiontext (7.0.10) sha256=ffadcbb9b21c09e9bfe946a79739d92abc92a9097eb1db7675e52484804c1c8c
211
- actionview (7.0.10) sha256=e5a9475ccfcde80dddf7ced701f44aedc4f8262286051db84ae2c48322ec000e
212
- activejob (7.0.10) sha256=f31b974206569a362e8c6c07aa00f3099fcc0f365880929c23e79c739d90fceb
213
- activemodel (7.0.10) sha256=e2e1e0a4664b69606363e9f6f59afadeab6fa8843c5fb73cd037bb72a40fa498
214
- activerecord (7.0.10) sha256=63bc193d4c6944d85f53255362b67269d246a51bd664e09b1aa2cecfe5288c9a
215
- activestorage (7.0.10) sha256=41906d59536170abcb480d05b2368ee06305307edcafc5e4891ffb7b0970eaa2
216
- activesupport (7.0.10) sha256=01487b0774045918b36893af4f012986db8375f6c5850c0ffc75b940ede72305
73
+ activemodel (7.1.6) sha256=f72f510018a560b5969e3ffc88214441ff09eed60b310feba678a597b2a2e721
74
+ activerecord (7.1.6) sha256=1aa298cd7fc97ed8639ebb05a46bd17243a1218d89945bdc2bac1e61e673f079
75
+ activesupport (7.1.6) sha256=7f12140a813b1c4922a322663e547129aef1840fc512fa262378f6d7e7fd3a7c
217
76
  base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
218
77
  benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
219
78
  bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
220
- builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
221
79
  bundler (4.0.11) sha256=5bcec0fb78302e48d02ee46f10ee6e6942be647ba5b44a6d1ddfda9a240ce785
222
80
  concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
223
- crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
224
- date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
81
+ connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
225
82
  drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
226
- erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
227
- globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11
228
83
  i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
229
84
  logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
230
- loofah (2.25.1) sha256=d436c73dbd0c1147b16c4a41db097942d217303e1f7728704b37e4df9f6d2e04
231
- mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941
232
- marcel (1.1.0) sha256=fdcfcfa33cc52e93c4308d40e4090a5d4ea279e160a7f6af988260fa970e0bee
233
- method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
234
- mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
235
85
  minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
236
86
  mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
237
- net-imap (0.6.4) sha256=9a5598c67a3022c284d98430ef1d4948e7dbdb62596f61081ea8ca933270a02b
238
- net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
239
- net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
240
- net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
241
- nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
242
- nokogiri (1.19.3-aarch64-linux-gnu) sha256=46b89e5d7b9e844c2ee360794240c6ea2a4e6fa0c5892a4ed487db621224b639
243
- nokogiri (1.19.3-aarch64-linux-musl) sha256=8392dfdcd21be7a94dbbe9ccc138dea01b97b24cb2dc02a114ca98bfb1d9a0b7
244
- nokogiri (1.19.3-arm-linux-gnu) sha256=3919d5ffc334ad778a4a9eb88fda7dcb8b1fb58c8a52ac640c6dcd2f038e774f
245
- nokogiri (1.19.3-arm-linux-musl) sha256=9ce1cb6346bb9c67b1550eb537aa183ead91e4b6eadb2f36ade02d8dd2a79fb6
246
- nokogiri (1.19.3-arm64-darwin) sha256=71b9bd424b1b7abc18b05052a1a3cfd3627abdca62be280854cc411791357e42
247
- nokogiri (1.19.3-x86_64-darwin) sha256=77f3fba57d46c53ab31e62fc6c28f705109d1bf6264356c76f132b2be5728d4d
248
- nokogiri (1.19.3-x86_64-linux-gnu) sha256=2f5078620fe12e83669b5b17311b32532a8153d02eee7ad06948b926d6080976
249
- nokogiri (1.19.3-x86_64-linux-musl) sha256=248c906d2166eca5efb56d52fdee5f9a1f51d69a72e2b64fdac647b4ce39ea3f
250
- racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
251
- rack (2.2.23) sha256=a8fe9d7e07064770b8ec123663fded8a59ef7e2b6db5cda7173d45a5718ab69c
252
- rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
253
- rails (7.0.10) sha256=866eb2c53d3184543fdb770d7ea308e4ee518063226a9e176229f3c7a9537c25
254
- rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
255
- rails-html-sanitizer (1.7.0) sha256=28b145cceaf9cc214a9874feaa183c3acba036c9592b19886e0e45efc62b1e89
256
- railties (7.0.10) sha256=d52a8b7a61ad941121a15a6596b2150e05c70b199c3afc9e9b73e63b3b1a57a7
257
87
  rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
258
88
  securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
259
89
  sqlite3 (1.7.3-aarch64-linux) sha256=0ccb8c001cd2617f4801a2c816142d3c9bc299e3f3e0f49e03812f3610b0891c
@@ -261,13 +91,9 @@ CHECKSUMS
261
91
  sqlite3 (1.7.3-arm64-darwin) sha256=b956160cc882d2568f332f915c9fe27cae9a4521b202d6e7ea540171c88e4600
262
92
  sqlite3 (1.7.3-x86_64-darwin) sha256=b88e117ae14b2c5b61a7eb14da24b3b0e93cd3e1c17774ff3b6e5a03ffe4e5b7
263
93
  sqlite3 (1.7.3-x86_64-linux) sha256=522a3285660dec8253465880c97980e873db0d79060900be8d14194217a3ee73
264
- thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
265
94
  timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb
266
95
  tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
267
- validation_hints (6.2.1)
268
- websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962
269
- websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
270
- zeitwerk (2.7.5) sha256=d8da92128c09ea6ec62c949011b00ed4a20242b255293dd66bf41545398f73dd
96
+ validation_hints (6.4.0)
271
97
 
272
98
  BUNDLED WITH
273
99
  4.0.11
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Proactive validation hints derived from model validators — complementary to Rails `errors` (which react after `valid?` fails).
4
4
 
5
- **Requirements:** Ruby >= 3.2, Rails / Active Record 7.0.x (`>= 7.0`, `< 7.1`). Used by [inline_forms](https://github.com/acesuares/inline_forms).
5
+ **Requirements:** Ruby >= 3.2, Rails / Active Record 7.1.x (`>= 7.1.5`, `< 7.2`). Used by [inline_forms](https://github.com/acesuares/inline_forms) 7.x for label tooltips on validated fields.
6
6
 
7
7
  ## Install
8
8
 
@@ -13,6 +13,10 @@ gem "validation_hints", "~> 6.2"
13
13
 
14
14
  Rails apps load the gem via `ValidationHints::Railtie` (no manual `require`).
15
15
 
16
+ ### inline_forms
17
+
18
+ Generated apps include `validation_hints` automatically. The engine patches load order so hints work when `rails/all` loads before Bundler. Tooltips use `has_validations_for?`, `hints.full_messages_for`, and Tippy.js in inline_forms 7.9.x — see inline_forms `CHANGELOG.md`.
19
+
16
20
  ## Example
17
21
 
18
22
  ```ruby
@@ -82,12 +86,58 @@ en:
82
86
 
83
87
  Attribute labels in full messages come from the normal Rails path (`activerecord.attributes.<model>.<attr>`), same as errors.
84
88
 
89
+ ## Conditional validators
90
+
91
+ `:if`, `:unless`, and `:on` are **not evaluated** when building hints. Hints describe the static validation rules declared on the model, not whether they would run for the current record state. Use `errors` (after `valid?`) when you need conditional feedback.
92
+
93
+ ## Custom validators
94
+
95
+ ### `validates :attr, my_validator: true` (EachValidator)
96
+
97
+ The hint type is derived from the validator class name (`MyValidator` → `my`). Add copy under `hints.messages.my` or per-model/per-attribute keys in the lookup chain.
98
+
99
+ ### `validates_with MyValidator` (class validator)
100
+
101
+ Only **EachValidator**-style validators (declared per attribute) produce hints automatically. Class-level `ActiveModel::Validator` implementations are not introspectable for attribute lists — prefer `validates :attr, …` or an EachValidator subclass when you need hint tooltips.
102
+
103
+ ## Format validators
104
+
105
+ `validates :attr, format: { with: /…/ }` emits the default **`hints.messages.format`** copy (“must match the required format”). Override globally, per model, or per attribute via the I18n lookup chain; or set `message:` on the validator.
106
+
107
+ ```yaml
108
+ en:
109
+ activerecord:
110
+ hints:
111
+ models:
112
+ person:
113
+ attributes:
114
+ code:
115
+ format: "must be numeric"
116
+ ```
117
+
118
+ ## Security
119
+
120
+ Runtime dependency is **Active Record 7.1.x** only (no Action View / Active Storage in the gem).
121
+
122
+ Dev dependencies were slimmed from full `rails` to `activerecord` + `activemodel` to reduce audit noise. Run:
123
+
124
+ ```bash
125
+ bundler-audit check --update
126
+ ```
127
+
128
+ Rails **7.1.x** may still report advisories fixed only in 7.2.3.1+; see roadmap Phase 5 for coordinated bumps.
129
+
85
130
  ## Tests
86
131
 
132
+ From the gem root:
133
+
87
134
  ```bash
135
+ bundle install
88
136
  bundle exec rake test
89
137
  ```
90
138
 
139
+ Runs Minitest against an in-memory SQLite Active Record 7.1 app (`test/test_helper.rb`).
140
+
91
141
  ## History
92
142
 
93
143
  See [CHANGELOG.md](CHANGELOG.md).
@@ -197,7 +197,11 @@ module ActiveModel
197
197
  []
198
198
  end
199
199
 
200
- from_validators = @base.class.validators.flat_map(&:attributes).map(&:to_s)
200
+ from_validators = @base.class.validators.flat_map do |validator|
201
+ next [] unless validator.respond_to?(:attributes)
202
+
203
+ validator.attributes
204
+ end.map(&:to_s)
201
205
  (from_record + from_validators).map(&:to_sym).uniq
202
206
  end
203
207
 
@@ -212,7 +216,14 @@ module ActiveModel
212
216
 
213
217
  if options[:message].is_a?(Symbol)
214
218
  message_key = "#{key}.#{options[:message]}"
215
- result << generate_message(attribute, message_key, options)
219
+ generate_options = options.dup
220
+ generate_options.delete(:message)
221
+ result << generate_message(attribute, message_key, generate_options)
222
+ return result
223
+ end
224
+
225
+ if key == "format"
226
+ result << generate_message(attribute, "format", options)
216
227
  return result
217
228
  end
218
229
 
@@ -20,6 +20,7 @@ en:
20
20
  exclusion:
21
21
  in: "must not be one of %{count}"
22
22
  format: "must match the required format"
23
+ email_format: "must look like an email address"
23
24
  associated: "is invalid"
24
25
  uniqueness: "must be unique"
25
26
  confirmation: "doesn't match confirmation"
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module ValidationHints
3
- VERSION = "6.2.1"
3
+ VERSION = "6.4.0"
4
4
  end
@@ -74,4 +74,47 @@ class ActiveModelHintsTest < Minitest::Test
74
74
  validators = Person.validators_on(:name).map { |v| v.class.name.demodulize }
75
75
  assert_includes validators, "PresenceValidator"
76
76
  end
77
+
78
+ def test_confirmation_hint
79
+ hints = @person.hints[:password]
80
+ assert_includes hints, "doesn't match confirmation"
81
+ end
82
+
83
+ def test_custom_message_as_symbol
84
+ I18n.backend.store_translations(:en, activerecord: {
85
+ hints: {
86
+ models: {
87
+ person: {
88
+ attributes: {
89
+ email: {
90
+ "presence" => { "required" => "is required" }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ })
97
+
98
+ hints = @person.hints[:email]
99
+ assert_includes hints, "is required"
100
+ messages = @person.hints.full_messages_for(:email)
101
+ assert_includes messages, "Email is required"
102
+ end
103
+
104
+ def test_format_validator_hint
105
+ hints = @person.hints[:code]
106
+ assert_includes hints, "must match the required format"
107
+ end
108
+
109
+ def test_custom_each_validator_hint
110
+ person = CustomValidatorPerson.new
111
+ hints = person.hints[:email]
112
+ assert_includes hints, "must look like an email address"
113
+ end
114
+
115
+ def test_validates_with_class_validator_does_not_crash
116
+ person = CustomValidatorPerson.new
117
+ person.hints[:name]
118
+ assert_empty person.hints[:code], "validates_with class validators are not introspectable for hints"
119
+ end
77
120
  end
data/test/test_helper.rb CHANGED
@@ -13,8 +13,11 @@ ActiveRecord::Schema.define do
13
13
  create_table :people, force: true do |t|
14
14
  t.string :name
15
15
  t.string :password
16
+ t.string :password_confirmation
16
17
  t.integer :age
17
18
  t.string :status
19
+ t.string :email
20
+ t.string :code
18
21
  end
19
22
  end
20
23
 
@@ -23,6 +26,28 @@ class Person < ActiveRecord::Base
23
26
  validates :password, length: { within: 1...5 }
24
27
  validates :age, numericality: { only_integer: true, greater_than: 19 }
25
28
  validates :status, inclusion: { in: %w[active inactive] }
29
+ validates :password, confirmation: true
30
+ validates :email, presence: { message: :required }
31
+ validates :code, format: { with: /\A\d+\z/ }
32
+ end
33
+
34
+ class EmailFormatValidator < ActiveModel::EachValidator
35
+ def validate_each(record, attribute, value)
36
+ record.errors.add(attribute, :invalid) unless value.to_s.include?("@")
37
+ end
38
+ end
39
+
40
+ class CodePresenceValidator < ActiveModel::Validator
41
+ def validate(record)
42
+ record.errors.add(:code, :blank) if record.code.blank?
43
+ end
44
+ end
45
+
46
+ class CustomValidatorPerson < ActiveRecord::Base
47
+ self.table_name = "people"
48
+
49
+ validates :email, email_format: true
50
+ validates_with CodePresenceValidator
26
51
  end
27
52
 
28
53
  class Profile < ActiveRecord::Base
@@ -4,7 +4,7 @@ require "test_helper"
4
4
 
5
5
  class ValidationHintsTest < Minitest::Test
6
6
  def test_version
7
- assert_equal "6.2.0", ValidationHints::VERSION
7
+ assert_equal "6.4.0", ValidationHints::VERSION
8
8
  end
9
9
 
10
10
  def test_locale_path_exists
@@ -28,10 +28,12 @@ Gem::Specification.new do |s|
28
28
 
29
29
  s.require_paths = ["lib"]
30
30
 
31
- s.add_dependency "activerecord", ">= 7.0", "< 7.1"
31
+ s.add_dependency "activerecord", ">= 7.1.5", "< 7.2"
32
32
 
33
- s.add_development_dependency "rails", ">= 7.0", "< 7.1"
33
+ s.add_development_dependency "activerecord", ">= 7.1.5", "< 7.2"
34
+ s.add_development_dependency "activemodel", ">= 7.1.5", "< 7.2"
34
35
  s.add_development_dependency "sqlite3", "~> 1.4"
35
36
  s.add_development_dependency "minitest", "~> 5.0"
37
+ s.add_development_dependency "rake", "~> 13.0"
36
38
  s.add_development_dependency "bundler", ">= 2.0"
37
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validation_hints
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.1
4
+ version: 6.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ace Suares
@@ -15,40 +15,60 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '7.0'
18
+ version: 7.1.5
19
19
  - - "<"
20
20
  - !ruby/object:Gem::Version
21
- version: '7.1'
21
+ version: '7.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: '7.0'
28
+ version: 7.1.5
29
29
  - - "<"
30
30
  - !ruby/object:Gem::Version
31
- version: '7.1'
31
+ version: '7.2'
32
32
  - !ruby/object:Gem::Dependency
33
- name: rails
33
+ name: activerecord
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
- version: '7.0'
38
+ version: 7.1.5
39
39
  - - "<"
40
40
  - !ruby/object:Gem::Version
41
- version: '7.1'
41
+ version: '7.2'
42
42
  type: :development
43
43
  prerelease: false
44
44
  version_requirements: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '7.0'
48
+ version: 7.1.5
49
49
  - - "<"
50
50
  - !ruby/object:Gem::Version
51
- version: '7.1'
51
+ version: '7.2'
52
+ - !ruby/object:Gem::Dependency
53
+ name: activemodel
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 7.1.5
59
+ - - "<"
60
+ - !ruby/object:Gem::Version
61
+ version: '7.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 7.1.5
69
+ - - "<"
70
+ - !ruby/object:Gem::Version
71
+ version: '7.2'
52
72
  - !ruby/object:Gem::Dependency
53
73
  name: sqlite3
54
74
  requirement: !ruby/object:Gem::Requirement
@@ -77,6 +97,20 @@ dependencies:
77
97
  - - "~>"
78
98
  - !ruby/object:Gem::Version
79
99
  version: '5.0'
100
+ - !ruby/object:Gem::Dependency
101
+ name: rake
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '13.0'
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '13.0'
80
114
  - !ruby/object:Gem::Dependency
81
115
  name: bundler
82
116
  requirement: !ruby/object:Gem::Requirement