elaine_crud 0.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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/LICENSE +21 -0
  4. data/README.md +225 -0
  5. data/Rakefile +9 -0
  6. data/TODO.md +496 -0
  7. data/app/controllers/elaine_crud/base_controller.rb +228 -0
  8. data/app/helpers/elaine_crud/base_helper.rb +787 -0
  9. data/app/helpers/elaine_crud/search_helper.rb +132 -0
  10. data/app/javascript/controllers/dropdown_controller.js +18 -0
  11. data/app/views/elaine_crud/base/_edit_row.html.erb +60 -0
  12. data/app/views/elaine_crud/base/_export_button.html.erb +88 -0
  13. data/app/views/elaine_crud/base/_foreign_key_select_refresh.html.erb +52 -0
  14. data/app/views/elaine_crud/base/_form.html.erb +45 -0
  15. data/app/views/elaine_crud/base/_form_fields.html.erb +45 -0
  16. data/app/views/elaine_crud/base/_index_table.html.erb +58 -0
  17. data/app/views/elaine_crud/base/_modal.html.erb +71 -0
  18. data/app/views/elaine_crud/base/_pagination.html.erb +110 -0
  19. data/app/views/elaine_crud/base/_per_page_selector.html.erb +30 -0
  20. data/app/views/elaine_crud/base/_search_bar.html.erb +75 -0
  21. data/app/views/elaine_crud/base/_show_details.html.erb +29 -0
  22. data/app/views/elaine_crud/base/_view_row.html.erb +96 -0
  23. data/app/views/elaine_crud/base/edit.html.erb +51 -0
  24. data/app/views/elaine_crud/base/index.html.erb +74 -0
  25. data/app/views/elaine_crud/base/new.html.erb +12 -0
  26. data/app/views/elaine_crud/base/new_modal.html.erb +37 -0
  27. data/app/views/elaine_crud/base/not_found.html.erb +49 -0
  28. data/app/views/elaine_crud/base/show.html.erb +32 -0
  29. data/docs/ARCHITECTURE.md +410 -0
  30. data/docs/CSS_GRID_LAYOUT.md +126 -0
  31. data/docs/DEMO.md +693 -0
  32. data/docs/DSL_EXAMPLES.md +313 -0
  33. data/docs/FOREIGN_KEY_EXAMPLE.rb +100 -0
  34. data/docs/FOREIGN_KEY_SUPPORT.md +197 -0
  35. data/docs/HAS_MANY_IMPLEMENTATION.md +154 -0
  36. data/docs/LAYOUT_EXAMPLES.md +301 -0
  37. data/docs/TROUBLESHOOTING.md +170 -0
  38. data/elaine_crud.gemspec +46 -0
  39. data/lib/elaine_crud/dsl_methods.rb +348 -0
  40. data/lib/elaine_crud/engine.rb +37 -0
  41. data/lib/elaine_crud/export_handling.rb +164 -0
  42. data/lib/elaine_crud/field_configuration.rb +422 -0
  43. data/lib/elaine_crud/field_configuration_methods.rb +152 -0
  44. data/lib/elaine_crud/layout_calculation.rb +55 -0
  45. data/lib/elaine_crud/parameter_handling.rb +48 -0
  46. data/lib/elaine_crud/record_fetching.rb +150 -0
  47. data/lib/elaine_crud/relationship_handling.rb +220 -0
  48. data/lib/elaine_crud/routing.rb +33 -0
  49. data/lib/elaine_crud/search_and_filtering.rb +285 -0
  50. data/lib/elaine_crud/sorting_concern.rb +65 -0
  51. data/lib/elaine_crud/version.rb +5 -0
  52. data/lib/elaine_crud.rb +25 -0
  53. data/lib/tasks/demo.rake +111 -0
  54. data/lib/tasks/spec.rake +26 -0
  55. metadata +264 -0
@@ -0,0 +1,410 @@
1
+ # ElaineCrud Architecture Documentation
2
+
3
+ ## Overview
4
+
5
+ ElaineCrud is a Ruby gem that provides a Rails Engine for rapidly generating CRUD (Create, Read, Update, Delete) interfaces for ActiveRecord models. The gem follows Rails conventions and provides a minimal, ergonomic DSL for creating database admin interfaces with zero boilerplate.
6
+
7
+ ## Design Goals
8
+
9
+ - **Minimal Configuration**: Developers should only need to specify the model and permitted attributes
10
+ - **Convention over Configuration**: Follow Rails patterns and conventions
11
+ - **Non-Mountable Engine**: Integrate seamlessly with host applications without namespace isolation
12
+ - **Zero External Dependencies**: Only depend on Rails itself
13
+ - **Customizable**: Allow host applications to override views and behavior
14
+ - **Modern UI**: Provide clean, responsive interfaces using TailwindCSS
15
+
16
+ ## Architecture Overview
17
+
18
+ ```
19
+ ┌─────────────────────────────────────────────────────────────────┐
20
+ │ Host Rails App │
21
+ │ ┌───────────────────────────────────────────────────────────┐ │
22
+ │ │ Custom Controller │ │
23
+ │ │ class PeopleController < ElaineCrud::BaseController │ │
24
+ │ │ model Person │ │
25
+ │ │ permit_params :name, :email │ │
26
+ │ │ end │ │
27
+ │ └───────────────────────────────────────────────────────────┘ │
28
+ │ │ │
29
+ │ ▼ │
30
+ │ ┌───────────────────────────────────────────────────────────┐ │
31
+ │ │ Routes │ │
32
+ │ │ resources :people │ │
33
+ │ └───────────────────────────────────────────────────────────┘ │
34
+ └─────────────────────────────────────────────────────────────────┘
35
+
36
+
37
+ ┌─────────────────────────────────────────────────────────────────┐
38
+ │ ElaineCrud Engine │
39
+ │ ┌───────────────────────────────────────────────────────────┐ │
40
+ │ │ BaseController │ │
41
+ │ │ • Model introspection │ │
42
+ │ │ • Standard CRUD actions │ │
43
+ │ │ • Strong parameters │ │
44
+ │ │ • Column detection │ │
45
+ │ └───────────────────────────────────────────────────────────┘ │
46
+ │ ┌───────────────────────────────────────────────────────────┐ │
47
+ │ │ Default Views │ │
48
+ │ │ • Index listing with table │ │
49
+ │ │ • Smart column formatting │ │
50
+ │ │ • Action buttons (Edit, Delete) │ │
51
+ │ │ • TailwindCSS styling │ │
52
+ │ └───────────────────────────────────────────────────────────┘ │
53
+ │ ┌───────────────────────────────────────────────────────────┐ │
54
+ │ │ Helpers │ │
55
+ │ │ • Column value formatting │ │
56
+ │ │ • Boolean/Date display logic │ │
57
+ │ │ • Truncation and styling │ │
58
+ │ └───────────────────────────────────────────────────────────┘ │
59
+ └─────────────────────────────────────────────────────────────────┘
60
+ ```
61
+
62
+ ## File Structure
63
+
64
+ ```
65
+ elaine_crud/
66
+ ├── elaine_crud.gemspec # Gem specification
67
+ ├── Gemfile # Development dependencies
68
+ ├── lib/
69
+ │ ├── elaine_crud.rb # Main gem entry point
70
+ │ └── elaine_crud/
71
+ │ ├── version.rb # Version constant
72
+ │ └── engine.rb # Rails Engine configuration
73
+ ├── app/
74
+ │ ├── controllers/
75
+ │ │ └── elaine_crud/
76
+ │ │ └── base_controller.rb # Core CRUD controller logic
77
+ │ ├── helpers/
78
+ │ │ └── elaine_crud/
79
+ │ │ └── base_helper.rb # View helper methods
80
+ │ └── views/
81
+ │ └── elaine_crud/
82
+ │ └── base/
83
+ │ └── index.html.erb # Default index view template
84
+ └── docs/
85
+ └── ARCHITECTURE.md # This documentation file
86
+ ```
87
+
88
+ ## Core Components
89
+
90
+ ### 1. Engine Configuration (`lib/elaine_crud/engine.rb`)
91
+
92
+ The Rails Engine is configured as **non-mountable** to integrate seamlessly with host applications:
93
+
94
+ ```ruby
95
+ module ElaineCrud
96
+ class Engine < ::Rails::Engine
97
+ # Non-mountable engine - do not call isolate_namespace
98
+
99
+ # Make app directories available to autoloader
100
+ config.autoload_paths << File.expand_path('../../app/controllers', __dir__)
101
+ config.autoload_paths << File.expand_path('../../app/helpers', __dir__)
102
+
103
+ # Add views to Rails view path
104
+ initializer 'elaine_crud.append_view_paths' do |app|
105
+ ActiveSupport.on_load :action_controller do
106
+ append_view_path File.expand_path('../../app/views', __dir__)
107
+ end
108
+ end
109
+
110
+ # Include helpers globally
111
+ initializer 'elaine_crud.include_helpers' do
112
+ ActiveSupport.on_load :action_controller do
113
+ include ElaineCrud::BaseHelper
114
+ end
115
+ end
116
+ end
117
+ end
118
+ ```
119
+
120
+ **Key Design Decisions:**
121
+ - No `isolate_namespace` call ensures classes are available in global namespace
122
+ - Autoload paths ensure proper class loading
123
+ - View paths are appended, allowing host app views to override engine views
124
+ - Helpers are included globally for maximum compatibility
125
+
126
+ ### 2. BaseController (`app/controllers/elaine_crud/base_controller.rb`)
127
+
128
+ The heart of the gem, providing a DSL and CRUD functionality:
129
+
130
+ ```ruby
131
+ class ElaineCrud::BaseController < ActionController::Base
132
+ # No layout specified - host app controllers set their own layout
133
+
134
+ # Class-level configuration
135
+ class_attribute :crud_model, :permitted_attributes, :column_configurations
136
+
137
+ # DSL Methods
138
+ class << self
139
+ def model(model_class)
140
+ self.crud_model = model_class
141
+ end
142
+
143
+ def permit_params(*attrs)
144
+ self.permitted_attributes = attrs
145
+ end
146
+
147
+ def columns(config = {})
148
+ self.column_configurations = config
149
+ end
150
+ end
151
+
152
+ # Standard CRUD actions: index, show, new, create, edit, update, destroy
153
+ end
154
+ ```
155
+
156
+ **Features:**
157
+ - **Layout Agnostic**: No layout specified, host app controls HTML structure
158
+ - **Model Introspection**: Automatically detects columns and relationships
159
+ - **Strong Parameters**: Uses configured permitted attributes
160
+ - **Column Detection**: Filters out ID and timestamp columns by default
161
+ - **Extensible**: Subclasses can override any method for custom behavior
162
+
163
+ ### 3. View Helpers (`app/helpers/elaine_crud/base_helper.rb`)
164
+
165
+ Smart formatting for different data types:
166
+
167
+ ```ruby
168
+ def display_column_value(record, column)
169
+ value = record.public_send(column)
170
+
171
+ case value
172
+ when nil
173
+ content_tag(:span, '—', class: 'text-gray-400')
174
+ when true
175
+ content_tag(:span, '✓', class: 'text-green-600 font-bold')
176
+ when false
177
+ content_tag(:span, '✗', class: 'text-red-600 font-bold')
178
+ when Date, DateTime, Time
179
+ value.strftime('%m/%d/%Y')
180
+ else
181
+ truncate(value.to_s, length: 50)
182
+ end
183
+ end
184
+ ```
185
+
186
+ **Features:**
187
+ - **Type-Aware Formatting**: Different display logic for booleans, dates, nil values
188
+ - **Consistent Styling**: Uses TailwindCSS classes for visual consistency
189
+ - **Truncation**: Prevents long text from breaking table layout
190
+
191
+ ### 4. Default Views (`app/views/elaine_crud/base/index.html.erb`)
192
+
193
+ Modern, responsive table interface:
194
+
195
+ ```erb
196
+ <div class="container mx-auto px-4 py-8">
197
+ <div class="flex justify-between items-center mb-6">
198
+ <h1 class="text-3xl font-bold text-gray-900"><%= @model_name.pluralize %></h1>
199
+ <%= link_to "New #{@model_name}", url_for(action: :new),
200
+ class: "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" %>
201
+ </div>
202
+
203
+ <% if @records.any? %>
204
+ <!-- Responsive table with TailwindCSS styling -->
205
+ <% else %>
206
+ <!-- Empty state with call-to-action -->
207
+ <% end %>
208
+ </div>
209
+ ```
210
+
211
+ **Features:**
212
+ - **Responsive Design**: Works on mobile and desktop
213
+ - **TailwindCSS Styling**: Modern, clean appearance
214
+ - **Empty States**: Helpful messaging when no records exist
215
+ - **Action Buttons**: Edit and Delete functionality
216
+
217
+ ## Usage Pattern
218
+
219
+ ### 1. Host Application Setup
220
+
221
+ Add to `Gemfile`:
222
+ ```ruby
223
+ gem "elaine_crud", path: "../elaine_crud"
224
+ ```
225
+
226
+ ### 2. Controller Creation
227
+
228
+ Create a minimal controller:
229
+ ```ruby
230
+ class PeopleController < ElaineCrud::BaseController
231
+ layout 'application' # Host app specifies layout (header/footer/styling)
232
+
233
+ model Person
234
+ permit_params :name, :email, :phone, :active
235
+ end
236
+ ```
237
+
238
+ ### 3. Route Configuration
239
+
240
+ Add standard Rails routes:
241
+ ```ruby
242
+ resources :people
243
+ ```
244
+
245
+ ### 4. Instant CRUD Interface
246
+
247
+ Navigate to `/people` for a fully functional CRUD interface with:
248
+ - Table listing of all records
249
+ - Automatic column detection and formatting
250
+ - Edit and delete functionality
251
+ - Clean, modern styling
252
+
253
+ ## TailwindCSS Integration
254
+
255
+ ### The Challenge
256
+
257
+ ElaineCrud provides views with TailwindCSS classes, but the gem itself doesn't bundle CSS. The host application needs to include these classes in its TailwindCSS build process.
258
+
259
+ ### Solution Options
260
+
261
+ #### 1. Update Host App TailwindCSS Config (Recommended)
262
+
263
+ Add the gem's files to `tailwind.config.js`:
264
+
265
+ ```javascript
266
+ module.exports = {
267
+ content: [
268
+ './app/views/**/*.html.erb',
269
+ './app/helpers/**/*.rb',
270
+ './app/assets/stylesheets/**/*.css',
271
+ './app/javascript/**/*.js',
272
+ // Include elaine_crud gem views for TailwindCSS class detection
273
+ '../elaine_crud/app/views/**/*.html.erb',
274
+ '../elaine_crud/app/helpers/**/*.rb'
275
+ ],
276
+ // ... rest of config
277
+ }
278
+ ```
279
+
280
+ #### 2. Safelist Critical Classes
281
+
282
+ Alternatively, add commonly used classes to the safelist:
283
+
284
+ ```javascript
285
+ module.exports = {
286
+ safelist: [
287
+ 'container', 'mx-auto', 'px-4', 'py-8',
288
+ 'bg-blue-500', 'hover:bg-blue-700', 'text-white',
289
+ 'bg-white', 'shadow-md', 'rounded-lg',
290
+ 'table', 'min-w-full', 'divide-y', 'divide-gray-200',
291
+ // ... other ElaineCrud classes
292
+ ]
293
+ }
294
+ ```
295
+
296
+ #### 3. Gem-Level Configuration (Future Enhancement)
297
+
298
+ Future versions could provide a TailwindCSS plugin or configuration helper:
299
+
300
+ ```ruby
301
+ # Potential future API
302
+ ElaineCrud.configure_tailwind(Rails.root.join('tailwind.config.js'))
303
+ ```
304
+
305
+ ### Current Status
306
+
307
+ The implemented solution updates the host application's TailwindCSS configuration to scan the gem's view files. This ensures all TailwindCSS classes used by ElaineCrud are included in the final CSS bundle.
308
+
309
+ ## Current Implementation Status
310
+
311
+ ### ✅ Completed Features
312
+
313
+ 1. **Basic Gem Structure**
314
+ - Proper gemspec with Rails dependency
315
+ - Non-mountable engine configuration
316
+ - Autoloading and view path setup
317
+
318
+ 2. **Core Controller**
319
+ - DSL for model and parameter configuration
320
+ - Standard CRUD action implementations
321
+ - Strong parameter handling
322
+ - Automatic column detection
323
+
324
+ 3. **View System**
325
+ - Responsive index view with TailwindCSS
326
+ - Smart column value formatting
327
+ - Action buttons for edit/delete operations
328
+ - Empty state handling
329
+
330
+ 4. **Helper System**
331
+ - Type-aware value formatting
332
+ - Boolean, date, and nil value handling
333
+ - Text truncation for long content
334
+
335
+ 5. **Integration Testing**
336
+ - Successfully integrated with kotirails app
337
+ - Working daycare_browser controller for DaycareEntry model
338
+ - Verified HTTP 200 responses and proper HTML rendering
339
+
340
+ ### 🚧 Future Enhancements (Not Yet Implemented)
341
+
342
+ 1. **Sorting**: Clickable column headers for sorting
343
+ 2. **Pagination**: Built-in pagination for large datasets
344
+ 3. **Search/Filtering**: Basic search functionality
345
+ 4. **Form Views**: New and edit form templates
346
+ 5. **Column Configuration**: Advanced column display customization
347
+ 6. **Validation Handling**: Proper error display for form submissions
348
+
349
+ ## Design Philosophy
350
+
351
+ ### Separation of Concerns
352
+
353
+ The gem follows a clean separation between content and presentation:
354
+ - **Engine provides**: CRUD logic, data formatting, content templates
355
+ - **Host app provides**: Layout, styling, HTML structure, navigation
356
+ - **Host app controls**: Headers, footers, CSS frameworks, page structure
357
+
358
+ ### Convention over Configuration
359
+
360
+ The gem follows Rails conventions wherever possible:
361
+ - Standard CRUD action names
362
+ - RESTful routing patterns
363
+ - ActiveRecord assumptions
364
+ - Rails view helper patterns
365
+
366
+ ### Minimal API Surface
367
+
368
+ The DSL is intentionally small:
369
+ - `model` - specify the ActiveRecord class
370
+ - `permit_params` - define strong parameters
371
+ - `layout` - host app specifies which layout to use
372
+ - `columns` - (future) customize column display
373
+
374
+ ### Extensibility
375
+
376
+ Host applications can override any behavior:
377
+ - Views override engine views by Rails precedence
378
+ - Controller methods can be overridden in subclasses
379
+ - Helpers can be customized or extended
380
+ - Layout and styling completely controlled by host app
381
+
382
+ ### Zero Configuration Default
383
+
384
+ The gem works with zero configuration for basic use cases:
385
+ - Automatic column detection
386
+ - Sensible defaults for display formatting
387
+ - Standard CRUD operations out of the box
388
+
389
+ ## Example: DaycareEntry Integration
390
+
391
+ The implemented example shows the gem in action:
392
+
393
+ ```ruby
394
+ # Controller (10 lines)
395
+ class DaycareBrowserController < ElaineCrud::BaseController
396
+ model DaycareEntry
397
+ permit_params :date, :pupu_sleep, :pupu_eat, :pentu_sleep, :pentu_eat
398
+ end
399
+
400
+ # Route (1 line)
401
+ resources :daycare_browser, except: [:show]
402
+ ```
403
+
404
+ This generates a complete CRUD interface for the DaycareEntry model with:
405
+ - Table showing date, sleep, and eating data
406
+ - Proper formatting for different field types
407
+ - Edit and delete buttons
408
+ - Clean, professional styling
409
+
410
+ The implementation demonstrates the gem's core value proposition: **maximum functionality with minimal code**.
@@ -0,0 +1,126 @@
1
+ # CSS Grid Layout
2
+
3
+ ElaineCrud uses CSS Grid-based layouts for all CRUD views, providing flexible and responsive data display with support for field spanning similar to HTML table `colspan` and `rowspan` attributes.
4
+
5
+ ## Overview
6
+
7
+ The system automatically:
8
+ - Calculates optimal grid columns based on field span configurations
9
+ - Encapsulates each ActiveRecord item in a `<div class="record">` with unique ID
10
+ - Supports both column and row spanning for flexible layouts
11
+ - Maintains inline editing capabilities within the grid structure
12
+
13
+ ## Grid Span Configuration
14
+
15
+ Fields can span multiple columns and rows using the new grid configuration options:
16
+
17
+ ### Column Spanning (similar to `colspan`)
18
+
19
+ ```ruby
20
+ field :description do |f|
21
+ f.title "Description"
22
+ f.grid_column_span 2 # This field will span 2 columns
23
+ end
24
+
25
+ # Or using hash syntax:
26
+ field :description,
27
+ title: "Description",
28
+ grid_column_span: 3 # This field will span 3 columns
29
+ ```
30
+
31
+ ### Row Spanning (similar to `rowspan`)
32
+
33
+ ```ruby
34
+ field :large_content do |f|
35
+ f.title "Large Content"
36
+ f.grid_row_span 2 # This field will span 2 rows
37
+ end
38
+
39
+ # Or using hash syntax:
40
+ field :large_content,
41
+ title: "Large Content",
42
+ grid_row_span: 2
43
+ ```
44
+
45
+ ### Combined Column and Row Spanning
46
+
47
+ ```ruby
48
+ field :big_field do |f|
49
+ f.title "Big Field"
50
+ f.grid_column_span 2
51
+ f.grid_row_span 2 # This field will span 2x2 grid cells
52
+ end
53
+ ```
54
+
55
+ ## Example Usage
56
+
57
+ ```ruby
58
+ class DaycareBrowserController < ElaineCrud::BaseController
59
+ model DaycareEntry
60
+
61
+ field :date, title: "Entry Date"
62
+
63
+ field :pupu_sleep,
64
+ title: "Pupu's Sleep",
65
+ options: DaycareEntry::SLEEP_OPTIONS
66
+
67
+ field :pupu_eat,
68
+ title: "Pupu's Eating",
69
+ options: DaycareEntry::EAT_OPTIONS
70
+
71
+ # Comments span 2 columns for more space
72
+ field :pupu_comments do |f|
73
+ f.title "Pupu Comments"
74
+ f.grid_column_span 2
75
+ end
76
+
77
+ field :pentu_sleep,
78
+ title: "Pentu's Sleep",
79
+ options: DaycareEntry::SLEEP_OPTIONS
80
+
81
+ field :pentu_eat,
82
+ title: "Pentu's Eating",
83
+ options: DaycareEntry::EAT_OPTIONS
84
+
85
+ # Comments span 2 columns for more space
86
+ field :pentu_comments do |f|
87
+ f.title "Pentu Comments"
88
+ f.grid_column_span 2
89
+ end
90
+ end
91
+ ```
92
+
93
+ ## How It Works
94
+
95
+ 1. **Grid Container**: Each record is wrapped in a `<div class="record">` with a unique ID based on the ActiveRecord ID (`record_#{record.id}`)
96
+
97
+ 2. **Dynamic Columns**: The grid automatically calculates the total number of columns needed based on field spans
98
+
99
+ 3. **Responsive**: Uses CSS Grid with `minmax(0, 1fr)` for responsive behavior
100
+
101
+ 4. **Inline Editing**: The grid layout supports inline editing just like the table layout
102
+
103
+ ## Template Files
104
+
105
+ - `elaine_crud/base/index.html.erb` - Main grid-based index view
106
+ - `elaine_crud/base/_edit_row.html.erb` - Grid-based inline edit partial
107
+
108
+ ## CSS Classes
109
+
110
+ The system automatically applies appropriate Tailwind CSS classes:
111
+ - `col-span-1` to `col-span-6` for column spanning
112
+ - `row-span-1` to `row-span-6` for row spanning
113
+
114
+ These classes are included in the Tailwind safelist to ensure they're available at runtime.
115
+
116
+ ## Record Encapsulation
117
+
118
+ Each ActiveRecord item is encapsulated in a `<div class="record">` with a unique ID based on the ActiveRecord ID:
119
+
120
+ ```html
121
+ <div class="record" id="record_123">
122
+ <!-- Field grid layout here -->
123
+ </div>
124
+ ```
125
+
126
+ This ensures proper isolation and targeting for JavaScript interactions or styling.