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.
- checksums.yaml +7 -0
- data/.actrc +20 -0
- data/.claude/commands/fix-tests.md +203 -0
- data/.github/workflows/ci.yml +170 -0
- data/.github/workflows/npm-publish.yml +47 -0
- data/.gitignore +27 -0
- data/.npmignore +58 -0
- data/.rspec +2 -0
- data/.rubocop.yml +67 -0
- data/.yardopts +2 -0
- data/AGENTS.md +39 -0
- data/Appraisals +15 -0
- data/CHANGELOG.md +24 -0
- data/CLAUDE.md +104 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +366 -0
- data/LICENSE.txt +25 -0
- data/README.md +439 -0
- data/Rakefile +4 -0
- data/bin/rspec +17 -0
- data/config/database.yml +16 -0
- data/config.ru +28 -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/for-next-session.md +199 -0
- data/docs/guide-update-your-app.md +213 -0
- data/docs/propshaft-readme.md +121 -0
- data/docs/propshaft-upgrade.md +267 -0
- data/docs/rails-7-asset-pipeline.md +279 -0
- data/docs/setup-activeadmin-app.md +552 -0
- data/docs/setup-activeadmin-gem.md +535 -0
- data/docs/upload-system.md +225 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile +11 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile.lock +371 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile +11 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile.lock +366 -0
- data/lefthook.yml +17 -0
- data/lib/activeadmin/inputs/filters/searchable_select_input.rb +13 -0
- data/lib/activeadmin/inputs/searchable_select_input.rb +11 -0
- data/lib/activeadmin/searchable_select/engine.rb +17 -0
- data/lib/activeadmin/searchable_select/option_collection.rb +119 -0
- data/lib/activeadmin/searchable_select/resource_dsl_extension.rb +56 -0
- data/lib/activeadmin/searchable_select/resource_extension.rb +10 -0
- data/lib/activeadmin/searchable_select/select_input_extension.rb +159 -0
- data/lib/activeadmin/searchable_select/version.rb +5 -0
- data/lib/activeadmin/searchable_select.rb +20 -0
- data/lib/activeadmin-searchable_select.rb +4 -0
- data/lib/generators/active_admin/searchable_select/install/install_generator.rb +217 -0
- data/package-lock.json +18 -0
- data/package.json +45 -0
- data/rs-activeadmin-searchable_select.gemspec +38 -0
- data/sonar-project.properties +25 -0
- data/spec/features/ajax_params_spec.rb +31 -0
- data/spec/features/end_to_end_spec.rb +227 -0
- data/spec/features/filter_input_spec.rb +137 -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 +220 -0
- data/spec/features/production_build_spec.rb +108 -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 +1 -0
- data/spec/internal/app/assets/javascripts/active_admin.js +2 -0
- data/spec/internal/app/assets/javascripts/searchable_select_test.js +2 -0
- data/spec/internal/app/controllers/application_controller.rb +5 -0
- data/spec/internal/app/css/active_admin_source.css +81 -0
- data/spec/internal/app/js/active_admin.js +17 -0
- data/spec/internal/app/models/article.rb +12 -0
- data/spec/internal/app/models/category.rb +12 -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/user.rb +12 -0
- data/spec/internal/app/models/variant.rb +12 -0
- data/spec/internal/build_activeadmin_css.js +115 -0
- data/spec/internal/config/database.yml +7 -0
- data/spec/internal/config/environment.rb +48 -0
- data/spec/internal/config/initializers/active_admin.rb +53 -0
- data/spec/internal/config/initializers/assets.rb +9 -0
- data/spec/internal/config/initializers/searchable_select.rb +6 -0
- data/spec/internal/config/routes.rb +4 -0
- data/spec/internal/config.ru +4 -0
- data/spec/internal/db/schema.rb +63 -0
- data/spec/internal/db/seeds.rb +88 -0
- data/spec/internal/esbuild.config.js +30 -0
- data/spec/internal/inject-jquery.js +4 -0
- data/spec/internal/log/.gitignore +1 -0
- data/spec/internal/package/LICENSE.txt +25 -0
- data/spec/internal/package/README.md +439 -0
- data/spec/internal/package/package.json +45 -0
- data/spec/internal/package/src/index.js +1 -0
- data/spec/internal/package/src/searchable_select/init.js +1 -0
- data/spec/internal/package/src/searchable_select.css +1 -0
- data/spec/internal/package/src/searchable_select.scss +1 -0
- data/spec/internal/package-lock.json +1385 -0
- data/spec/internal/package.json +26 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/internal/spec/internal/app/css/active_admin_source.css +38 -0
- data/spec/internal/spec/internal/log/test.log +0 -0
- data/spec/internal/tailwind-active_admin.config.js +53 -0
- data/spec/rails_helper.rb +86 -0
- data/spec/spec_helper.rb +137 -0
- data/spec/support/active_admin_helpers.rb +17 -0
- data/spec/support/capybara.rb +8 -0
- data/spec/support/models.rb +88 -0
- data/spec/support/pluck_polyfill.rb +12 -0
- data/spec/support/reset_settings.rb +5 -0
- data/src/index.js +77 -0
- data/src/searchable_select/init.js +58 -0
- data/src/searchable_select.css +5 -0
- data/src/searchable_select.css.map +1 -0
- metadata +405 -0
@@ -0,0 +1,535 @@
|
|
1
|
+
# Setting Up ActiveAdmin 4 Extension Gem with Combustion
|
2
|
+
|
3
|
+
This guide shows how to set up a new Rails gem for ActiveAdmin 4 with Combustion testing, exactly as configured in the working activeadmin_trumbowyg gem.
|
4
|
+
|
5
|
+
## CRITICAL: JavaScript Architecture for Gem Distribution
|
6
|
+
|
7
|
+
**Your gem's JavaScript code must live in the gem, NOT be copied to user apps!**
|
8
|
+
|
9
|
+
✅ **Correct approach:**
|
10
|
+
- Main JS module in `app/assets/javascripts/your_gem.js`
|
11
|
+
- Generator adds single import: `import 'your_gem_name'`
|
12
|
+
- Users get updates when they update your gem
|
13
|
+
- Code is maintainable and reusable
|
14
|
+
|
15
|
+
❌ **Wrong approach:**
|
16
|
+
- Generator copies large code blocks to user's app
|
17
|
+
- Users never get updates without re-running generator
|
18
|
+
- Code duplication across all installations
|
19
|
+
- Maintenance nightmare
|
20
|
+
|
21
|
+
## 1. Create Gem Structure
|
22
|
+
|
23
|
+
```bash
|
24
|
+
# Create new gem
|
25
|
+
bundle gem activeadmin_your_feature --test=rspec
|
26
|
+
cd activeadmin_your_feature
|
27
|
+
```
|
28
|
+
|
29
|
+
## 2. Update Gemspec
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# activeadmin_your_feature.gemspec
|
33
|
+
Gem::Specification.new do |spec|
|
34
|
+
spec.name = "activeadmin_your_feature"
|
35
|
+
# ... other standard fields ...
|
36
|
+
|
37
|
+
spec.required_ruby_version = ">= 3.2"
|
38
|
+
|
39
|
+
# Runtime dependencies
|
40
|
+
spec.add_runtime_dependency "activeadmin", [">= 1.0", "< 5"]
|
41
|
+
|
42
|
+
# Development dependencies
|
43
|
+
spec.add_development_dependency "combustion", "~> 1.3"
|
44
|
+
spec.add_development_dependency "rspec-rails", "~> 6.0"
|
45
|
+
spec.add_development_dependency "capybara", "~> 3.39"
|
46
|
+
spec.add_development_dependency "importmap-rails", "~> 2.0"
|
47
|
+
spec.add_development_dependency "propshaft" # Required - Sprockets not supported
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
## 3. Set Up Gemfile
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
# Gemfile
|
55
|
+
source "https://rubygems.org"
|
56
|
+
gemspec
|
57
|
+
|
58
|
+
gem "rails", "~> 7.2"
|
59
|
+
gem "activeadmin", "~> 4.0.0.beta16"
|
60
|
+
gem "sqlite3"
|
61
|
+
gem "puma"
|
62
|
+
|
63
|
+
# Required for ActiveAdmin 4
|
64
|
+
gem "importmap-rails", "~> 2.0"
|
65
|
+
gem "propshaft" # Required - Sprockets not supported
|
66
|
+
|
67
|
+
group :development, :test do
|
68
|
+
gem "combustion", "~> 1.3"
|
69
|
+
gem "rspec-rails"
|
70
|
+
gem "capybara"
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
## 4. Generate Combustion Test App
|
75
|
+
|
76
|
+
```bash
|
77
|
+
# This creates spec/internal directory
|
78
|
+
bundle exec combust
|
79
|
+
```
|
80
|
+
|
81
|
+
## 5. Configure config.ru (CRITICAL LOADING ORDER!)
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# config.ru
|
85
|
+
require "rubygems"
|
86
|
+
require "bundler"
|
87
|
+
|
88
|
+
# DON'T use Bundler.require - loads gems too early!
|
89
|
+
Bundler.setup(:default, :development)
|
90
|
+
|
91
|
+
# Load Rails and combustion first
|
92
|
+
require 'combustion'
|
93
|
+
|
94
|
+
# Initialize Combustion with Rails components
|
95
|
+
Combustion.initialize! :active_record, :action_controller, :action_view do
|
96
|
+
config.load_defaults Rails::VERSION::STRING.to_f if Rails::VERSION::MAJOR >= 7
|
97
|
+
end
|
98
|
+
|
99
|
+
# NOW load ActiveAdmin and dependencies after Rails is initialized
|
100
|
+
require 'importmap-rails'
|
101
|
+
require 'active_admin'
|
102
|
+
require 'activeadmin_your_feature'
|
103
|
+
|
104
|
+
# If you have custom Formtastic inputs
|
105
|
+
# require 'formtastic/inputs/your_input'
|
106
|
+
|
107
|
+
run Combustion::Application
|
108
|
+
```
|
109
|
+
|
110
|
+
## 6. Set Up Test App Structure
|
111
|
+
|
112
|
+
```bash
|
113
|
+
cd spec/internal
|
114
|
+
|
115
|
+
# Create necessary directories
|
116
|
+
mkdir -p app/admin
|
117
|
+
mkdir -p app/assets/{builds,config,stylesheets,javascripts}
|
118
|
+
mkdir -p app/js
|
119
|
+
mkdir -p app/models
|
120
|
+
mkdir -p config/initializers
|
121
|
+
mkdir -p db
|
122
|
+
```
|
123
|
+
|
124
|
+
## 7. Database Schema
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
# spec/internal/db/schema.rb
|
128
|
+
ActiveRecord::Schema.define do
|
129
|
+
create_table :active_admin_comments, force: true do |t|
|
130
|
+
t.string :namespace
|
131
|
+
t.text :body
|
132
|
+
t.references :resource, polymorphic: true
|
133
|
+
t.references :author, polymorphic: true
|
134
|
+
t.timestamps
|
135
|
+
end
|
136
|
+
|
137
|
+
# Add your test models
|
138
|
+
create_table :posts, force: true do |t|
|
139
|
+
t.string :title
|
140
|
+
t.text :body
|
141
|
+
t.timestamps
|
142
|
+
end
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
## 8. ActiveAdmin Configuration
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
# spec/internal/config/initializers/active_admin.rb
|
150
|
+
ActiveAdmin.setup do |config|
|
151
|
+
config.site_title = "Test App"
|
152
|
+
config.authentication_method = false
|
153
|
+
config.current_user_method = false
|
154
|
+
config.batch_actions = true
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
## 9. Routes Configuration
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
# spec/internal/config/routes.rb
|
162
|
+
Rails.application.routes.draw do
|
163
|
+
ActiveAdmin.routes(self)
|
164
|
+
root to: 'admin/dashboard#index'
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
## 10. Install NPM Dependencies
|
169
|
+
|
170
|
+
```bash
|
171
|
+
cd spec/internal
|
172
|
+
npm init -y
|
173
|
+
|
174
|
+
# Install required packages
|
175
|
+
npm install --save-dev \
|
176
|
+
@activeadmin/activeadmin@^3.3.0 \
|
177
|
+
tailwindcss@^3.4.17 \
|
178
|
+
esbuild@^0.24.2
|
179
|
+
|
180
|
+
# Install runtime dependencies (if your gem needs jQuery plugins)
|
181
|
+
npm install \
|
182
|
+
jquery@^3.7.1 \
|
183
|
+
your-vendor-package
|
184
|
+
```
|
185
|
+
|
186
|
+
## 11. Create Package.json Scripts
|
187
|
+
|
188
|
+
```json
|
189
|
+
{
|
190
|
+
"name": "internal",
|
191
|
+
"version": "1.0.0",
|
192
|
+
"scripts": {
|
193
|
+
"build:css": "node ./build_css.js",
|
194
|
+
"build:js": "node esbuild.config.js",
|
195
|
+
"build": "npm run build:js && npm run build:css",
|
196
|
+
"watch": "npm run build:js --watch & npm run build:css -- --watch"
|
197
|
+
},
|
198
|
+
"dependencies": {
|
199
|
+
"esbuild": "^0.24.2",
|
200
|
+
"jquery": "^3.7.1"
|
201
|
+
},
|
202
|
+
"devDependencies": {
|
203
|
+
"@activeadmin/activeadmin": "^3.3.0",
|
204
|
+
"tailwindcss": "^3.4.17"
|
205
|
+
}
|
206
|
+
}
|
207
|
+
```
|
208
|
+
|
209
|
+
## 12. Create Tailwind Config (WITH SAFELIST!)
|
210
|
+
|
211
|
+
```javascript
|
212
|
+
// spec/internal/tailwind.config.mjs
|
213
|
+
import activeAdminPlugin from '@activeadmin/activeadmin/plugin'
|
214
|
+
import { execSync } from 'node:child_process'
|
215
|
+
|
216
|
+
let activeAdminPath = null
|
217
|
+
try {
|
218
|
+
activeAdminPath = execSync('bundle show activeadmin', { encoding: 'utf8' }).trim()
|
219
|
+
} catch (e) {
|
220
|
+
// Continue without scanning if bundler unavailable
|
221
|
+
}
|
222
|
+
|
223
|
+
export default {
|
224
|
+
content: [
|
225
|
+
'./app/admin/**/*.{arb,erb,html,rb}',
|
226
|
+
'./app/views/**/*.{arb,erb,html,rb}',
|
227
|
+
'./app/javascript/**/*.js',
|
228
|
+
'./app/js/**/*.js',
|
229
|
+
...(activeAdminPath ? [
|
230
|
+
`${activeAdminPath}/vendor/javascript/flowbite.js`,
|
231
|
+
`${activeAdminPath}/plugin.js`,
|
232
|
+
`${activeAdminPath}/app/views/**/*.{arb,erb,html,rb}`,
|
233
|
+
] : [])
|
234
|
+
],
|
235
|
+
darkMode: 'selector',
|
236
|
+
plugins: [activeAdminPlugin],
|
237
|
+
// CRITICAL: Without safelist, ActiveAdmin layout breaks!
|
238
|
+
safelist: [
|
239
|
+
// Grid and layout
|
240
|
+
'grid', 'gap-4', 'gap-6', 'lg:grid-cols-3', 'md:grid-cols-2',
|
241
|
+
'col-span-2', 'col-span-3', 'lg:col-span-2', 'lg:col-span-1',
|
242
|
+
// Flexbox
|
243
|
+
'flex', 'flex-col', 'flex-row', 'flex-wrap', 'items-center',
|
244
|
+
'justify-between', 'justify-center', 'items-start', 'items-end',
|
245
|
+
// Spacing
|
246
|
+
'p-4', 'p-6', 'px-4', 'px-6', 'py-2', 'py-4', 'm-0', 'mx-auto',
|
247
|
+
'mt-4', 'mb-4', 'ml-auto', 'mr-auto', 'space-y-4', 'space-x-4',
|
248
|
+
// Display
|
249
|
+
'block', 'inline-block', 'hidden', 'lg:hidden', 'lg:block', 'lg:flex',
|
250
|
+
// Width/Height
|
251
|
+
'w-full', 'w-auto', 'w-64', 'h-full', 'min-h-screen', 'max-w-7xl',
|
252
|
+
// Typography
|
253
|
+
'text-sm', 'text-base', 'text-lg', 'text-xl', 'font-medium', 'font-semibold',
|
254
|
+
// Colors
|
255
|
+
'bg-white', 'bg-gray-50', 'bg-gray-100', 'text-gray-900', 'text-gray-600',
|
256
|
+
'dark:bg-gray-800', 'dark:bg-gray-900', 'dark:text-white', 'dark:text-gray-300',
|
257
|
+
// Borders
|
258
|
+
'border', 'border-gray-200', 'dark:border-gray-700', 'rounded-lg', 'rounded-md',
|
259
|
+
// Forms
|
260
|
+
'form-input', 'form-select', 'form-checkbox',
|
261
|
+
// Position & Z-index
|
262
|
+
'relative', 'absolute', 'fixed', 'sticky', 'top-0', 'left-0', 'right-0',
|
263
|
+
'z-10', 'z-20', 'z-30', 'z-40', 'z-50',
|
264
|
+
// Shadows
|
265
|
+
'shadow', 'shadow-md', 'shadow-lg'
|
266
|
+
]
|
267
|
+
}
|
268
|
+
```
|
269
|
+
|
270
|
+
## 13. Create Build Script for CSS
|
271
|
+
|
272
|
+
```javascript
|
273
|
+
// spec/internal/build_css.js
|
274
|
+
#!/usr/bin/env node
|
275
|
+
const fs = require('fs');
|
276
|
+
const path = require('path');
|
277
|
+
const { spawnSync } = require('child_process');
|
278
|
+
|
279
|
+
const root = __dirname;
|
280
|
+
const inputPath = path.join(root, 'app/assets/stylesheets/active_admin_source.css');
|
281
|
+
const tmpPath = path.join(root, 'app/assets/stylesheets/__aa_tmp.css');
|
282
|
+
const outPath = path.join(root, 'app/assets/builds/active_admin.css');
|
283
|
+
|
284
|
+
function build() {
|
285
|
+
// Read source file
|
286
|
+
const src = fs.readFileSync(inputPath, 'utf8');
|
287
|
+
|
288
|
+
// If you have vendor CSS to include:
|
289
|
+
// const vendorCssPath = path.join(root, 'node_modules/your-package/dist/styles.css');
|
290
|
+
// const vendorCss = fs.readFileSync(vendorCssPath, 'utf8');
|
291
|
+
|
292
|
+
// Ensure Tailwind directives are first
|
293
|
+
const tailwindDirectives = '@tailwind base;\n@tailwind components;\n@tailwind utilities;';
|
294
|
+
|
295
|
+
// Build final CSS
|
296
|
+
// With vendor: const tmpCss = `${tailwindDirectives}\n\n/* Vendor */\n${vendorCss}\n\n/* Custom */\n${src}`;
|
297
|
+
const tmpCss = `${tailwindDirectives}\n\n${src}`;
|
298
|
+
|
299
|
+
fs.writeFileSync(tmpPath, tmpCss, 'utf8');
|
300
|
+
|
301
|
+
// Run Tailwind
|
302
|
+
const res = spawnSync('npx', [
|
303
|
+
'tailwindcss',
|
304
|
+
'-c', 'tailwind.config.mjs',
|
305
|
+
'-i', tmpPath,
|
306
|
+
'-o', outPath
|
307
|
+
], { stdio: 'inherit', cwd: root });
|
308
|
+
|
309
|
+
if (res.status !== 0) {
|
310
|
+
process.exit(res.status);
|
311
|
+
}
|
312
|
+
|
313
|
+
fs.unlinkSync(tmpPath);
|
314
|
+
console.log(`CSS built: ${outPath}`);
|
315
|
+
}
|
316
|
+
|
317
|
+
build();
|
318
|
+
```
|
319
|
+
|
320
|
+
## 14. Create jQuery Injection (if needed)
|
321
|
+
|
322
|
+
```javascript
|
323
|
+
// spec/internal/inject-jquery.js
|
324
|
+
// https://github.com/evanw/esbuild/issues/1681
|
325
|
+
export { default as $ } from 'jquery/dist/jquery.js'
|
326
|
+
export { default as jQuery } from 'jquery/dist/jquery.js'
|
327
|
+
```
|
328
|
+
|
329
|
+
## 15. Create JavaScript Entry Point
|
330
|
+
|
331
|
+
```javascript
|
332
|
+
// spec/internal/app/js/active_admin.js
|
333
|
+
import '@activeadmin/activeadmin';
|
334
|
+
|
335
|
+
// Import your gem's JavaScript module - users will use this exact import
|
336
|
+
// NOTE: In development, this needs to be resolved via esbuild alias to your local gem
|
337
|
+
import 'your_gem_name';
|
338
|
+
```
|
339
|
+
|
340
|
+
For development testing, create an esbuild config:
|
341
|
+
|
342
|
+
```javascript
|
343
|
+
// spec/internal/esbuild.config.js
|
344
|
+
const esbuild = require('esbuild');
|
345
|
+
const path = require('path');
|
346
|
+
|
347
|
+
const config = {
|
348
|
+
entryPoints: ['app/js/active_admin.js'],
|
349
|
+
bundle: true,
|
350
|
+
sourcemap: true,
|
351
|
+
format: 'esm',
|
352
|
+
outdir: 'app/assets/builds',
|
353
|
+
publicPath: '/assets',
|
354
|
+
inject: ['./inject-jquery.js'],
|
355
|
+
alias: {
|
356
|
+
// Map your gem's module name to the actual file for development
|
357
|
+
'your_gem_name': path.resolve(__dirname, '../../app/assets/javascripts/your_gem_main.js')
|
358
|
+
}
|
359
|
+
};
|
360
|
+
|
361
|
+
// Build logic...
|
362
|
+
```
|
363
|
+
|
364
|
+
## 16. Create CSS Source
|
365
|
+
|
366
|
+
```css
|
367
|
+
/* spec/internal/app/assets/stylesheets/active_admin_source.css */
|
368
|
+
@tailwind base;
|
369
|
+
@tailwind components;
|
370
|
+
@tailwind utilities;
|
371
|
+
|
372
|
+
/* Your custom styles here */
|
373
|
+
```
|
374
|
+
|
375
|
+
## 17. Set Up Propshaft Assets
|
376
|
+
|
377
|
+
With Propshaft, assets in `app/assets/builds` are automatically served. No manifest configuration needed.
|
378
|
+
|
379
|
+
```css
|
380
|
+
/* spec/internal/app/assets/stylesheets/active_admin.css */
|
381
|
+
/*
|
382
|
+
* This file can be empty or include custom overrides
|
383
|
+
* The real CSS is in builds/active_admin.css
|
384
|
+
*/
|
385
|
+
```
|
386
|
+
|
387
|
+
## 19. Create Test Models
|
388
|
+
|
389
|
+
```ruby
|
390
|
+
# spec/internal/app/models/post.rb
|
391
|
+
class Post < ActiveRecord::Base
|
392
|
+
def self.ransackable_attributes(_auth_object = nil)
|
393
|
+
%w[title body created_at updated_at]
|
394
|
+
end
|
395
|
+
end
|
396
|
+
```
|
397
|
+
|
398
|
+
## 20. Create Admin Resources
|
399
|
+
|
400
|
+
```ruby
|
401
|
+
# spec/internal/app/admin/posts.rb
|
402
|
+
ActiveAdmin.register Post do
|
403
|
+
permit_params :title, :body
|
404
|
+
|
405
|
+
form do |f|
|
406
|
+
f.semantic_errors
|
407
|
+
f.inputs do
|
408
|
+
f.input :title
|
409
|
+
f.input :body, as: :text
|
410
|
+
# Use your custom input types here
|
411
|
+
end
|
412
|
+
f.actions
|
413
|
+
end
|
414
|
+
end
|
415
|
+
```
|
416
|
+
|
417
|
+
## 21. Build Assets
|
418
|
+
|
419
|
+
```bash
|
420
|
+
cd spec/internal
|
421
|
+
npm install
|
422
|
+
npm run build
|
423
|
+
|
424
|
+
# Verify output
|
425
|
+
ls -lah app/assets/builds/
|
426
|
+
# Should see active_admin.css (100KB+) and active_admin.js
|
427
|
+
```
|
428
|
+
|
429
|
+
## 22. Test the Setup
|
430
|
+
|
431
|
+
```bash
|
432
|
+
# From gem root
|
433
|
+
bundle exec rackup
|
434
|
+
|
435
|
+
# Visit http://localhost:9292/admin
|
436
|
+
# Should see styled ActiveAdmin interface
|
437
|
+
```
|
438
|
+
|
439
|
+
## 23. Set Up RSpec
|
440
|
+
|
441
|
+
```ruby
|
442
|
+
# spec/rails_helper.rb
|
443
|
+
ENV['RAILS_ENV'] ||= 'test'
|
444
|
+
|
445
|
+
require 'combustion'
|
446
|
+
|
447
|
+
Combustion.path = 'spec/internal'
|
448
|
+
Combustion.initialize! :active_record, :action_controller, :action_view do
|
449
|
+
config.load_defaults Rails::VERSION::STRING.to_f
|
450
|
+
end
|
451
|
+
|
452
|
+
require 'rspec/rails'
|
453
|
+
require 'capybara/rails'
|
454
|
+
|
455
|
+
RSpec.configure do |config|
|
456
|
+
config.use_transactional_fixtures = true
|
457
|
+
config.infer_spec_type_from_file_location!
|
458
|
+
config.filter_rails_from_backtrace!
|
459
|
+
end
|
460
|
+
```
|
461
|
+
|
462
|
+
## 24. Create Basic Spec
|
463
|
+
|
464
|
+
```ruby
|
465
|
+
# spec/features/admin_spec.rb
|
466
|
+
require 'rails_helper'
|
467
|
+
|
468
|
+
RSpec.describe 'Admin Interface', type: :feature do
|
469
|
+
it 'loads the admin dashboard' do
|
470
|
+
visit '/admin'
|
471
|
+
expect(page).to have_content('Dashboard')
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'has properly styled interface' do
|
475
|
+
visit '/admin'
|
476
|
+
# Check for Tailwind classes indicating proper styling
|
477
|
+
expect(page).to have_css('.flex')
|
478
|
+
expect(page).to have_css('.grid')
|
479
|
+
end
|
480
|
+
end
|
481
|
+
```
|
482
|
+
|
483
|
+
## 25. Add to .gitignore
|
484
|
+
|
485
|
+
```
|
486
|
+
# .gitignore
|
487
|
+
spec/internal/node_modules/
|
488
|
+
spec/internal/app/assets/builds/
|
489
|
+
spec/internal/tmp/
|
490
|
+
spec/internal/log/
|
491
|
+
spec/internal/db/*.sqlite3
|
492
|
+
spec/internal/package-lock.json
|
493
|
+
```
|
494
|
+
|
495
|
+
## Checklist
|
496
|
+
|
497
|
+
- [ ] Gem structure created with proper dependencies
|
498
|
+
- [ ] Combustion test app generated
|
499
|
+
- [ ] config.ru with correct loading order
|
500
|
+
- [ ] NPM packages installed
|
501
|
+
- [ ] Tailwind configured with safelist
|
502
|
+
- [ ] CSS build script created
|
503
|
+
- [ ] JavaScript entry point set up
|
504
|
+
- [ ] jQuery injection (if needed)
|
505
|
+
- [ ] Asset manifests configured
|
506
|
+
- [ ] Test models and admin resources created
|
507
|
+
- [ ] Assets built successfully (>100KB CSS file)
|
508
|
+
- [ ] Server starts and admin interface is styled
|
509
|
+
- [ ] RSpec tests pass
|
510
|
+
|
511
|
+
## Common Issues
|
512
|
+
|
513
|
+
### Issue: "uninitialized constant ActiveAdmin"
|
514
|
+
**Solution**: Check config.ru loading order - ActiveAdmin must load AFTER Combustion.initialize!
|
515
|
+
|
516
|
+
### Issue: Unstyled admin pages
|
517
|
+
**Solution**: Ensure Tailwind safelist is included and CSS file is >100KB
|
518
|
+
|
519
|
+
### Issue: jQuery not defined
|
520
|
+
**Solution**: Add inject-jquery.js and use with esbuild --inject flag
|
521
|
+
|
522
|
+
### Issue: Vendor CSS not loading
|
523
|
+
**Solution**: Use build_css.js to concatenate vendor CSS before Tailwind processing
|
524
|
+
|
525
|
+
### Issue: Assets not loading / 404 errors
|
526
|
+
**Solution**: Ensure you're using Propshaft, not Sprockets. Check that assets are in `app/assets/builds/`
|
527
|
+
|
528
|
+
## Success Indicators
|
529
|
+
|
530
|
+
✅ Admin interface fully styled with proper layout
|
531
|
+
✅ CSS file size > 100KB
|
532
|
+
✅ No JavaScript console errors
|
533
|
+
✅ Dark mode toggle works
|
534
|
+
✅ Custom features/inputs working
|
535
|
+
✅ Tests passing
|