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.
- checksums.yaml +7 -0
- data/.actrc +20 -0
- data/.claude/commands/fix-tests.md +203 -0
- data/.github/workflows/ci.yml +174 -0
- data/.github/workflows/npm-publish.yml +50 -0
- data/.gitignore +35 -0
- data/.npmignore +58 -0
- data/.rspec +1 -0
- data/.rubocop.yml +75 -0
- data/.yardopts +2 -0
- data/AGENTS.md +39 -0
- data/Appraisals +9 -0
- data/CHANGELOG.md +64 -0
- data/CLAUDE.md +157 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +368 -0
- data/LICENSE.txt +25 -0
- data/README.md +483 -0
- data/Rakefile +4 -0
- data/activeadmin-tom_select.gemspec +43 -0
- data/bin/rspec +17 -0
- data/config/database.yml +16 -0
- data/docs/activeadmin-4-detailed-reference.md +932 -0
- data/docs/activeadmin-4-gem-migration-guide.md +313 -0
- data/docs/combustion.md +213 -0
- data/docs/fail.png +0 -0
- data/docs/guide-update-your-app.md +283 -0
- data/docs/normal.png +0 -0
- data/docs/propshaft-readme.md +320 -0
- data/docs/propshaft-upgrade.md +484 -0
- data/docs/setup-activeadmin-app.md +552 -0
- data/docs/setup-activeadmin-gem.md +535 -0
- data/docs/tailwind/blog-page.md +341 -0
- data/docs/tailwind/upgrade-guide-enhanced.md +438 -0
- data/docs/tailwind/upgrade-guide.md +416 -0
- data/docs/tailwind-4/active_admin.rake +38 -0
- data/docs/tailwind-4/active_admin.tailwind.css +415 -0
- data/docs/tailwind-4/tailwind-active_admin.config.js +18 -0
- data/docs/test-app-change.md +154 -0
- data/docs/test-environment-fixes.md +58 -0
- data/docs/update-tom-select.md +184 -0
- data/docs/upload-system.md +225 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile +10 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile.lock +377 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile +10 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile.lock +372 -0
- data/lefthook.yml +17 -0
- data/lib/activeadmin/inputs/filters/searchable_select_input.rb +19 -0
- data/lib/activeadmin/inputs/searchable_select_input.rb +16 -0
- data/lib/activeadmin/tom_select/engine.rb +17 -0
- data/lib/activeadmin/tom_select/option_collection.rb +128 -0
- data/lib/activeadmin/tom_select/resource_dsl_extension.rb +56 -0
- data/lib/activeadmin/tom_select/resource_extension.rb +10 -0
- data/lib/activeadmin/tom_select/select_input_extension.rb +168 -0
- data/lib/activeadmin/tom_select/version.rb +5 -0
- data/lib/activeadmin/tom_select.rb +20 -0
- data/lib/activeadmin-tom_select.rb +5 -0
- data/lib/generators/active_admin/tom_select/install/install_generator.rb +180 -0
- data/npm-package/package-lock.json +51 -0
- data/npm-package/package.json +43 -0
- data/npm-package/src/index.js +153 -0
- data/npm-package/src/tom-select-tailwind.css +392 -0
- data/sonar-project.properties +25 -0
- data/spec/features/ajax_params_spec.rb +31 -0
- data/spec/features/asset_pipeline_diagnostic_spec.rb +155 -0
- data/spec/features/end_to_end_spec.rb +273 -0
- data/spec/features/filter_input_spec.rb +144 -0
- data/spec/features/form_input_spec.rb +122 -0
- data/spec/features/inline_ajax_setting_spec.rb +26 -0
- data/spec/features/input_errors_spec.rb +76 -0
- data/spec/features/input_html_options_spec.rb +30 -0
- data/spec/features/options_dsl_spec.rb +230 -0
- data/spec/features/production_build_spec.rb +108 -0
- data/spec/internal/.node-version +1 -0
- data/spec/internal/Gemfile +43 -0
- data/spec/internal/Gemfile.lock +333 -0
- data/spec/internal/Procfile.dev +3 -0
- data/spec/internal/README.md +24 -0
- data/spec/internal/Rakefile +6 -0
- data/spec/internal/app/admin/categories.rb +26 -0
- data/spec/internal/app/admin/dashboard.rb +29 -0
- data/spec/internal/app/admin/option_types.rb +19 -0
- data/spec/internal/app/admin/option_values.rb +30 -0
- data/spec/internal/app/admin/posts.rb +27 -0
- data/spec/internal/app/admin/products.rb +22 -0
- data/spec/internal/app/admin/rgb_colors.rb +25 -0
- data/spec/internal/app/admin/tag_names.rb +21 -0
- data/spec/internal/app/admin/test_ajax_params_category.rb +10 -0
- data/spec/internal/app/admin/test_ajax_params_post.rb +20 -0
- data/spec/internal/app/admin/test_form_post_class.rb +7 -0
- data/spec/internal/app/admin/test_form_post_custom.rb +11 -0
- data/spec/internal/app/admin/test_form_post_resource.rb +11 -0
- data/spec/internal/app/admin/test_form_post_resource_custom.rb +12 -0
- data/spec/internal/app/admin/test_inline_ajax_post.rb +9 -0
- data/spec/internal/app/admin/test_input_html_post.rb +11 -0
- data/spec/internal/app/admin/test_posts_display_text.rb +9 -0
- data/spec/internal/app/admin/test_posts_filter.rb +9 -0
- data/spec/internal/app/admin/test_posts_named.rb +9 -0
- data/spec/internal/app/admin/test_posts_pagination.rb +9 -0
- data/spec/internal/app/admin/test_posts_payload_lambda.rb +11 -0
- data/spec/internal/app/admin/test_posts_payload_proc.rb +9 -0
- data/spec/internal/app/admin/test_posts_scope_lambda.rb +8 -0
- data/spec/internal/app/admin/test_posts_scope_params.rb +8 -0
- data/spec/internal/app/admin/test_posts_scope_user.rb +8 -0
- data/spec/internal/app/admin/test_posts_text_attr.rb +5 -0
- data/spec/internal/app/admin/users.rb +23 -0
- data/spec/internal/app/admin/variants.rb +31 -0
- data/spec/internal/app/assets/config/manifest.js +2 -0
- data/spec/internal/app/assets/images/.keep +0 -0
- data/spec/internal/app/assets/stylesheets/active_admin.tailwind.css +16 -0
- data/spec/internal/app/assets/stylesheets/application.tailwind.css +15 -0
- data/spec/internal/app/controllers/application_controller.rb +9 -0
- data/spec/internal/app/controllers/concerns/.keep +0 -0
- data/spec/internal/app/helpers/application_helper.rb +2 -0
- data/spec/internal/app/javascript/active_admin.js +19 -0
- data/spec/internal/app/javascript/application.js +2 -0
- data/spec/internal/app/jobs/application_job.rb +7 -0
- data/spec/internal/app/mailers/application_mailer.rb +4 -0
- data/spec/internal/app/models/admin_user.rb +9 -0
- data/spec/internal/app/models/application_record.rb +3 -0
- data/spec/internal/app/models/article.rb +12 -0
- data/spec/internal/app/models/category.rb +12 -0
- data/spec/internal/app/models/color.rb +9 -0
- data/spec/internal/app/models/concerns/.keep +0 -0
- data/spec/internal/app/models/internal/tag_name.rb +14 -0
- data/spec/internal/app/models/internal_tag_name.rb +11 -0
- data/spec/internal/app/models/option_type.rb +12 -0
- data/spec/internal/app/models/option_value.rb +4 -0
- data/spec/internal/app/models/post.rb +15 -0
- data/spec/internal/app/models/product.rb +12 -0
- data/spec/internal/app/models/rgb_color.rb +16 -0
- data/spec/internal/app/models/tag.rb +12 -0
- data/spec/internal/app/models/tagging.rb +12 -0
- data/spec/internal/app/models/user.rb +12 -0
- data/spec/internal/app/models/variant.rb +12 -0
- data/spec/internal/app/views/layouts/application.html.erb +28 -0
- data/spec/internal/app/views/layouts/mailer.html.erb +13 -0
- data/spec/internal/app/views/layouts/mailer.text.erb +1 -0
- data/spec/internal/app/views/pwa/manifest.json.erb +22 -0
- data/spec/internal/app/views/pwa/service-worker.js +26 -0
- data/spec/internal/bin/bundle +117 -0
- data/spec/internal/bin/dev +11 -0
- data/spec/internal/bin/rackup +27 -0
- data/spec/internal/bin/rails +4 -0
- data/spec/internal/bin/rake +4 -0
- data/spec/internal/bin/setup +37 -0
- data/spec/internal/config/application.rb +50 -0
- data/spec/internal/config/boot.rb +3 -0
- data/spec/internal/config/credentials.yml.enc +1 -0
- data/spec/internal/config/database.yml +32 -0
- data/spec/internal/config/environment.rb +5 -0
- data/spec/internal/config/environments/development.rb +63 -0
- data/spec/internal/config/environments/production.rb +86 -0
- data/spec/internal/config/environments/test.rb +50 -0
- data/spec/internal/config/initializers/active_admin.rb +54 -0
- data/spec/internal/config/initializers/assets.rb +8 -0
- data/spec/internal/config/initializers/content_security_policy.rb +25 -0
- data/spec/internal/config/initializers/devise.rb +315 -0
- data/spec/internal/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/internal/config/initializers/inflections.rb +16 -0
- data/spec/internal/config/initializers/searchable_select.rb +6 -0
- data/spec/internal/config/locales/devise.en.yml +65 -0
- data/spec/internal/config/locales/en.yml +31 -0
- data/spec/internal/config/master.key +1 -0
- data/spec/internal/config/puma.rb +38 -0
- data/spec/internal/config/routes.rb +17 -0
- data/spec/internal/config.ru +6 -0
- data/spec/internal/db/schema.rb +174 -0
- data/spec/internal/db/seeds.rb +167 -0
- data/spec/internal/esbuild.config.js +34 -0
- data/spec/internal/lib/tasks/.keep +0 -0
- data/spec/internal/lib/tasks/active_admin.rake +55 -0
- data/spec/internal/log/.keep +0 -0
- data/spec/internal/package-lock.json +1954 -0
- data/spec/internal/package.json +21 -0
- data/spec/internal/public/400.html +114 -0
- data/spec/internal/public/404.html +114 -0
- data/spec/internal/public/406-unsupported-browser.html +114 -0
- data/spec/internal/public/422.html +114 -0
- data/spec/internal/public/500.html +114 -0
- data/spec/internal/public/icon.png +0 -0
- data/spec/internal/public/icon.svg +3 -0
- data/spec/internal/public/robots.txt +1 -0
- data/spec/internal/script/.keep +0 -0
- data/spec/internal/storage/.keep +0 -0
- data/spec/internal/tailwind.config.js +23 -0
- data/spec/internal/vendor/.keep +0 -0
- data/spec/internal/yarn.lock +824 -0
- data/spec/rails_helper.rb +62 -0
- data/spec/spec_helper.rb +138 -0
- data/spec/support/active_admin_helpers.rb +17 -0
- data/spec/support/capybara.rb +8 -0
- data/spec/support/models.rb +11 -0
- data/spec/support/pluck_polyfill.rb +12 -0
- data/spec/support/reset_settings.rb +5 -0
- metadata +497 -0
data/README.md
ADDED
@@ -0,0 +1,483 @@
|
|
1
|
+
# ActiveAdmin Tom Select
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/activeadmin-tom_select)
|
4
|
+
[](https://badge.fury.io/js/@rocket-sensei%2Factiveadmin-tom_select)
|
5
|
+
[](https://www.npmjs.com/package/@rocket-sensei/activeadmin-tom_select)
|
6
|
+
[](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,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")
|
data/config/database.yml
ADDED
@@ -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
|