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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/LICENSE +21 -0
- data/README.md +225 -0
- data/Rakefile +9 -0
- data/TODO.md +496 -0
- data/app/controllers/elaine_crud/base_controller.rb +228 -0
- data/app/helpers/elaine_crud/base_helper.rb +787 -0
- data/app/helpers/elaine_crud/search_helper.rb +132 -0
- data/app/javascript/controllers/dropdown_controller.js +18 -0
- data/app/views/elaine_crud/base/_edit_row.html.erb +60 -0
- data/app/views/elaine_crud/base/_export_button.html.erb +88 -0
- data/app/views/elaine_crud/base/_foreign_key_select_refresh.html.erb +52 -0
- data/app/views/elaine_crud/base/_form.html.erb +45 -0
- data/app/views/elaine_crud/base/_form_fields.html.erb +45 -0
- data/app/views/elaine_crud/base/_index_table.html.erb +58 -0
- data/app/views/elaine_crud/base/_modal.html.erb +71 -0
- data/app/views/elaine_crud/base/_pagination.html.erb +110 -0
- data/app/views/elaine_crud/base/_per_page_selector.html.erb +30 -0
- data/app/views/elaine_crud/base/_search_bar.html.erb +75 -0
- data/app/views/elaine_crud/base/_show_details.html.erb +29 -0
- data/app/views/elaine_crud/base/_view_row.html.erb +96 -0
- data/app/views/elaine_crud/base/edit.html.erb +51 -0
- data/app/views/elaine_crud/base/index.html.erb +74 -0
- data/app/views/elaine_crud/base/new.html.erb +12 -0
- data/app/views/elaine_crud/base/new_modal.html.erb +37 -0
- data/app/views/elaine_crud/base/not_found.html.erb +49 -0
- data/app/views/elaine_crud/base/show.html.erb +32 -0
- data/docs/ARCHITECTURE.md +410 -0
- data/docs/CSS_GRID_LAYOUT.md +126 -0
- data/docs/DEMO.md +693 -0
- data/docs/DSL_EXAMPLES.md +313 -0
- data/docs/FOREIGN_KEY_EXAMPLE.rb +100 -0
- data/docs/FOREIGN_KEY_SUPPORT.md +197 -0
- data/docs/HAS_MANY_IMPLEMENTATION.md +154 -0
- data/docs/LAYOUT_EXAMPLES.md +301 -0
- data/docs/TROUBLESHOOTING.md +170 -0
- data/elaine_crud.gemspec +46 -0
- data/lib/elaine_crud/dsl_methods.rb +348 -0
- data/lib/elaine_crud/engine.rb +37 -0
- data/lib/elaine_crud/export_handling.rb +164 -0
- data/lib/elaine_crud/field_configuration.rb +422 -0
- data/lib/elaine_crud/field_configuration_methods.rb +152 -0
- data/lib/elaine_crud/layout_calculation.rb +55 -0
- data/lib/elaine_crud/parameter_handling.rb +48 -0
- data/lib/elaine_crud/record_fetching.rb +150 -0
- data/lib/elaine_crud/relationship_handling.rb +220 -0
- data/lib/elaine_crud/routing.rb +33 -0
- data/lib/elaine_crud/search_and_filtering.rb +285 -0
- data/lib/elaine_crud/sorting_concern.rb +65 -0
- data/lib/elaine_crud/version.rb +5 -0
- data/lib/elaine_crud.rb +25 -0
- data/lib/tasks/demo.rake +111 -0
- data/lib/tasks/spec.rake +26 -0
- metadata +264 -0
data/docs/DEMO.md
ADDED
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
# ElaineCrud Demo Application
|
|
2
|
+
|
|
3
|
+
A fully functional demo application showcasing all features of the ElaineCrud gem through a **Library Management System**.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### First Time Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# From the elaine_crud root directory
|
|
11
|
+
rake demo:setup
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This will:
|
|
15
|
+
1. Create the SQLite database
|
|
16
|
+
2. Run all migrations
|
|
17
|
+
3. Seed the database with sample data
|
|
18
|
+
|
|
19
|
+
### Run the Demo
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
rake demo:server
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then open your browser to: **http://localhost:3000**
|
|
26
|
+
|
|
27
|
+
## Demo Application Overview
|
|
28
|
+
|
|
29
|
+
The demo models a complete library management system with realistic relationships and data.
|
|
30
|
+
|
|
31
|
+
### Domain Model
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Library (3 records)
|
|
35
|
+
├── has_many :books (8 total)
|
|
36
|
+
├── has_many :members (6 total)
|
|
37
|
+
└── has_many :librarians (5 total)
|
|
38
|
+
|
|
39
|
+
Author (5 records)
|
|
40
|
+
└── has_many :books
|
|
41
|
+
|
|
42
|
+
Book (8 records)
|
|
43
|
+
├── belongs_to :author
|
|
44
|
+
├── belongs_to :library
|
|
45
|
+
└── has_many :loans
|
|
46
|
+
|
|
47
|
+
Member (6 records)
|
|
48
|
+
├── belongs_to :library
|
|
49
|
+
└── has_many :loans
|
|
50
|
+
|
|
51
|
+
Loan (4 records)
|
|
52
|
+
├── belongs_to :book
|
|
53
|
+
└── belongs_to :member
|
|
54
|
+
|
|
55
|
+
Librarian (5 records)
|
|
56
|
+
└── belongs_to :library
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Sample Data Included
|
|
60
|
+
|
|
61
|
+
- **3 Libraries**: Central City Library (NY), Riverside Library (OR), Oakwood Library (TX)
|
|
62
|
+
- **5 Authors**: Jane Austen, George Orwell, Toni Morrison, Haruki Murakami, Chimamanda Ngozi Adichie
|
|
63
|
+
- **8 Books**: Classic and contemporary literature with ISBNs, prices, and descriptions
|
|
64
|
+
- **6 Members**: Various membership types (Standard, Premium, Student, Senior)
|
|
65
|
+
- **4 Loans**: Different statuses (active, returned, overdue, pending)
|
|
66
|
+
- **5 Librarians**: Different roles (Manager, Assistant, Clerk, Archivist)
|
|
67
|
+
|
|
68
|
+
## Features Demonstrated
|
|
69
|
+
|
|
70
|
+
### 1. **Basic CRUD** (All Resources)
|
|
71
|
+
- ✅ Create, Read, Update, Delete operations
|
|
72
|
+
- ✅ Zero custom view code required
|
|
73
|
+
- ✅ Works out of the box
|
|
74
|
+
|
|
75
|
+
**Example**: Navigate to `/libraries` to see a full CRUD interface with just:
|
|
76
|
+
```ruby
|
|
77
|
+
class LibrariesController < ElaineCrud::BaseController
|
|
78
|
+
layout 'application'
|
|
79
|
+
model Library
|
|
80
|
+
permit_params :name, :city, :state, :phone, :email, :established_date
|
|
81
|
+
end
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### 2. **Foreign Key Relationships** (Books, Members, Loans, Librarians)
|
|
87
|
+
|
|
88
|
+
**Auto-detected and configured:**
|
|
89
|
+
- `Book` → `Author` and `Library`
|
|
90
|
+
- `Member` → `Library`
|
|
91
|
+
- `Loan` → `Book` and `Member`
|
|
92
|
+
- `Librarian` → `Library`
|
|
93
|
+
|
|
94
|
+
**What you get:**
|
|
95
|
+
- ✅ Dropdown selects in forms (automatically populated)
|
|
96
|
+
- ✅ Display names instead of IDs in index views
|
|
97
|
+
- ✅ N+1 query prevention (automatic `includes`)
|
|
98
|
+
|
|
99
|
+
**Try it**:
|
|
100
|
+
1. Go to `/books/new`
|
|
101
|
+
2. See Author and Library dropdowns automatically populated
|
|
102
|
+
3. Notice the form shows author names, not IDs
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### 3. **Has-Many Relationships** (Libraries, Authors)
|
|
107
|
+
|
|
108
|
+
**Auto-detected:**
|
|
109
|
+
- Library shows counts of books, members, librarians
|
|
110
|
+
- Author shows count of books
|
|
111
|
+
|
|
112
|
+
**What you get:**
|
|
113
|
+
- ✅ Clickable counts: "5 books" links to filtered view
|
|
114
|
+
- ✅ Preview of related items
|
|
115
|
+
- ✅ Automatic eager loading
|
|
116
|
+
|
|
117
|
+
**Try it**:
|
|
118
|
+
1. Go to `/libraries`
|
|
119
|
+
2. Click on the book count for any library
|
|
120
|
+
3. See filtered view: `/books?library_id=1`
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### 4. **Custom Field Display**
|
|
125
|
+
|
|
126
|
+
#### Currency Fields (Books, Librarians)
|
|
127
|
+
```ruby
|
|
128
|
+
field :price do |f|
|
|
129
|
+
f.display_as { |value| number_to_currency(value) if value.present? }
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
**See it**: Book price shows as `$15.99` instead of `15.99`
|
|
133
|
+
|
|
134
|
+
#### Boolean Fields (Books, Authors, Members)
|
|
135
|
+
```ruby
|
|
136
|
+
field :available do |f|
|
|
137
|
+
f.display_as { |value|
|
|
138
|
+
if value
|
|
139
|
+
content_tag(:span, '✓ Available', class: 'bg-green-100 text-green-800 ...')
|
|
140
|
+
else
|
|
141
|
+
content_tag(:span, '✗ Checked Out', class: 'bg-red-100 text-red-800 ...')
|
|
142
|
+
end
|
|
143
|
+
}
|
|
144
|
+
end
|
|
145
|
+
```
|
|
146
|
+
**See it**: Book availability shows as colored badges, not true/false
|
|
147
|
+
|
|
148
|
+
#### Date Formatting (Multiple Resources)
|
|
149
|
+
```ruby
|
|
150
|
+
field :established_date do |f|
|
|
151
|
+
f.display_as { |value| value&.strftime("%B %Y") }
|
|
152
|
+
end
|
|
153
|
+
```
|
|
154
|
+
**See it**: Dates show as "June 1895" instead of "1895-06-15"
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 5. **Status Badges** (Loans)
|
|
159
|
+
|
|
160
|
+
Color-coded status indicators:
|
|
161
|
+
```ruby
|
|
162
|
+
field :status do |f|
|
|
163
|
+
f.display_as lambda { |value, record|
|
|
164
|
+
colors = {
|
|
165
|
+
'pending' => 'gray',
|
|
166
|
+
'active' => 'blue',
|
|
167
|
+
'returned' => 'green',
|
|
168
|
+
'overdue' => 'red'
|
|
169
|
+
}
|
|
170
|
+
color = colors[value] || 'gray'
|
|
171
|
+
content_tag(:span, value.titleize,
|
|
172
|
+
class: "px-2.5 py-0.5 rounded-full bg-#{color}-100 text-#{color}-800")
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Try it**: Go to `/loans` to see color-coded loan statuses
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### 6. **Dropdown Options** (Members, Loans, Librarians)
|
|
182
|
+
|
|
183
|
+
Predefined dropdown values:
|
|
184
|
+
```ruby
|
|
185
|
+
field :membership_type do |f|
|
|
186
|
+
f.options ["Standard", "Premium", "Student", "Senior"]
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Try it**:
|
|
191
|
+
1. Go to `/members/new`
|
|
192
|
+
2. See membership type dropdown with predefined options
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### 7. **Sorting** (All Resources)
|
|
197
|
+
|
|
198
|
+
- ✅ Click any column header to sort
|
|
199
|
+
- ✅ Click again to reverse direction
|
|
200
|
+
- ✅ Visual indicators (↑ ↓) for current sort
|
|
201
|
+
- ✅ Configurable default sort
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
default_sort column: :name, direction: :asc
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Try it**: Click on any column header in any index view
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### 8. **Inline Editing with Turbo** (All Resources)
|
|
212
|
+
|
|
213
|
+
- ✅ Click "Edit" to edit row inline
|
|
214
|
+
- ✅ No page reload
|
|
215
|
+
- ✅ Validation errors shown inline
|
|
216
|
+
- ✅ Cancel to revert changes
|
|
217
|
+
|
|
218
|
+
**Try it**:
|
|
219
|
+
1. Go to any index page (e.g., `/authors`)
|
|
220
|
+
2. Click "Edit" on any row
|
|
221
|
+
3. Make changes and save or cancel
|
|
222
|
+
4. Notice no page reload!
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### 9. **Parent-Child Filtering** (Books by Library, Loans by Member)
|
|
227
|
+
|
|
228
|
+
URL-based filtering for has_many relationships:
|
|
229
|
+
- `/books?library_id=1` - Shows only books from Library #1
|
|
230
|
+
- `/loans?member_id=2` - Shows only loans for Member #2
|
|
231
|
+
|
|
232
|
+
**What you get:**
|
|
233
|
+
- ✅ Breadcrumb showing parent context
|
|
234
|
+
- ✅ Pre-populated foreign key when creating
|
|
235
|
+
- ✅ "Back to parent" links
|
|
236
|
+
|
|
237
|
+
**Try it**:
|
|
238
|
+
1. Go to `/libraries`
|
|
239
|
+
2. Click on the book count (e.g., "3 books")
|
|
240
|
+
3. See filtered book list with library context
|
|
241
|
+
4. Click "New Book" - library field is pre-selected!
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### 10. **Email Links** (Libraries, Members, Librarians)
|
|
246
|
+
|
|
247
|
+
Auto-formatted mailto links:
|
|
248
|
+
```ruby
|
|
249
|
+
field :email do |f|
|
|
250
|
+
f.display_as { |value| mail_to(value) if value.present? }
|
|
251
|
+
end
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Try it**: Click any email address in the index view
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### 11. **Visibility Control** (Loans)
|
|
259
|
+
|
|
260
|
+
Override default column visibility:
|
|
261
|
+
```ruby
|
|
262
|
+
field :returned_at do |f|
|
|
263
|
+
f.visible true # Override default hiding of _at fields
|
|
264
|
+
end
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Default behavior**: Columns ending with `_at` are hidden unless explicitly shown
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Navigation Guide
|
|
272
|
+
|
|
273
|
+
### Main Resources (Top Navigation)
|
|
274
|
+
|
|
275
|
+
1. **Libraries** (`/libraries`)
|
|
276
|
+
- Demonstrates: Basic CRUD, has_many relationships, email links, date formatting
|
|
277
|
+
- Try: Click book/member counts to see filtered views
|
|
278
|
+
|
|
279
|
+
2. **Authors** (`/authors`)
|
|
280
|
+
- Demonstrates: Boolean display, has_many books, biography text field
|
|
281
|
+
- Try: Edit an author inline, toggle active status
|
|
282
|
+
|
|
283
|
+
3. **Books** (`/books`)
|
|
284
|
+
- Demonstrates: Foreign keys (author, library), currency, availability badges
|
|
285
|
+
- Try: Create a new book, see dropdown options
|
|
286
|
+
|
|
287
|
+
4. **Members** (`/members`)
|
|
288
|
+
- Demonstrates: Dropdown options, date formatting, email links
|
|
289
|
+
- Try: Change membership type via dropdown
|
|
290
|
+
|
|
291
|
+
5. **Loans** (`/loans`)
|
|
292
|
+
- Demonstrates: Status badges, date highlighting, parent filtering
|
|
293
|
+
- Try: Filter by member_id, observe overdue highlighting
|
|
294
|
+
|
|
295
|
+
6. **Librarians** (`/librarians`)
|
|
296
|
+
- Demonstrates: Role dropdown, salary currency, hire date formatting
|
|
297
|
+
- Try: Sort by salary, edit role inline
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Available Rake Tasks
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Display all demo information
|
|
305
|
+
rake demo:info
|
|
306
|
+
|
|
307
|
+
# Initial database setup
|
|
308
|
+
rake demo:setup
|
|
309
|
+
|
|
310
|
+
# Reset database with fresh data
|
|
311
|
+
rake demo:reset
|
|
312
|
+
|
|
313
|
+
# Start the demo server
|
|
314
|
+
rake demo:server
|
|
315
|
+
|
|
316
|
+
# Open Rails console
|
|
317
|
+
rake demo:console
|
|
318
|
+
|
|
319
|
+
# Open database console
|
|
320
|
+
rake demo:dbconsole
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Code Examples
|
|
326
|
+
|
|
327
|
+
### Minimal Controller (Libraries)
|
|
328
|
+
```ruby
|
|
329
|
+
class LibrariesController < ElaineCrud::BaseController
|
|
330
|
+
layout 'application'
|
|
331
|
+
model Library
|
|
332
|
+
permit_params :name, :city, :state, :phone, :email, :established_date
|
|
333
|
+
|
|
334
|
+
default_sort column: :name, direction: :asc
|
|
335
|
+
|
|
336
|
+
field :email do |f|
|
|
337
|
+
f.display_as { |value| mail_to(value) if value.present? }
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
```
|
|
341
|
+
**Result**: Full CRUD interface with 10 lines of code!
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
### Advanced Controller (Books)
|
|
346
|
+
```ruby
|
|
347
|
+
class BooksController < ElaineCrud::BaseController
|
|
348
|
+
layout 'application'
|
|
349
|
+
model Book
|
|
350
|
+
permit_params :title, :isbn, :publication_year, :pages, :description, :available, :price
|
|
351
|
+
|
|
352
|
+
default_sort column: :title, direction: :asc
|
|
353
|
+
|
|
354
|
+
# Currency formatting
|
|
355
|
+
field :price do |f|
|
|
356
|
+
f.title "Price"
|
|
357
|
+
f.display_as { |value| number_to_currency(value) if value.present? }
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Boolean with badge
|
|
361
|
+
field :available do |f|
|
|
362
|
+
f.title "Availability"
|
|
363
|
+
f.display_as { |value|
|
|
364
|
+
if value
|
|
365
|
+
content_tag(:span, '✓ Available',
|
|
366
|
+
class: 'inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-green-100 text-green-800')
|
|
367
|
+
else
|
|
368
|
+
content_tag(:span, '✗ Checked Out',
|
|
369
|
+
class: 'inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-red-100 text-red-800')
|
|
370
|
+
end
|
|
371
|
+
}
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Foreign keys auto-configured: author_id, library_id
|
|
375
|
+
# Has-many loans auto-shown with count
|
|
376
|
+
end
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
### Status Badge Controller (Loans)
|
|
382
|
+
```ruby
|
|
383
|
+
class LoansController < ElaineCrud::BaseController
|
|
384
|
+
layout 'application'
|
|
385
|
+
model Loan
|
|
386
|
+
permit_params :due_date, :returned_at, :status
|
|
387
|
+
|
|
388
|
+
default_sort column: :due_date, direction: :desc
|
|
389
|
+
|
|
390
|
+
# Colored status badges
|
|
391
|
+
field :status do |f|
|
|
392
|
+
f.title "Status"
|
|
393
|
+
f.display_as lambda { |value, record|
|
|
394
|
+
colors = {
|
|
395
|
+
'pending' => 'gray',
|
|
396
|
+
'active' => 'blue',
|
|
397
|
+
'returned' => 'green',
|
|
398
|
+
'overdue' => 'red'
|
|
399
|
+
}
|
|
400
|
+
color = colors[value] || 'gray'
|
|
401
|
+
content_tag(:span, value.titleize,
|
|
402
|
+
class: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-#{color}-100 text-#{color}-800")
|
|
403
|
+
}
|
|
404
|
+
f.options ["pending", "active", "returned", "overdue"]
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# Conditional styling for overdue dates
|
|
408
|
+
field :due_date do |f|
|
|
409
|
+
f.title "Due Date"
|
|
410
|
+
f.display_as { |value, record|
|
|
411
|
+
formatted = value&.strftime("%m/%d/%Y")
|
|
412
|
+
if record.status == 'overdue'
|
|
413
|
+
content_tag(:span, formatted, class: 'text-red-600 font-semibold')
|
|
414
|
+
else
|
|
415
|
+
formatted
|
|
416
|
+
end
|
|
417
|
+
}
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
# Show timestamp with time_ago
|
|
421
|
+
field :returned_at do |f|
|
|
422
|
+
f.title "Returned"
|
|
423
|
+
f.visible true # Override default hiding
|
|
424
|
+
f.display_as { |value| value ? time_ago_in_words(value) + " ago" : "—" }
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Architecture
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
test/dummy_app/
|
|
435
|
+
├── app/
|
|
436
|
+
│ ├── controllers/
|
|
437
|
+
│ │ ├── application_controller.rb
|
|
438
|
+
│ │ ├── libraries_controller.rb # Basic CRUD + has_many
|
|
439
|
+
│ │ ├── authors_controller.rb # Boolean fields
|
|
440
|
+
│ │ ├── books_controller.rb # Foreign keys + currency
|
|
441
|
+
│ │ ├── members_controller.rb # Dropdown options
|
|
442
|
+
│ │ ├── loans_controller.rb # Status badges + filtering
|
|
443
|
+
│ │ └── librarians_controller.rb # Roles + salary
|
|
444
|
+
│ ├── models/
|
|
445
|
+
│ │ ├── application_record.rb
|
|
446
|
+
│ │ ├── library.rb
|
|
447
|
+
│ │ ├── author.rb
|
|
448
|
+
│ │ ├── book.rb
|
|
449
|
+
│ │ ├── member.rb
|
|
450
|
+
│ │ ├── loan.rb
|
|
451
|
+
│ │ └── librarian.rb
|
|
452
|
+
│ └── views/
|
|
453
|
+
│ └── layouts/
|
|
454
|
+
│ └── application.html.erb # Tailwind CSS layout
|
|
455
|
+
├── config/
|
|
456
|
+
│ ├── application.rb # Rails config
|
|
457
|
+
│ ├── database.yml # SQLite3
|
|
458
|
+
│ ├── routes.rb # Resource routes
|
|
459
|
+
│ └── environments/
|
|
460
|
+
├── db/
|
|
461
|
+
│ ├── migrate/ # 6 migrations
|
|
462
|
+
│ └── seeds.rb # Rich sample data
|
|
463
|
+
└── bin/
|
|
464
|
+
└── rails # Rails executable
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Customization Examples
|
|
470
|
+
|
|
471
|
+
### Override Record Fetching
|
|
472
|
+
```ruby
|
|
473
|
+
private
|
|
474
|
+
def fetch_records
|
|
475
|
+
# Only show active books from current year
|
|
476
|
+
Book.where(available: true)
|
|
477
|
+
.where('publication_year >= ?', Date.current.year - 1)
|
|
478
|
+
.includes(:author, :library)
|
|
479
|
+
end
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Override Column Selection
|
|
483
|
+
```ruby
|
|
484
|
+
private
|
|
485
|
+
def determine_columns
|
|
486
|
+
%w[title author_id price available]
|
|
487
|
+
end
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Custom Layout
|
|
491
|
+
```ruby
|
|
492
|
+
def calculate_layout_header(fields)
|
|
493
|
+
[
|
|
494
|
+
{ width: "40%", field_name: :title },
|
|
495
|
+
{ width: "20%", field_name: :author_id },
|
|
496
|
+
{ width: "15%", field_name: :price },
|
|
497
|
+
{ width: "15%", field_name: :available },
|
|
498
|
+
{ width: "10%", title: "Actions" }
|
|
499
|
+
]
|
|
500
|
+
end
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## Technology Stack
|
|
506
|
+
|
|
507
|
+
- **Ruby**: 3.0+
|
|
508
|
+
- **Rails**: 7.0+
|
|
509
|
+
- **Database**: SQLite3
|
|
510
|
+
- **CSS**: Tailwind CSS (via CDN)
|
|
511
|
+
- **JavaScript**: Turbo (built into Rails)
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
## Troubleshooting
|
|
516
|
+
|
|
517
|
+
### Database Issues
|
|
518
|
+
```bash
|
|
519
|
+
# Reset everything
|
|
520
|
+
rake demo:reset
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Port Already in Use
|
|
524
|
+
```bash
|
|
525
|
+
# Stop the server (Ctrl+C) and run on different port
|
|
526
|
+
cd test/dummy_app
|
|
527
|
+
bin/rails server -p 3001
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Missing Dependencies
|
|
531
|
+
```bash
|
|
532
|
+
# From elaine_crud root
|
|
533
|
+
bundle install
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## What to Look For
|
|
539
|
+
|
|
540
|
+
### 1. **Zero Boilerplate**
|
|
541
|
+
Notice how each controller is typically 15-30 lines including field configurations. No view files needed!
|
|
542
|
+
|
|
543
|
+
### 2. **Smart Defaults**
|
|
544
|
+
- Foreign keys auto-detected
|
|
545
|
+
- Has-many relationships auto-shown
|
|
546
|
+
- Sensible column visibility
|
|
547
|
+
- N+1 query prevention
|
|
548
|
+
|
|
549
|
+
### 3. **Easy Customization**
|
|
550
|
+
Every default behavior can be overridden with simple DSL methods.
|
|
551
|
+
|
|
552
|
+
### 4. **Modern UX**
|
|
553
|
+
- Inline editing with Turbo
|
|
554
|
+
- No page reloads
|
|
555
|
+
- Responsive design
|
|
556
|
+
- Clean Tailwind styling
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Running Integration Tests
|
|
561
|
+
|
|
562
|
+
The demo app includes a comprehensive integration test suite that validates all CRUD operations, custom layouts, and features.
|
|
563
|
+
|
|
564
|
+
### Test Setup
|
|
565
|
+
|
|
566
|
+
The test suite uses:
|
|
567
|
+
- **RSpec** - Testing framework
|
|
568
|
+
- **Capybara** - Browser simulation for integration testing
|
|
569
|
+
- **Database** - Automatically resets and seeds before tests
|
|
570
|
+
|
|
571
|
+
### Running Tests
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
# Run all integration tests
|
|
575
|
+
bundle exec rake spec
|
|
576
|
+
|
|
577
|
+
# Run only integration tests
|
|
578
|
+
bundle exec rake spec:integration
|
|
579
|
+
|
|
580
|
+
# Run tests for a specific controller
|
|
581
|
+
bundle exec rake spec:controller[libraries]
|
|
582
|
+
bundle exec rake spec:controller[books]
|
|
583
|
+
bundle exec rake spec:controller[members]
|
|
584
|
+
bundle exec rake spec:controller[librarians]
|
|
585
|
+
|
|
586
|
+
# Run a specific test file
|
|
587
|
+
bundle exec rspec spec/integration/books_crud_spec.rb
|
|
588
|
+
|
|
589
|
+
# Run tests with detailed output
|
|
590
|
+
bundle exec rspec spec/integration --format documentation
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Test Coverage
|
|
594
|
+
|
|
595
|
+
The integration test suite covers:
|
|
596
|
+
|
|
597
|
+
#### CRUD Operations (all controllers)
|
|
598
|
+
- ✅ Index page displays all records
|
|
599
|
+
- ✅ Index page shows correct field values
|
|
600
|
+
- ✅ Create new records via forms
|
|
601
|
+
- ✅ Edit existing records
|
|
602
|
+
- ✅ Delete records
|
|
603
|
+
- ✅ Form validation and error handling
|
|
604
|
+
|
|
605
|
+
#### Custom Layout Features
|
|
606
|
+
- ✅ Multi-row layout (Books with description on second row)
|
|
607
|
+
- ✅ Column spanning (colspan on description field)
|
|
608
|
+
- ✅ Flexible grid columns with minmax()
|
|
609
|
+
- ✅ Responsive horizontal scrolling
|
|
610
|
+
- ✅ Grid borders and styling
|
|
611
|
+
|
|
612
|
+
#### Field Display Customization
|
|
613
|
+
- ✅ Currency formatting ($19.99)
|
|
614
|
+
- ✅ Date formatting (January 15, 2024)
|
|
615
|
+
- ✅ Boolean badges (✓ Available / ✗ Checked Out)
|
|
616
|
+
- ✅ Email mailto links
|
|
617
|
+
- ✅ Dropdown options (roles, membership types)
|
|
618
|
+
|
|
619
|
+
#### Sorting and Filtering
|
|
620
|
+
- ✅ Default sort order (ascending by name/title)
|
|
621
|
+
- ✅ Sortable column headers with indicators
|
|
622
|
+
- ✅ Has-many relationship counts
|
|
623
|
+
- ✅ Relationship filtering
|
|
624
|
+
|
|
625
|
+
### Test Files
|
|
626
|
+
|
|
627
|
+
```
|
|
628
|
+
spec/
|
|
629
|
+
├── spec_helper.rb # RSpec configuration
|
|
630
|
+
├── support/
|
|
631
|
+
│ └── test_helpers.rb # Helper methods for tests
|
|
632
|
+
└── integration/
|
|
633
|
+
├── libraries_crud_spec.rb # Libraries CRUD tests
|
|
634
|
+
├── books_crud_spec.rb # Books CRUD tests (with multi-row layout)
|
|
635
|
+
├── members_crud_spec.rb # Members CRUD tests (with dropdowns)
|
|
636
|
+
├── librarians_crud_spec.rb # Librarians CRUD tests (with currency)
|
|
637
|
+
├── layout_features_spec.rb # Custom layout feature tests
|
|
638
|
+
└── sorting_and_filtering_spec.rb # Sorting and filtering tests
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### Example Test Output
|
|
642
|
+
|
|
643
|
+
```
|
|
644
|
+
Libraries CRUD
|
|
645
|
+
Index page
|
|
646
|
+
✓ displays all libraries
|
|
647
|
+
✓ displays library details correctly
|
|
648
|
+
✓ has New Library link
|
|
649
|
+
Creating a library
|
|
650
|
+
✓ shows new library form
|
|
651
|
+
✓ creates a new library successfully
|
|
652
|
+
Editing a library
|
|
653
|
+
✓ shows edit library form
|
|
654
|
+
✓ updates library successfully
|
|
655
|
+
Deleting a library
|
|
656
|
+
✓ deletes library successfully
|
|
657
|
+
|
|
658
|
+
Finished in 2.34 seconds (files took 1.2 seconds to load)
|
|
659
|
+
8 examples, 0 failures
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Continuous Integration
|
|
663
|
+
|
|
664
|
+
The test suite is designed to:
|
|
665
|
+
- Reset the database to a clean state before each test run
|
|
666
|
+
- Use database transactions to isolate tests
|
|
667
|
+
- Verify all routes work without errors
|
|
668
|
+
- Ensure data integrity after CRUD operations
|
|
669
|
+
- Validate custom field displays and layouts
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## Next Steps
|
|
674
|
+
|
|
675
|
+
1. **Explore the UI**: Click around and try all the features
|
|
676
|
+
2. **Run the Tests**: Verify everything works with `bundle exec rake spec`
|
|
677
|
+
3. **Read the Code**: Check `test/dummy_app/app/controllers/` for examples
|
|
678
|
+
4. **Modify Data**: Use the console to add your own records
|
|
679
|
+
5. **Customize**: Try changing field configurations and see the results
|
|
680
|
+
6. **Integrate**: Use this as a reference for your own ElaineCrud projects
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## Additional Resources
|
|
685
|
+
|
|
686
|
+
- **Main Documentation**: See `/docs` folder for detailed feature documentation
|
|
687
|
+
- **API Reference**: `ELAINE_CRUD_API_DOCUMENTATION.md` in project root
|
|
688
|
+
- **Source Code**: All controllers in `test/dummy_app/app/controllers/`
|
|
689
|
+
- **Test Suite**: Integration tests in `spec/integration/`
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
**Happy Exploring! 🎉**
|