rs-activeadmin-searchable_select 4.0.5

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 (145) 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 +170 -0
  5. data/.github/workflows/npm-publish.yml +47 -0
  6. data/.gitignore +27 -0
  7. data/.npmignore +58 -0
  8. data/.rspec +2 -0
  9. data/.rubocop.yml +67 -0
  10. data/.yardopts +2 -0
  11. data/AGENTS.md +39 -0
  12. data/Appraisals +15 -0
  13. data/CHANGELOG.md +24 -0
  14. data/CLAUDE.md +104 -0
  15. data/Gemfile +11 -0
  16. data/Gemfile.lock +366 -0
  17. data/LICENSE.txt +25 -0
  18. data/README.md +439 -0
  19. data/Rakefile +4 -0
  20. data/bin/rspec +17 -0
  21. data/config/database.yml +16 -0
  22. data/config.ru +28 -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/for-next-session.md +199 -0
  27. data/docs/guide-update-your-app.md +213 -0
  28. data/docs/propshaft-readme.md +121 -0
  29. data/docs/propshaft-upgrade.md +267 -0
  30. data/docs/rails-7-asset-pipeline.md +279 -0
  31. data/docs/setup-activeadmin-app.md +552 -0
  32. data/docs/setup-activeadmin-gem.md +535 -0
  33. data/docs/upload-system.md +225 -0
  34. data/gemfiles/rails_7.x_active_admin_4.x.gemfile +11 -0
  35. data/gemfiles/rails_7.x_active_admin_4.x.gemfile.lock +371 -0
  36. data/gemfiles/rails_8.x_active_admin_4.x.gemfile +11 -0
  37. data/gemfiles/rails_8.x_active_admin_4.x.gemfile.lock +366 -0
  38. data/lefthook.yml +17 -0
  39. data/lib/activeadmin/inputs/filters/searchable_select_input.rb +13 -0
  40. data/lib/activeadmin/inputs/searchable_select_input.rb +11 -0
  41. data/lib/activeadmin/searchable_select/engine.rb +17 -0
  42. data/lib/activeadmin/searchable_select/option_collection.rb +119 -0
  43. data/lib/activeadmin/searchable_select/resource_dsl_extension.rb +56 -0
  44. data/lib/activeadmin/searchable_select/resource_extension.rb +10 -0
  45. data/lib/activeadmin/searchable_select/select_input_extension.rb +159 -0
  46. data/lib/activeadmin/searchable_select/version.rb +5 -0
  47. data/lib/activeadmin/searchable_select.rb +20 -0
  48. data/lib/activeadmin-searchable_select.rb +4 -0
  49. data/lib/generators/active_admin/searchable_select/install/install_generator.rb +217 -0
  50. data/package-lock.json +18 -0
  51. data/package.json +45 -0
  52. data/rs-activeadmin-searchable_select.gemspec +38 -0
  53. data/sonar-project.properties +25 -0
  54. data/spec/features/ajax_params_spec.rb +31 -0
  55. data/spec/features/end_to_end_spec.rb +227 -0
  56. data/spec/features/filter_input_spec.rb +137 -0
  57. data/spec/features/form_input_spec.rb +122 -0
  58. data/spec/features/inline_ajax_setting_spec.rb +26 -0
  59. data/spec/features/input_errors_spec.rb +76 -0
  60. data/spec/features/input_html_options_spec.rb +30 -0
  61. data/spec/features/options_dsl_spec.rb +220 -0
  62. data/spec/features/production_build_spec.rb +108 -0
  63. data/spec/internal/app/admin/categories.rb +26 -0
  64. data/spec/internal/app/admin/dashboard.rb +29 -0
  65. data/spec/internal/app/admin/option_types.rb +19 -0
  66. data/spec/internal/app/admin/option_values.rb +30 -0
  67. data/spec/internal/app/admin/posts.rb +27 -0
  68. data/spec/internal/app/admin/products.rb +22 -0
  69. data/spec/internal/app/admin/rgb_colors.rb +25 -0
  70. data/spec/internal/app/admin/tag_names.rb +21 -0
  71. data/spec/internal/app/admin/test_ajax_params_category.rb +10 -0
  72. data/spec/internal/app/admin/test_ajax_params_post.rb +20 -0
  73. data/spec/internal/app/admin/test_form_post_class.rb +7 -0
  74. data/spec/internal/app/admin/test_form_post_custom.rb +11 -0
  75. data/spec/internal/app/admin/test_form_post_resource.rb +11 -0
  76. data/spec/internal/app/admin/test_form_post_resource_custom.rb +12 -0
  77. data/spec/internal/app/admin/test_inline_ajax_post.rb +9 -0
  78. data/spec/internal/app/admin/test_input_html_post.rb +11 -0
  79. data/spec/internal/app/admin/test_posts_display_text.rb +9 -0
  80. data/spec/internal/app/admin/test_posts_filter.rb +9 -0
  81. data/spec/internal/app/admin/test_posts_named.rb +9 -0
  82. data/spec/internal/app/admin/test_posts_pagination.rb +9 -0
  83. data/spec/internal/app/admin/test_posts_payload_lambda.rb +11 -0
  84. data/spec/internal/app/admin/test_posts_payload_proc.rb +9 -0
  85. data/spec/internal/app/admin/test_posts_scope_lambda.rb +8 -0
  86. data/spec/internal/app/admin/test_posts_scope_params.rb +8 -0
  87. data/spec/internal/app/admin/test_posts_scope_user.rb +8 -0
  88. data/spec/internal/app/admin/test_posts_text_attr.rb +5 -0
  89. data/spec/internal/app/admin/users.rb +23 -0
  90. data/spec/internal/app/admin/variants.rb +31 -0
  91. data/spec/internal/app/assets/config/manifest.js +1 -0
  92. data/spec/internal/app/assets/javascripts/active_admin.js +2 -0
  93. data/spec/internal/app/assets/javascripts/searchable_select_test.js +2 -0
  94. data/spec/internal/app/controllers/application_controller.rb +5 -0
  95. data/spec/internal/app/css/active_admin_source.css +81 -0
  96. data/spec/internal/app/js/active_admin.js +17 -0
  97. data/spec/internal/app/models/article.rb +12 -0
  98. data/spec/internal/app/models/category.rb +12 -0
  99. data/spec/internal/app/models/internal/tag_name.rb +14 -0
  100. data/spec/internal/app/models/internal_tag_name.rb +11 -0
  101. data/spec/internal/app/models/option_type.rb +12 -0
  102. data/spec/internal/app/models/option_value.rb +4 -0
  103. data/spec/internal/app/models/post.rb +15 -0
  104. data/spec/internal/app/models/product.rb +12 -0
  105. data/spec/internal/app/models/rgb_color.rb +16 -0
  106. data/spec/internal/app/models/user.rb +12 -0
  107. data/spec/internal/app/models/variant.rb +12 -0
  108. data/spec/internal/build_activeadmin_css.js +115 -0
  109. data/spec/internal/config/database.yml +7 -0
  110. data/spec/internal/config/environment.rb +48 -0
  111. data/spec/internal/config/initializers/active_admin.rb +53 -0
  112. data/spec/internal/config/initializers/assets.rb +9 -0
  113. data/spec/internal/config/initializers/searchable_select.rb +6 -0
  114. data/spec/internal/config/routes.rb +4 -0
  115. data/spec/internal/config.ru +4 -0
  116. data/spec/internal/db/schema.rb +63 -0
  117. data/spec/internal/db/seeds.rb +88 -0
  118. data/spec/internal/esbuild.config.js +30 -0
  119. data/spec/internal/inject-jquery.js +4 -0
  120. data/spec/internal/log/.gitignore +1 -0
  121. data/spec/internal/package/LICENSE.txt +25 -0
  122. data/spec/internal/package/README.md +439 -0
  123. data/spec/internal/package/package.json +45 -0
  124. data/spec/internal/package/src/index.js +1 -0
  125. data/spec/internal/package/src/searchable_select/init.js +1 -0
  126. data/spec/internal/package/src/searchable_select.css +1 -0
  127. data/spec/internal/package/src/searchable_select.scss +1 -0
  128. data/spec/internal/package-lock.json +1385 -0
  129. data/spec/internal/package.json +26 -0
  130. data/spec/internal/public/favicon.ico +0 -0
  131. data/spec/internal/spec/internal/app/css/active_admin_source.css +38 -0
  132. data/spec/internal/spec/internal/log/test.log +0 -0
  133. data/spec/internal/tailwind-active_admin.config.js +53 -0
  134. data/spec/rails_helper.rb +86 -0
  135. data/spec/spec_helper.rb +137 -0
  136. data/spec/support/active_admin_helpers.rb +17 -0
  137. data/spec/support/capybara.rb +8 -0
  138. data/spec/support/models.rb +88 -0
  139. data/spec/support/pluck_polyfill.rb +12 -0
  140. data/spec/support/reset_settings.rb +5 -0
  141. data/src/index.js +77 -0
  142. data/src/searchable_select/init.js +58 -0
  143. data/src/searchable_select.css +5 -0
  144. data/src/searchable_select.css.map +1 -0
  145. metadata +405 -0
@@ -0,0 +1,63 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table(:active_admin_comments, force: true) do |t|
3
+ t.string :namespace
4
+ t.text :body
5
+ t.string :resource_id, null: false
6
+ t.string :resource_type, null: false
7
+ t.references :author, polymorphic: true
8
+ t.timestamps null: false
9
+ end
10
+
11
+ create_table(:categories, force: true) do |t|
12
+ t.string :name
13
+ t.text :description
14
+ t.belongs_to :created_by
15
+ t.timestamps
16
+ end
17
+
18
+ create_table(:posts, force: true) do |t|
19
+ t.string :title
20
+ t.text :body
21
+ t.belongs_to :category
22
+ t.belongs_to :user
23
+ t.boolean :published
24
+ t.timestamps
25
+ end
26
+
27
+ create_table(:rgb_colors, force: true) do |t|
28
+ t.string :code
29
+ t.text :description
30
+ end
31
+
32
+ create_table(:internal_tag_names, force: true) do |t|
33
+ t.string :name
34
+ t.text :description
35
+ t.integer :color_id
36
+ end
37
+
38
+ create_table(:option_types, force: true) do |t|
39
+ t.string :name
40
+ end
41
+
42
+ create_table(:option_values, force: true) do |t|
43
+ t.string :value
44
+ t.belongs_to :option_type
45
+ end
46
+
47
+ create_table(:products, force: true) do |t|
48
+ t.string :name
49
+ t.belongs_to :option_type
50
+ end
51
+
52
+ create_table(:variants, force: true) do |t|
53
+ t.integer :price
54
+ t.belongs_to :product
55
+ t.belongs_to :option_value
56
+ end
57
+
58
+ create_table(:users, force: true) do |t|
59
+ t.string :name
60
+ t.string :email
61
+ t.timestamps
62
+ end
63
+ end
@@ -0,0 +1,88 @@
1
+ # Create sample users
2
+ users = []
3
+ 10.times do |i|
4
+ users << User.create!(name: "User #{i + 1}")
5
+ end
6
+
7
+ # Create sample categories
8
+ categories = []
9
+ 5.times do |i|
10
+ categories << Category.create!(
11
+ name: "Category #{i + 1}",
12
+ created_by: users.sample
13
+ )
14
+ end
15
+
16
+ # Create sample posts
17
+ 20.times do |i|
18
+ Post.create!(
19
+ title: "Post #{i + 1}",
20
+ category: categories.sample,
21
+ user: users.sample,
22
+ published: [true, false].sample
23
+ )
24
+ end
25
+
26
+ # Create RGB colors
27
+ colors = [
28
+ { code: '#FF0000', description: 'Red' },
29
+ { code: '#00FF00', description: 'Green' },
30
+ { code: '#0000FF', description: 'Blue' },
31
+ { code: '#FFFF00', description: 'Yellow' },
32
+ { code: '#FF00FF', description: 'Magenta' },
33
+ { code: '#00FFFF', description: 'Cyan' },
34
+ { code: '#000000', description: 'Black' },
35
+ { code: '#FFFFFF', description: 'White' }
36
+ ]
37
+
38
+ rgb_colors = colors.map { |color| RgbColor.create!(color) }
39
+
40
+ # Create internal tag names
41
+ 10.times do |i|
42
+ InternalTagName.create!(
43
+ name: "Tag #{i + 1}",
44
+ description: "Description for tag #{i + 1}",
45
+ color: rgb_colors.sample
46
+ )
47
+ end
48
+
49
+ # Create option types and values
50
+ option_types = []
51
+ 3.times do |i|
52
+ option_type = OptionType.create!(name: "Option Type #{i + 1}")
53
+ option_types << option_type
54
+
55
+ 5.times do |j|
56
+ OptionValue.create!(
57
+ value: "Value #{j + 1} for #{option_type.name}",
58
+ option_type: option_type
59
+ )
60
+ end
61
+ end
62
+
63
+ # Create products and variants
64
+ 10.times do |i|
65
+ product = Product.create!(
66
+ name: "Product #{i + 1}",
67
+ option_type: option_types.sample
68
+ )
69
+
70
+ 3.times do |j|
71
+ Variant.create!(
72
+ price: (10 + j) * 100,
73
+ product: product,
74
+ option_value: product.option_type&.option_values&.sample
75
+ )
76
+ end
77
+ end
78
+
79
+ puts 'Seed data created successfully!'
80
+ puts "Created #{User.count} users"
81
+ puts "Created #{Category.count} categories"
82
+ puts "Created #{Post.count} posts"
83
+ puts "Created #{RgbColor.count} RGB colors"
84
+ puts "Created #{InternalTagName.count} internal tag names"
85
+ puts "Created #{OptionType.count} option types"
86
+ puts "Created #{OptionValue.count} option values"
87
+ puts "Created #{Product.count} products"
88
+ puts "Created #{Variant.count} variants"
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ const esbuild = require('esbuild');
3
+ const path = require('path');
4
+
5
+ // Configuration for esbuild with proper module resolution
6
+ const config = {
7
+ entryPoints: ['app/js/active_admin.js'],
8
+ bundle: true,
9
+ sourcemap: true,
10
+ format: 'iife',
11
+ outdir: 'app/assets/builds',
12
+ publicPath: '/assets',
13
+ inject: ['./inject-jquery.js']
14
+ };
15
+
16
+ // Check if we're in watch mode
17
+ const watchMode = process.argv.includes('--watch');
18
+
19
+ if (watchMode) {
20
+ // Start the build with watch mode
21
+ esbuild.context(config).then(ctx => {
22
+ ctx.watch();
23
+ console.log('Watching for changes...');
24
+ });
25
+ } else {
26
+ // Single build
27
+ esbuild.build(config).then(() => {
28
+ console.log('Build completed');
29
+ }).catch(() => process.exit(1));
30
+ }
@@ -0,0 +1,4 @@
1
+ // https://github.com/evanw/esbuild/issues/1681
2
+ // This file injects jQuery as a global for all modules
3
+ export { default as $ } from 'jquery/dist/jquery.js'
4
+ export { default as jQuery } from 'jquery/dist/jquery.js'
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,25 @@
1
+
2
+ Copyright for portions of `codevise/activeadmin-searchable_select`
3
+ held by Mark Fariburn, Praxitar Ltd, 2014 as part of
4
+ `mfairburn/activeadmin-select2` which this project is based on. All
5
+ other copyright for `codevise/activeadmin-searchable_select` held by
6
+ Codevise Solutions Ltd, 2017.
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining
9
+ a copy of this software and associated documentation files (the
10
+ "Software"), to deal in the Software without restriction, including
11
+ without limitation the rights to use, copy, modify, merge, publish,
12
+ distribute, sublicense, and/or sell copies of the Software, and to
13
+ permit persons to whom the Software is furnished to do so, subject to
14
+ the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be
17
+ included in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,439 @@
1
+ # ActiveAdmin Searchable Select
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/activeadmin-searchable_select.svg)](http://badge.fury.io/rb/activeadmin-searchable_select)
4
+ [![NPM Version](https://badge.fury.io/js/@codevise%2Factiveadmin-searchable_select.svg)](https://badge.fury.io/js/@codevise%2Factiveadmin-searchable_select)
5
+ [![npm](https://img.shields.io/npm/dm/@codevise/activeadmin-searchable_select)](https://www.npmjs.com/package/@codevise/activeadmin-searchable_select)
6
+ [![Build Status](https://github.com/codevise/activeadmin-searchable_select/actions/workflows/tests.yml/badge.svg)](https://github.com/codevise/activeadmin-searchable_select/actions)
7
+
8
+ Searchable select boxes (via [Select2](https://select2.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
+ ## Installation
13
+
14
+ Add `activeadmin-searchable_select` to your Gemfile:
15
+
16
+ ```ruby
17
+ gem 'activeadmin-searchable_select'
18
+ ```
19
+
20
+ ### ActiveAdmin 4.x (esbuild/importmap)
21
+
22
+ ActiveAdmin 4 uses modern JavaScript bundlers. If you encounter "select2 is not a function" errors in production, see the [complete setup guide](docs/setup-active-admin.md).
23
+
24
+ #### Quick Install with Generator
25
+
26
+ ```bash
27
+ # For esbuild (recommended)
28
+ rails generate active_admin:searchable_select:install
29
+
30
+ # For importmap
31
+ rails generate active_admin:searchable_select:install --bundler=importmap
32
+ ```
33
+
34
+ #### Manual Setup for esbuild
35
+
36
+ 1. Install npm packages:
37
+ ```bash
38
+ npm install @codevise/activeadmin-searchable_select jquery select2
39
+ ```
40
+
41
+ 2. In `app/javascript/active_admin.js`:
42
+ ```javascript
43
+ import "@activeadmin/activeadmin";
44
+ import $ from 'jquery';
45
+ import select2 from 'select2';
46
+
47
+ // Critical: Initialize select2 on jQuery (fixes production builds)
48
+ select2($);
49
+ window.$ = window.jQuery = $;
50
+
51
+ import '@codevise/activeadmin-searchable_select';
52
+ ```
53
+
54
+ 3. Add Select2 CSS to your ActiveAdmin stylesheet:
55
+ ```css
56
+ @import url('https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css');
57
+ ```
58
+
59
+ ### ActiveAdmin 3.x and older
60
+
61
+ ##### Using assets via Sprockets
62
+ Import stylesheets and require javascripts:
63
+
64
+ ```scss
65
+ // active_admin.css.scss
66
+ @import "active_admin/searchable_select";
67
+ ```
68
+
69
+ ```coffee
70
+ // active_admin.js
71
+ //= require active_admin/searchable_select
72
+ ```
73
+
74
+ ##### Using assets via Webpacker
75
+
76
+ Add to `package.json`:
77
+ ```json
78
+ "dependencies": {
79
+ "@codevise/activeadmin-searchable_select": "^1.8.0"
80
+ }
81
+ ```
82
+
83
+ In `app/javascript/packs/active_admin.js`:
84
+ ```javascript
85
+ import '@codevise/activeadmin-searchable_select';
86
+ ```
87
+
88
+ In `app/javascript/stylesheets/active_admin.scss`:
89
+ ```css
90
+ @import '@codevise/activeadmin-searchable_select';
91
+ ```
92
+
93
+ ## Usage
94
+
95
+ ### Making Select Boxes Searchable
96
+
97
+ To add search functionality to a select box, use the
98
+ `:searchable_select` input type:
99
+
100
+ ```ruby
101
+ ActiveAdmin.register Product do
102
+ form do |f|
103
+ f.input(:category, as: :searchable_select)
104
+ end
105
+ end
106
+ ```
107
+
108
+ This also works for filters:
109
+
110
+ ```ruby
111
+ ActiveAdmin.register Product do
112
+ filter(:category, as: :searchable_select)
113
+ end
114
+ ```
115
+
116
+ By default, you can only select one at a time for a filter. You can
117
+ specify a multi-select with:
118
+
119
+ ```ruby
120
+ ActiveAdmin.register Product do
121
+ filter(:category, as: :searchable_select, multiple: true)
122
+ end
123
+ ```
124
+
125
+ ### Fetching Options via Ajax
126
+
127
+ For large collections, rendering the whole set of options can be to
128
+ expensive. Use the `ajax` option to fetch a set of matching options
129
+ once the user begins to type:
130
+
131
+ ```ruby
132
+
133
+ ActiveAdmin.register Product do
134
+ filter(:category,
135
+ as: :searchable_select,
136
+ ajax: true)
137
+ end
138
+ ```
139
+
140
+ If the input attribute corresponds to an ActiveAdmin resource, it is
141
+ expected to provide the JSON endpoint that provides the options. Use
142
+ the `searchable_select_options` method to define the required
143
+ collection action:
144
+
145
+ ```ruby
146
+ ActiveAdmin.register Category do
147
+ searchable_select_options(scope: Category.all,
148
+ text_attribute: :name)
149
+ end
150
+ ```
151
+
152
+ By default, `scope` needs to be a Ransack enabled ActiveRecord
153
+ collection proxy determining which options are available. The
154
+ attribute given by `text_attribute` will be used to get a display name
155
+ for each record. Via Ransack, it is also used to filter by search
156
+ term. Limiting result set size is handled automatically.
157
+
158
+ You can customize the display text:
159
+
160
+ ```ruby
161
+ ActiveAdmin.register Category do
162
+ searchable_select_options(scope: Category.all,
163
+ text_attribute: :name,
164
+ display_text: ->(record) { "Category: #{record.name}" } )
165
+ end
166
+ ```
167
+
168
+ Note that `text_attribute` is still required to perform filtering via
169
+ Ransack. You can pass the `filter` option, to specify your own
170
+ filtering strategy:
171
+
172
+ ```ruby
173
+ ActiveAdmin.register Category do
174
+ searchable_select_options(scope: Category.all,
175
+ text_attribute: :name,
176
+ filter: lambda |term, scope|
177
+ scope.ransack(name_cont_all: term.split(' ')).result
178
+ end)
179
+ end
180
+ ```
181
+
182
+ `scope` can also be a lambda which is evaluated in the context of the
183
+ collection action defined by the helper:
184
+
185
+ ```ruby
186
+ ActiveAdmin.register Category do
187
+ searchable_select_options(scope: -> { Category.allowed_for(current_user) },
188
+ text_attribute: :name)
189
+ end
190
+ ```
191
+
192
+ If the input attribute is set on the form's object, ajax based
193
+ searchable selects will automatically render a single option to ensure
194
+ the selected item is displayed correctly even before options have been
195
+ loaded asynchronously.
196
+
197
+ #### Specifying the Options Endpoint Resource
198
+
199
+ If the resource that provides the options endpoint cannot be guessed
200
+ based on the input attribute name, you can pass an object with a
201
+ `resource` key as `ajax` option:
202
+
203
+ ```ruby
204
+ ActiveAdmin.register Product do
205
+ form do |f|
206
+ f.input(:additional_category,
207
+ as: :searchable_select,
208
+ ajax: { resource: Category })
209
+ end
210
+ end
211
+ ```
212
+
213
+ #### Multiple Options Endpoints per Resource
214
+
215
+ A single ActiveAdmin resource can define multiple options endpoints:
216
+
217
+ ```ruby
218
+ ActiveAdmin.register Category do
219
+ searchable_select_options(name: :favorites,
220
+ scope: Category.favorites,
221
+ text_attribute: :name)
222
+
223
+ searchable_select_options(name: :recent,
224
+ scope: Category.recent,
225
+ text_attribute: :name)
226
+ end
227
+ ```
228
+
229
+ To specify which collection to use, pass an object with a
230
+ `collection_name` key as `ajax` option:
231
+
232
+ ```ruby
233
+ ActiveAdmin.register Product do
234
+ form do |f|
235
+ f.input(:category,
236
+ as: :searchable_select,
237
+ ajax: { collection_name: :favorites })
238
+ end
239
+ end
240
+ ```
241
+
242
+ #### Querying Multiple Attributes
243
+
244
+ ActiveAdmin Searchable Select querying is performed by Ransack. As such, you can
245
+ build your query in a way that it can query multiple attributes at once.
246
+
247
+ ```ruby
248
+ ActiveAdmin.register User do
249
+ searchable_select_options(scope: User.all,
250
+ text_attribute: :username,
251
+ filter: lambda do |term, scope|
252
+ scope.ransack(email_or_username_cont: term).result
253
+ end)
254
+ end
255
+ ```
256
+
257
+ In this example, the `all` scope will query `email OR username`.
258
+
259
+ You can add the additional payload as dsl option:
260
+
261
+ ```ruby
262
+ ActiveAdmin.register Category do
263
+ searchable_select_options(scope: Category.all,
264
+ text_attribute: :name,
265
+ additional_payload: ->(record) { { foo: record.bar } } )
266
+ end
267
+ ```
268
+
269
+ response example which uses additional_payload:
270
+
271
+ ```json
272
+ {
273
+ "results": [{ "id": "1", "text": "Bicycles", "foo": "Bar" }],
274
+ "pagination": { "more": "false" }
275
+ }
276
+ ```
277
+
278
+ #### Passing Parameters
279
+
280
+ You can pass additional parameters to the options endpoint:
281
+
282
+ ```ruby
283
+ ActiveAdmin.register Product do
284
+ form do |f|
285
+ f.input(:category,
286
+ as: :searchable_select,
287
+ ajax: {
288
+ params: {
289
+ some: 'value'
290
+ }
291
+ })
292
+ end
293
+ end
294
+ ```
295
+
296
+ The lambda passed as `scope` can receive those parameters as first
297
+ argument:
298
+
299
+ ```ruby
300
+ ActiveAdmin.register Category do
301
+ searchable_select_options(scope: lambda do |params|
302
+ Category.find_all_by_some(params[:some])
303
+ end,
304
+ text_attribute: :name)
305
+ end
306
+ ```
307
+
308
+ #### Path options for nested resources
309
+
310
+ Example for the following setup:
311
+
312
+ ```ruby
313
+ # Models
314
+ class OptionType < ActiveRecord::Base; end
315
+
316
+ class OptionValue < ActiveRecord::Base
317
+ belongs_to :option_type
318
+ end
319
+
320
+ class Product < ActiveRecord::Base
321
+ belongs_to :option_type
322
+ has_many :variants
323
+ end
324
+
325
+ class Variant < ActiveRecord::Base
326
+ belongs_to :product
327
+ belongs_to :option_value
328
+ end
329
+
330
+ # ActiveAdmin
331
+ ActiveAdmin.register(OptionType)
332
+
333
+ ActiveAdmin.register(Product)
334
+
335
+ ActiveAdmin.register(OptionValue) do
336
+ belongs_to :option_type
337
+ searchable_select_options(scope: lambda do |params|
338
+ OptionValue.where(
339
+ option_type_id: params[:option_type_id]
340
+ )
341
+ end,
342
+ text_attribute: :value)
343
+ end
344
+ ```
345
+
346
+ It is possible to pass path parameters for correctly generating URLs for nested resources fetching via `path_params`
347
+
348
+ ```ruby
349
+ ActiveAdmin.register(Variant) do
350
+ belongs_to :product
351
+
352
+ form do |f|
353
+ ...
354
+ f.input(:option_value,
355
+ as: :searchable_select,
356
+ ajax: {
357
+ resource: OptionValue,
358
+ path_params: {
359
+ option_type_id: f.object.product.option_type_id
360
+ }
361
+ })
362
+ ...
363
+ end
364
+ end
365
+ ```
366
+
367
+ 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`)
368
+
369
+ #### Inlining Ajax Options in Feature Tests
370
+
371
+ When writing UI driven feature specs (i.e. with Capybara),
372
+ asynchronous loading of select options can increase test
373
+ complexity. `activeadmin-searchable_select` provides an option to
374
+ render all available options just like a normal select input while
375
+ still exercsing the same code paths including `scope` and
376
+ `text_attribute` handling.
377
+
378
+ For example with RSpec/Capybara, simply set `inline_ajax_options` true
379
+ for feature specs:
380
+
381
+ ```ruby
382
+ RSpec.configure do |config|
383
+ config.before(:each) do |example|
384
+ ActiveAdmin::SearchableSelect.inline_ajax_options = (example.metadata[:type] == :feature)
385
+ end
386
+ end
387
+
388
+ ```
389
+
390
+ ### Passing options to Select2
391
+
392
+ It is possible to pass and define configuration options to Select2
393
+ via `data-attributes` using nested (subkey) options.
394
+
395
+ Attributes need to be added to the `input_html` option in the form input.
396
+ For example you can tell Select2 how long to wait after a user
397
+ has stopped typing before sending the request:
398
+
399
+ ```ruby
400
+ ...
401
+ f.input(:category,
402
+ as: :searchable_select,
403
+ ajax: true,
404
+ input_html: {
405
+ data: {
406
+ 'ajax--delay' => 500
407
+ }
408
+ })
409
+ ...
410
+ ```
411
+
412
+
413
+ ## Development
414
+
415
+ To run the tests install bundled gems and invoke RSpec:
416
+
417
+ ```
418
+ $ bundle
419
+ $ bundle exec rspec
420
+ ```
421
+
422
+ The test suite can be run against different versions of Rails and
423
+ Active Admin (see `Appraisals` file):
424
+
425
+ ```
426
+ $ appraisal install
427
+ $ appraisal rspec
428
+ ```
429
+
430
+ Please make sure changes conform with the styleguide:
431
+
432
+ ```
433
+ $ bundle exec rubocop
434
+ ```
435
+
436
+ ## Acknowledgements
437
+
438
+ Based on
439
+ [mfairburn/activeadmin-select2](https://github.com/mfairburn/activeadmin-select2).
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@rocket-sensei/activeadmin-searchable_select",
3
+ "version": "4.0.2",
4
+ "description": "Use searchable selects based on Select2 in Active Admin forms and filters.",
5
+ "main": "src/index.js",
6
+ "module": "src/index.js",
7
+ "style": "src/searchable_select.scss",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./src/index.js",
11
+ "require": "./src/index.js",
12
+ "default": "./src/index.js"
13
+ },
14
+ "./css": "./src/searchable_select.css",
15
+ "./style": "./src/searchable_select.css",
16
+ "./scss": "./src/searchable_select.scss"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/glebtv/activeadmin-searchable_select.git"
21
+ },
22
+ "author": "Codevise Solutions Ltd <info@codevise.de>",
23
+ "license": "MIT",
24
+ "private": false,
25
+ "bugs": {
26
+ "url": "https://github.com/glebtv/activeadmin-searchable_select/issues"
27
+ },
28
+ "homepage": "https://github.com/glebtv/activeadmin-searchable_select#readme",
29
+ "keywords": [
30
+ "select2",
31
+ "active",
32
+ "admin",
33
+ "searchable",
34
+ "select",
35
+ "activeadmin",
36
+ "rails"
37
+ ],
38
+ "peerDependencies": {
39
+ "jquery": ">= 3.0, < 5",
40
+ "select2": "^4.0.0 || ^4.1.0-rc.0"
41
+ },
42
+ "files": [
43
+ "src/**/*"
44
+ ]
45
+ }
@@ -0,0 +1 @@
1
+ ../../../../src/index.js
@@ -0,0 +1 @@
1
+ ../../../../../src/searchable_select/init.js