activeadmin-tom_select 4.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.
Files changed (196) hide show
  1. checksums.yaml +7 -0
  2. data/.actrc +20 -0
  3. data/.claude/commands/fix-tests.md +203 -0
  4. data/.github/workflows/ci.yml +174 -0
  5. data/.github/workflows/npm-publish.yml +50 -0
  6. data/.gitignore +35 -0
  7. data/.npmignore +58 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +75 -0
  10. data/.yardopts +2 -0
  11. data/AGENTS.md +39 -0
  12. data/Appraisals +9 -0
  13. data/CHANGELOG.md +64 -0
  14. data/CLAUDE.md +157 -0
  15. data/Gemfile +12 -0
  16. data/Gemfile.lock +368 -0
  17. data/LICENSE.txt +25 -0
  18. data/README.md +483 -0
  19. data/Rakefile +4 -0
  20. data/activeadmin-tom_select.gemspec +43 -0
  21. data/bin/rspec +17 -0
  22. data/config/database.yml +16 -0
  23. data/docs/activeadmin-4-detailed-reference.md +932 -0
  24. data/docs/activeadmin-4-gem-migration-guide.md +313 -0
  25. data/docs/combustion.md +213 -0
  26. data/docs/fail.png +0 -0
  27. data/docs/guide-update-your-app.md +283 -0
  28. data/docs/normal.png +0 -0
  29. data/docs/propshaft-readme.md +320 -0
  30. data/docs/propshaft-upgrade.md +484 -0
  31. data/docs/setup-activeadmin-app.md +552 -0
  32. data/docs/setup-activeadmin-gem.md +535 -0
  33. data/docs/tailwind/blog-page.md +341 -0
  34. data/docs/tailwind/upgrade-guide-enhanced.md +438 -0
  35. data/docs/tailwind/upgrade-guide.md +416 -0
  36. data/docs/tailwind-4/active_admin.rake +38 -0
  37. data/docs/tailwind-4/active_admin.tailwind.css +415 -0
  38. data/docs/tailwind-4/tailwind-active_admin.config.js +18 -0
  39. data/docs/test-app-change.md +154 -0
  40. data/docs/test-environment-fixes.md +58 -0
  41. data/docs/update-tom-select.md +184 -0
  42. data/docs/upload-system.md +225 -0
  43. data/gemfiles/rails_7.x_active_admin_4.x.gemfile +10 -0
  44. data/gemfiles/rails_7.x_active_admin_4.x.gemfile.lock +377 -0
  45. data/gemfiles/rails_8.x_active_admin_4.x.gemfile +10 -0
  46. data/gemfiles/rails_8.x_active_admin_4.x.gemfile.lock +372 -0
  47. data/lefthook.yml +17 -0
  48. data/lib/activeadmin/inputs/filters/searchable_select_input.rb +19 -0
  49. data/lib/activeadmin/inputs/searchable_select_input.rb +16 -0
  50. data/lib/activeadmin/tom_select/engine.rb +17 -0
  51. data/lib/activeadmin/tom_select/option_collection.rb +128 -0
  52. data/lib/activeadmin/tom_select/resource_dsl_extension.rb +56 -0
  53. data/lib/activeadmin/tom_select/resource_extension.rb +10 -0
  54. data/lib/activeadmin/tom_select/select_input_extension.rb +168 -0
  55. data/lib/activeadmin/tom_select/version.rb +5 -0
  56. data/lib/activeadmin/tom_select.rb +20 -0
  57. data/lib/activeadmin-tom_select.rb +5 -0
  58. data/lib/generators/active_admin/tom_select/install/install_generator.rb +180 -0
  59. data/npm-package/package-lock.json +51 -0
  60. data/npm-package/package.json +43 -0
  61. data/npm-package/src/index.js +153 -0
  62. data/npm-package/src/tom-select-tailwind.css +392 -0
  63. data/sonar-project.properties +25 -0
  64. data/spec/features/ajax_params_spec.rb +31 -0
  65. data/spec/features/asset_pipeline_diagnostic_spec.rb +155 -0
  66. data/spec/features/end_to_end_spec.rb +273 -0
  67. data/spec/features/filter_input_spec.rb +144 -0
  68. data/spec/features/form_input_spec.rb +122 -0
  69. data/spec/features/inline_ajax_setting_spec.rb +26 -0
  70. data/spec/features/input_errors_spec.rb +76 -0
  71. data/spec/features/input_html_options_spec.rb +30 -0
  72. data/spec/features/options_dsl_spec.rb +230 -0
  73. data/spec/features/production_build_spec.rb +108 -0
  74. data/spec/internal/.node-version +1 -0
  75. data/spec/internal/Gemfile +43 -0
  76. data/spec/internal/Gemfile.lock +333 -0
  77. data/spec/internal/Procfile.dev +3 -0
  78. data/spec/internal/README.md +24 -0
  79. data/spec/internal/Rakefile +6 -0
  80. data/spec/internal/app/admin/categories.rb +26 -0
  81. data/spec/internal/app/admin/dashboard.rb +29 -0
  82. data/spec/internal/app/admin/option_types.rb +19 -0
  83. data/spec/internal/app/admin/option_values.rb +30 -0
  84. data/spec/internal/app/admin/posts.rb +27 -0
  85. data/spec/internal/app/admin/products.rb +22 -0
  86. data/spec/internal/app/admin/rgb_colors.rb +25 -0
  87. data/spec/internal/app/admin/tag_names.rb +21 -0
  88. data/spec/internal/app/admin/test_ajax_params_category.rb +10 -0
  89. data/spec/internal/app/admin/test_ajax_params_post.rb +20 -0
  90. data/spec/internal/app/admin/test_form_post_class.rb +7 -0
  91. data/spec/internal/app/admin/test_form_post_custom.rb +11 -0
  92. data/spec/internal/app/admin/test_form_post_resource.rb +11 -0
  93. data/spec/internal/app/admin/test_form_post_resource_custom.rb +12 -0
  94. data/spec/internal/app/admin/test_inline_ajax_post.rb +9 -0
  95. data/spec/internal/app/admin/test_input_html_post.rb +11 -0
  96. data/spec/internal/app/admin/test_posts_display_text.rb +9 -0
  97. data/spec/internal/app/admin/test_posts_filter.rb +9 -0
  98. data/spec/internal/app/admin/test_posts_named.rb +9 -0
  99. data/spec/internal/app/admin/test_posts_pagination.rb +9 -0
  100. data/spec/internal/app/admin/test_posts_payload_lambda.rb +11 -0
  101. data/spec/internal/app/admin/test_posts_payload_proc.rb +9 -0
  102. data/spec/internal/app/admin/test_posts_scope_lambda.rb +8 -0
  103. data/spec/internal/app/admin/test_posts_scope_params.rb +8 -0
  104. data/spec/internal/app/admin/test_posts_scope_user.rb +8 -0
  105. data/spec/internal/app/admin/test_posts_text_attr.rb +5 -0
  106. data/spec/internal/app/admin/users.rb +23 -0
  107. data/spec/internal/app/admin/variants.rb +31 -0
  108. data/spec/internal/app/assets/config/manifest.js +2 -0
  109. data/spec/internal/app/assets/images/.keep +0 -0
  110. data/spec/internal/app/assets/stylesheets/active_admin.tailwind.css +16 -0
  111. data/spec/internal/app/assets/stylesheets/application.tailwind.css +15 -0
  112. data/spec/internal/app/controllers/application_controller.rb +9 -0
  113. data/spec/internal/app/controllers/concerns/.keep +0 -0
  114. data/spec/internal/app/helpers/application_helper.rb +2 -0
  115. data/spec/internal/app/javascript/active_admin.js +19 -0
  116. data/spec/internal/app/javascript/application.js +2 -0
  117. data/spec/internal/app/jobs/application_job.rb +7 -0
  118. data/spec/internal/app/mailers/application_mailer.rb +4 -0
  119. data/spec/internal/app/models/admin_user.rb +9 -0
  120. data/spec/internal/app/models/application_record.rb +3 -0
  121. data/spec/internal/app/models/article.rb +12 -0
  122. data/spec/internal/app/models/category.rb +12 -0
  123. data/spec/internal/app/models/color.rb +9 -0
  124. data/spec/internal/app/models/concerns/.keep +0 -0
  125. data/spec/internal/app/models/internal/tag_name.rb +14 -0
  126. data/spec/internal/app/models/internal_tag_name.rb +11 -0
  127. data/spec/internal/app/models/option_type.rb +12 -0
  128. data/spec/internal/app/models/option_value.rb +4 -0
  129. data/spec/internal/app/models/post.rb +15 -0
  130. data/spec/internal/app/models/product.rb +12 -0
  131. data/spec/internal/app/models/rgb_color.rb +16 -0
  132. data/spec/internal/app/models/tag.rb +12 -0
  133. data/spec/internal/app/models/tagging.rb +12 -0
  134. data/spec/internal/app/models/user.rb +12 -0
  135. data/spec/internal/app/models/variant.rb +12 -0
  136. data/spec/internal/app/views/layouts/application.html.erb +28 -0
  137. data/spec/internal/app/views/layouts/mailer.html.erb +13 -0
  138. data/spec/internal/app/views/layouts/mailer.text.erb +1 -0
  139. data/spec/internal/app/views/pwa/manifest.json.erb +22 -0
  140. data/spec/internal/app/views/pwa/service-worker.js +26 -0
  141. data/spec/internal/bin/bundle +117 -0
  142. data/spec/internal/bin/dev +11 -0
  143. data/spec/internal/bin/rackup +27 -0
  144. data/spec/internal/bin/rails +4 -0
  145. data/spec/internal/bin/rake +4 -0
  146. data/spec/internal/bin/setup +37 -0
  147. data/spec/internal/config/application.rb +50 -0
  148. data/spec/internal/config/boot.rb +3 -0
  149. data/spec/internal/config/credentials.yml.enc +1 -0
  150. data/spec/internal/config/database.yml +32 -0
  151. data/spec/internal/config/environment.rb +5 -0
  152. data/spec/internal/config/environments/development.rb +63 -0
  153. data/spec/internal/config/environments/production.rb +86 -0
  154. data/spec/internal/config/environments/test.rb +50 -0
  155. data/spec/internal/config/initializers/active_admin.rb +54 -0
  156. data/spec/internal/config/initializers/assets.rb +8 -0
  157. data/spec/internal/config/initializers/content_security_policy.rb +25 -0
  158. data/spec/internal/config/initializers/devise.rb +315 -0
  159. data/spec/internal/config/initializers/filter_parameter_logging.rb +8 -0
  160. data/spec/internal/config/initializers/inflections.rb +16 -0
  161. data/spec/internal/config/initializers/searchable_select.rb +6 -0
  162. data/spec/internal/config/locales/devise.en.yml +65 -0
  163. data/spec/internal/config/locales/en.yml +31 -0
  164. data/spec/internal/config/master.key +1 -0
  165. data/spec/internal/config/puma.rb +38 -0
  166. data/spec/internal/config/routes.rb +17 -0
  167. data/spec/internal/config.ru +6 -0
  168. data/spec/internal/db/schema.rb +174 -0
  169. data/spec/internal/db/seeds.rb +167 -0
  170. data/spec/internal/esbuild.config.js +34 -0
  171. data/spec/internal/lib/tasks/.keep +0 -0
  172. data/spec/internal/lib/tasks/active_admin.rake +55 -0
  173. data/spec/internal/log/.keep +0 -0
  174. data/spec/internal/package-lock.json +1954 -0
  175. data/spec/internal/package.json +21 -0
  176. data/spec/internal/public/400.html +114 -0
  177. data/spec/internal/public/404.html +114 -0
  178. data/spec/internal/public/406-unsupported-browser.html +114 -0
  179. data/spec/internal/public/422.html +114 -0
  180. data/spec/internal/public/500.html +114 -0
  181. data/spec/internal/public/icon.png +0 -0
  182. data/spec/internal/public/icon.svg +3 -0
  183. data/spec/internal/public/robots.txt +1 -0
  184. data/spec/internal/script/.keep +0 -0
  185. data/spec/internal/storage/.keep +0 -0
  186. data/spec/internal/tailwind.config.js +23 -0
  187. data/spec/internal/vendor/.keep +0 -0
  188. data/spec/internal/yarn.lock +824 -0
  189. data/spec/rails_helper.rb +62 -0
  190. data/spec/spec_helper.rb +138 -0
  191. data/spec/support/active_admin_helpers.rb +17 -0
  192. data/spec/support/capybara.rb +8 -0
  193. data/spec/support/models.rb +11 -0
  194. data/spec/support/pluck_polyfill.rb +12 -0
  195. data/spec/support/reset_settings.rb +5 -0
  196. metadata +497 -0
data/README.md ADDED
@@ -0,0 +1,483 @@
1
+ # ActiveAdmin Tom Select
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/activeadmin-tom_select.svg)](http://badge.fury.io/rb/activeadmin-tom_select)
4
+ [![NPM Version](https://badge.fury.io/js/@rocket-sensei%2Factiveadmin-tom_select.svg)](https://badge.fury.io/js/@rocket-sensei%2Factiveadmin-tom_select)
5
+ [![npm](https://img.shields.io/npm/dm/@rocket-sensei/activeadmin-tom_select)](https://www.npmjs.com/package/@rocket-sensei/activeadmin-tom_select)
6
+ [![Build Status](https://github.com/rs-pro/activeadmin-tom_select/actions/workflows/ci.yml/badge.svg)](https://github.com/rs-pro/activeadmin-tom_select/actions)
7
+
8
+ Searchable select boxes (via [Tom Select](https://tom-select.js.org/)) for
9
+ ActiveAdmin forms and filters. Extends the ActiveAdmin resource DSL to
10
+ allow defining JSON endpoints to fetch options from asynchronously.
11
+
12
+ **Note:** This gem provides Tom Select integration for ActiveAdmin. It was originally forked from activeadmin-searchable_select but has been completely rewritten to use Tom Select instead of Select2.
13
+
14
+ ## Installation
15
+
16
+ Add `activeadmin-tom_select` to your Gemfile:
17
+
18
+ ```ruby
19
+ gem 'activeadmin-tom_select'
20
+ ```
21
+
22
+ ### ActiveAdmin 4.x with Rails 8 (esbuild/importmap/Propshaft)
23
+
24
+ This gem is optimized for ActiveAdmin 4.x with Rails 8, supporting modern JavaScript bundlers and Propshaft. See the [complete setup guide](docs/guide-update-your-app.md) for detailed instructions.
25
+
26
+ #### Quick Install with Generator
27
+
28
+ ```bash
29
+ # For esbuild (recommended)
30
+ rails generate active_admin:searchable_select:install
31
+
32
+ # For importmap
33
+ rails generate active_admin:searchable_select:install --bundler=importmap
34
+ ```
35
+
36
+ #### Manual Setup for esbuild
37
+
38
+ 1. Install npm packages:
39
+ ```bash
40
+ npm install @rocket-sensei/activeadmin-tom_select tom-select
41
+ ```
42
+
43
+ 2. In `app/javascript/active_admin.js`:
44
+ ```javascript
45
+ import "@activeadmin/activeadmin";
46
+ import TomSelect from 'tom-select';
47
+
48
+ // Make Tom Select available globally
49
+ window.TomSelect = TomSelect;
50
+
51
+ // Import and auto-initialize searchable selects
52
+ import { setupAutoInit } from '@rocket-sensei/activeadmin-tom_select';
53
+ setupAutoInit();
54
+ ```
55
+
56
+ 3. Add Tom Select CSS to your ActiveAdmin stylesheet:
57
+ ```css
58
+ @import 'tom-select/dist/css/tom-select.css';
59
+ /* Or use CDN: */
60
+ @import url('https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/css/tom-select.css');
61
+ ```
62
+
63
+ ### ActiveAdmin 3.x and older
64
+
65
+ ##### Using assets via Sprockets
66
+ Import stylesheets and require javascripts:
67
+
68
+ ```scss
69
+ // active_admin.css.scss
70
+ @import "active_admin/searchable_select";
71
+ ```
72
+
73
+ ```coffee
74
+ // active_admin.js
75
+ //= require active_admin/searchable_select
76
+ ```
77
+
78
+ ##### Using assets via Webpacker
79
+
80
+ Add to `package.json`:
81
+ ```json
82
+ "dependencies": {
83
+ "@rocket-sensei/activeadmin-tom_select": "^5.0.0"
84
+ }
85
+ ```
86
+
87
+ In `app/javascript/packs/active_admin.js`:
88
+ ```javascript
89
+ import { setupAutoInit } from '@rocket-sensei/activeadmin-tom_select';
90
+ setupAutoInit();
91
+ ```
92
+
93
+ In `app/javascript/stylesheets/active_admin.scss`:
94
+ ```css
95
+ @import '@rocket-sensei/activeadmin-tom_select/css';
96
+ ```
97
+
98
+ ## Usage
99
+
100
+ ### Making Select Boxes Searchable
101
+
102
+ To add search functionality to a select box, use the
103
+ `:searchable_select` input type:
104
+
105
+ ```ruby
106
+ ActiveAdmin.register Product do
107
+ form do |f|
108
+ f.input(:category, as: :searchable_select)
109
+ end
110
+ end
111
+ ```
112
+
113
+ This also works for filters:
114
+
115
+ ```ruby
116
+ ActiveAdmin.register Product do
117
+ filter(:category, as: :searchable_select)
118
+ end
119
+ ```
120
+
121
+ By default, you can only select one at a time for a filter. You can
122
+ specify a multi-select with:
123
+
124
+ ```ruby
125
+ ActiveAdmin.register Product do
126
+ filter(:category, as: :searchable_select, multiple: true)
127
+ end
128
+ ```
129
+
130
+ ### Fetching Options via Ajax
131
+
132
+ For large collections, rendering the whole set of options can be to
133
+ expensive. Use the `ajax` option to fetch a set of matching options
134
+ once the user begins to type:
135
+
136
+ ```ruby
137
+
138
+ ActiveAdmin.register Product do
139
+ filter(:category,
140
+ as: :searchable_select,
141
+ ajax: true)
142
+ end
143
+ ```
144
+
145
+ If the input attribute corresponds to an ActiveAdmin resource, it is
146
+ expected to provide the JSON endpoint that provides the options. Use
147
+ the `searchable_select_options` method to define the required
148
+ collection action:
149
+
150
+ ```ruby
151
+ ActiveAdmin.register Category do
152
+ searchable_select_options(scope: Category.all,
153
+ text_attribute: :name)
154
+ end
155
+ ```
156
+
157
+ By default, `scope` needs to be a Ransack enabled ActiveRecord
158
+ collection proxy determining which options are available. The
159
+ attribute given by `text_attribute` will be used to get a display name
160
+ for each record. Via Ransack, it is also used to filter by search
161
+ term. Limiting result set size is handled automatically.
162
+
163
+ You can customize the display text:
164
+
165
+ ```ruby
166
+ ActiveAdmin.register Category do
167
+ searchable_select_options(scope: Category.all,
168
+ text_attribute: :name,
169
+ display_text: ->(record) { "Category: #{record.name}" } )
170
+ end
171
+ ```
172
+
173
+ Note that `text_attribute` is still required to perform filtering via
174
+ Ransack. You can pass the `filter` option, to specify your own
175
+ filtering strategy:
176
+
177
+ ```ruby
178
+ ActiveAdmin.register Category do
179
+ searchable_select_options(scope: Category.all,
180
+ text_attribute: :name,
181
+ filter: lambda |term, scope|
182
+ scope.ransack(name_cont_all: term.split(' ')).result
183
+ end)
184
+ end
185
+ ```
186
+
187
+ `scope` can also be a lambda which is evaluated in the context of the
188
+ collection action defined by the helper:
189
+
190
+ ```ruby
191
+ ActiveAdmin.register Category do
192
+ searchable_select_options(scope: -> { Category.allowed_for(current_user) },
193
+ text_attribute: :name)
194
+ end
195
+ ```
196
+
197
+ If the input attribute is set on the form's object, ajax based
198
+ searchable selects will automatically render a single option to ensure
199
+ the selected item is displayed correctly even before options have been
200
+ loaded asynchronously.
201
+
202
+ #### Specifying the Options Endpoint Resource
203
+
204
+ If the resource that provides the options endpoint cannot be guessed
205
+ based on the input attribute name, you can pass an object with a
206
+ `resource` key as `ajax` option:
207
+
208
+ ```ruby
209
+ ActiveAdmin.register Product do
210
+ form do |f|
211
+ f.input(:additional_category,
212
+ as: :searchable_select,
213
+ ajax: { resource: Category })
214
+ end
215
+ end
216
+ ```
217
+
218
+ #### Multiple Options Endpoints per Resource
219
+
220
+ A single ActiveAdmin resource can define multiple options endpoints:
221
+
222
+ ```ruby
223
+ ActiveAdmin.register Category do
224
+ searchable_select_options(name: :favorites,
225
+ scope: Category.favorites,
226
+ text_attribute: :name)
227
+
228
+ searchable_select_options(name: :recent,
229
+ scope: Category.recent,
230
+ text_attribute: :name)
231
+ end
232
+ ```
233
+
234
+ To specify which collection to use, pass an object with a
235
+ `collection_name` key as `ajax` option:
236
+
237
+ ```ruby
238
+ ActiveAdmin.register Product do
239
+ form do |f|
240
+ f.input(:category,
241
+ as: :searchable_select,
242
+ ajax: { collection_name: :favorites })
243
+ end
244
+ end
245
+ ```
246
+
247
+ #### Querying Multiple Attributes
248
+
249
+ ActiveAdmin Searchable Select querying is performed by Ransack. As such, you can
250
+ build your query in a way that it can query multiple attributes at once.
251
+
252
+ ```ruby
253
+ ActiveAdmin.register User do
254
+ searchable_select_options(scope: User.all,
255
+ text_attribute: :username,
256
+ filter: lambda do |term, scope|
257
+ scope.ransack(email_or_username_cont: term).result
258
+ end)
259
+ end
260
+ ```
261
+
262
+ In this example, the `all` scope will query `email OR username`.
263
+
264
+ You can add the additional payload as dsl option:
265
+
266
+ ```ruby
267
+ ActiveAdmin.register Category do
268
+ searchable_select_options(scope: Category.all,
269
+ text_attribute: :name,
270
+ additional_payload: ->(record) { { foo: record.bar } } )
271
+ end
272
+ ```
273
+
274
+ response example which uses additional_payload:
275
+
276
+ ```json
277
+ {
278
+ "results": [{ "id": "1", "text": "Bicycles", "foo": "Bar" }],
279
+ "pagination": { "more": "false" }
280
+ }
281
+ ```
282
+
283
+ #### Passing Parameters
284
+
285
+ You can pass additional parameters to the options endpoint:
286
+
287
+ ```ruby
288
+ ActiveAdmin.register Product do
289
+ form do |f|
290
+ f.input(:category,
291
+ as: :searchable_select,
292
+ ajax: {
293
+ params: {
294
+ some: 'value'
295
+ }
296
+ })
297
+ end
298
+ end
299
+ ```
300
+
301
+ The lambda passed as `scope` can receive those parameters as first
302
+ argument:
303
+
304
+ ```ruby
305
+ ActiveAdmin.register Category do
306
+ searchable_select_options(scope: lambda do |params|
307
+ Category.find_all_by_some(params[:some])
308
+ end,
309
+ text_attribute: :name)
310
+ end
311
+ ```
312
+
313
+ #### Path options for nested resources
314
+
315
+ Example for the following setup:
316
+
317
+ ```ruby
318
+ # Models
319
+ class OptionType < ActiveRecord::Base; end
320
+
321
+ class OptionValue < ActiveRecord::Base
322
+ belongs_to :option_type
323
+ end
324
+
325
+ class Product < ActiveRecord::Base
326
+ belongs_to :option_type
327
+ has_many :variants
328
+ end
329
+
330
+ class Variant < ActiveRecord::Base
331
+ belongs_to :product
332
+ belongs_to :option_value
333
+ end
334
+
335
+ # ActiveAdmin
336
+ ActiveAdmin.register(OptionType)
337
+
338
+ ActiveAdmin.register(Product)
339
+
340
+ ActiveAdmin.register(OptionValue) do
341
+ belongs_to :option_type
342
+ searchable_select_options(scope: lambda do |params|
343
+ OptionValue.where(
344
+ option_type_id: params[:option_type_id]
345
+ )
346
+ end,
347
+ text_attribute: :value)
348
+ end
349
+ ```
350
+
351
+ It is possible to pass path parameters for correctly generating URLs for nested resources fetching via `path_params`
352
+
353
+ ```ruby
354
+ ActiveAdmin.register(Variant) do
355
+ belongs_to :product
356
+
357
+ form do |f|
358
+ ...
359
+ f.input(:option_value,
360
+ as: :searchable_select,
361
+ ajax: {
362
+ resource: OptionValue,
363
+ path_params: {
364
+ option_type_id: f.object.product.option_type_id
365
+ }
366
+ })
367
+ ...
368
+ end
369
+ end
370
+ ```
371
+
372
+ This will generate the path for fetching as `all_options_admin_option_type_option_values(option_type_id: f.object.product.option_type_id)` (e.g. `/admin/option_types/2/option_values/all_options`)
373
+
374
+ #### Inlining Ajax Options in Feature Tests
375
+
376
+ When writing UI driven feature specs (i.e. with Capybara),
377
+ asynchronous loading of select options can increase test
378
+ complexity. `activeadmin-searchable_select` provides an option to
379
+ render all available options just like a normal select input while
380
+ still exercsing the same code paths including `scope` and
381
+ `text_attribute` handling.
382
+
383
+ For example with RSpec/Capybara, simply set `inline_ajax_options` true
384
+ for feature specs:
385
+
386
+ ```ruby
387
+ RSpec.configure do |config|
388
+ config.before(:each) do |example|
389
+ ActiveAdmin::SearchableSelect.inline_ajax_options = (example.metadata[:type] == :feature)
390
+ end
391
+ end
392
+
393
+ ```
394
+
395
+ ### Passing options to Tom Select
396
+
397
+ It is possible to pass and define configuration options to Tom Select
398
+ via `data-attributes` using nested (subkey) options.
399
+
400
+ Attributes need to be added to the `input_html` option in the form input.
401
+ For example you can tell Tom Select how long to wait after a user
402
+ has stopped typing before sending the request:
403
+
404
+ ```ruby
405
+ ...
406
+ f.input(:category,
407
+ as: :searchable_select,
408
+ ajax: true,
409
+ input_html: {
410
+ data: {
411
+ 'ajax--delay' => 500
412
+ }
413
+ })
414
+ ...
415
+ ```
416
+
417
+
418
+ ## Development
419
+
420
+ ### Running Tests
421
+
422
+ To run the tests install bundled gems and invoke RSpec:
423
+
424
+ ```bash
425
+ $ bundle
426
+ $ bundle exec rspec
427
+ ```
428
+
429
+ The test suite can be run against different versions of Rails and
430
+ Active Admin (see `Appraisals` file):
431
+
432
+ ```bash
433
+ $ appraisal install
434
+ $ appraisal rspec
435
+ ```
436
+
437
+ ### Running the Test Application
438
+
439
+ A full Rails 8 test application is included for manual testing and development:
440
+
441
+ ```bash
442
+ # Start the test app
443
+ $ cd spec/internal
444
+ $ bundle exec rackup
445
+
446
+ # The app will be available at http://localhost:9292
447
+ # Default admin credentials: admin@example.com / password
448
+ ```
449
+
450
+ The test app includes:
451
+ - Sample models (User, Category, Post, Color) with seed data
452
+ - Various admin resources demonstrating different searchable select configurations
453
+ - ActiveAdmin with Tailwind CSS integration
454
+ - Tom Select with full Tailwind styling
455
+
456
+ ### Building Assets in Test App
457
+
458
+ ```bash
459
+ $ cd spec/internal
460
+
461
+ # Build CSS (Tailwind)
462
+ $ bundle exec rake active_admin:build
463
+
464
+ # Build JavaScript
465
+ $ npm run build:js
466
+
467
+ # Watch for changes during development
468
+ $ bundle exec rake active_admin:watch # CSS
469
+ $ npm run watch:js # JavaScript
470
+ ```
471
+
472
+ ### Code Style
473
+
474
+ Please make sure changes conform with the styleguide:
475
+
476
+ ```bash
477
+ $ bundle exec rubocop
478
+ ```
479
+
480
+ ## Acknowledgements
481
+
482
+ Based on
483
+ [mfairburn/activeadmin-select2](https://github.com/mfairburn/activeadmin-select2).
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'semmy'
4
+ Semmy::Tasks.install
@@ -0,0 +1,43 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'activeadmin/tom_select/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'activeadmin-tom_select'
7
+ spec.version = ActiveAdmin::SearchableSelect::VERSION
8
+ spec.summary = 'Use Tom Select for searchable selects in Active Admin forms and filters.'
9
+ spec.license = 'MIT'
10
+ spec.authors = ['Rocket Sensei']
11
+ spec.email = 'glebtv@gmail.com'
12
+ spec.homepage = 'https://github.com/rs-pro/activeadmin-tom_select'
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.require_paths = ['lib']
16
+
17
+ spec.required_ruby_version = ['>= 3.0', '< 4']
18
+
19
+ spec.add_development_dependency 'appraisal', '~> 2.2'
20
+ spec.add_development_dependency 'bundler', ['>= 1.5', '< 3']
21
+ spec.add_development_dependency 'combustion', '~> 1.5'
22
+ spec.add_development_dependency 'database_cleaner-active_record', '~> 2.1'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rspec-rails', '~> 6.0'
25
+ spec.add_development_dependency 'sqlite3', '~> 2.1'
26
+
27
+ spec.add_development_dependency 'capybara', '~> 3.39'
28
+ spec.add_development_dependency 'capybara-playwright-driver', '~> 0.5'
29
+ spec.add_development_dependency 'puma', '~> 6.0'
30
+
31
+ spec.add_development_dependency 'rubocop', '~> 1.50'
32
+ spec.add_development_dependency 'rubocop-ast', '~> 1.46.0'
33
+ spec.add_development_dependency 'rubocop-rspec', '~> 3.0'
34
+
35
+ spec.add_development_dependency 'rspec_junit_formatter'
36
+ spec.add_development_dependency 'simplecov'
37
+
38
+ spec.add_runtime_dependency 'activeadmin', '>= 3.0', '< 5'
39
+ spec.add_runtime_dependency 'ransack', '>= 1.8', '< 5'
40
+
41
+ spec.metadata['rubygems_mfa_required'] = 'true'
42
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
43
+ end
data/bin/rspec ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'rspec' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,16 @@
1
+ default: &default
2
+ adapter: sqlite3
3
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
4
+ timeout: 5000
5
+
6
+ development:
7
+ <<: *default
8
+ database: db/development.sqlite3
9
+
10
+ test:
11
+ <<: *default
12
+ database: db/test.sqlite3
13
+
14
+ production:
15
+ <<: *default
16
+ database: db/production.sqlite3