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,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElaineCrud
4
+ # Concern for sorting functionality in ElaineCrud controllers
5
+ # Provides methods for URL parameter-based sorting with validation
6
+ module SortingConcern
7
+ extend ActiveSupport::Concern
8
+
9
+ # Get current sort column from params or default
10
+ # @return [Symbol] The sort column
11
+ def current_sort_column
12
+ if params[:sort].present? && valid_sort_column?(params[:sort])
13
+ params[:sort].to_sym
14
+ else
15
+ self.class.default_sort_column || :id
16
+ end
17
+ end
18
+
19
+ # Get current sort direction from params or default
20
+ # @return [Symbol] The sort direction (:asc or :desc)
21
+ def current_sort_direction
22
+ if params[:direction].present? && %w[asc desc].include?(params[:direction])
23
+ params[:direction].to_sym
24
+ else
25
+ self.class.default_sort_direction || :asc
26
+ end
27
+ end
28
+
29
+ # Get the opposite direction for toggling sort
30
+ # @param current_direction [Symbol] Current sort direction
31
+ # @return [Symbol] Opposite direction
32
+ def toggle_sort_direction(current_direction)
33
+ current_direction.to_sym == :asc ? :desc : :asc
34
+ end
35
+
36
+ private
37
+
38
+ # Apply sorting to the records based on URL parameters
39
+ # @param records [ActiveRecord::Relation] The base query
40
+ # @return [ActiveRecord::Relation] The sorted query
41
+ def apply_sorting(records)
42
+ sort_column = current_sort_column
43
+ sort_direction = current_sort_direction
44
+
45
+ # Validate sort column exists
46
+ return records unless valid_sort_column?(sort_column)
47
+
48
+ # Use Arel to safely construct ORDER BY clause
49
+ # This prevents SQL injection in column names
50
+ table = crud_model.arel_table
51
+ records.order(table[sort_column].send(sort_direction))
52
+ end
53
+
54
+ # Check if a column is valid for sorting
55
+ # @param column [String, Symbol] The column name
56
+ # @return [Boolean] True if valid for sorting
57
+ def valid_sort_column?(column)
58
+ return false if column.blank?
59
+
60
+ column_str = column.to_s
61
+ crud_model.column_names.include?(column_str) ||
62
+ crud_model.attribute_names.include?(column_str)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElaineCrud
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kaminari'
4
+
5
+ require_relative 'elaine_crud/version'
6
+ require_relative 'elaine_crud/engine'
7
+ require_relative 'elaine_crud/field_configuration'
8
+ require_relative 'elaine_crud/sorting_concern'
9
+ require_relative 'elaine_crud/search_and_filtering'
10
+
11
+ # Controller concerns
12
+ require_relative 'elaine_crud/dsl_methods'
13
+ require_relative 'elaine_crud/field_configuration_methods'
14
+ require_relative 'elaine_crud/layout_calculation'
15
+ require_relative 'elaine_crud/relationship_handling'
16
+ require_relative 'elaine_crud/record_fetching'
17
+ require_relative 'elaine_crud/parameter_handling'
18
+ require_relative 'elaine_crud/export_handling'
19
+
20
+ # Routing helper
21
+ require_relative 'elaine_crud/routing'
22
+
23
+ module ElaineCrud
24
+ class Error < StandardError; end
25
+ end
@@ -0,0 +1,111 @@
1
+ namespace :demo do
2
+ desc "Run the demo application server"
3
+ task :server do
4
+ puts "Starting ElaineCrud Demo Application..."
5
+ puts "=" * 60
6
+ puts "Navigate to: http://localhost:3000"
7
+ puts "=" * 60
8
+
9
+ Dir.chdir(File.expand_path('../../test/dummy_app', __dir__)) do
10
+ exec "bin/rails server"
11
+ end
12
+ end
13
+
14
+ desc "Setup demo database (migrate and seed)"
15
+ task :setup do
16
+ puts "Setting up demo database..."
17
+ Dir.chdir(File.expand_path('../../test/dummy_app', __dir__)) do
18
+ puts "\n1. Creating database..."
19
+ system("bin/rails db:create") || abort("Database creation failed")
20
+
21
+ puts "\n2. Running migrations..."
22
+ system("bin/rails db:migrate") || abort("Migration failed")
23
+
24
+ puts "\n3. Seeding database with sample data..."
25
+ system("bin/rails db:seed") || abort("Seeding failed")
26
+
27
+ puts "\n" + "=" * 60
28
+ puts "Demo setup complete!"
29
+ puts "Run: rake demo:server"
30
+ puts "=" * 60
31
+ end
32
+ end
33
+
34
+ desc "Reset demo database (drop, create, migrate, seed)"
35
+ task :reset do
36
+ puts "Resetting demo database..."
37
+ Dir.chdir(File.expand_path('../../test/dummy_app', __dir__)) do
38
+ puts "\n1. Dropping database..."
39
+ system("bin/rails db:drop")
40
+
41
+ puts "\n2. Creating database..."
42
+ system("bin/rails db:create") || abort("Database creation failed")
43
+
44
+ puts "\n3. Running migrations..."
45
+ system("bin/rails db:migrate") || abort("Migration failed")
46
+
47
+ puts "\n4. Seeding database with sample data..."
48
+ system("bin/rails db:seed") || abort("Seeding failed")
49
+
50
+ puts "\n" + "=" * 60
51
+ puts "Demo database reset complete!"
52
+ puts "Run: rake demo:server"
53
+ puts "=" * 60
54
+ end
55
+ end
56
+
57
+ desc "Run Rails console in demo app context"
58
+ task :console do
59
+ puts "Starting Rails console for demo app..."
60
+ Dir.chdir(File.expand_path('../../test/dummy_app', __dir__)) do
61
+ exec "bin/rails console"
62
+ end
63
+ end
64
+
65
+ desc "Open Rails database console for demo app"
66
+ task :dbconsole do
67
+ puts "Starting database console for demo app..."
68
+ Dir.chdir(File.expand_path('../../test/dummy_app', __dir__)) do
69
+ exec "bin/rails dbconsole"
70
+ end
71
+ end
72
+
73
+ desc "Display demo app information and available routes"
74
+ task :info do
75
+ puts "\n" + "=" * 60
76
+ puts "ElaineCrud Demo Application Information"
77
+ puts "=" * 60
78
+
79
+ puts "\nAvailable Resources:"
80
+ puts " - Libraries (has_many books, members, librarians)"
81
+ puts " - Authors (has_many books)"
82
+ puts " - Books (belongs_to author, library | has_many loans)"
83
+ puts " - Members (belongs_to library | has_many loans)"
84
+ puts " - Loans (belongs_to book, member)"
85
+ puts " - Librarians (belongs_to library)"
86
+
87
+ puts "\nFeatures Demonstrated:"
88
+ puts " ✓ Automatic foreign key detection and dropdowns"
89
+ puts " ✓ Has-many relationships with counts"
90
+ puts " ✓ Custom field display (currency, dates, booleans)"
91
+ puts " ✓ Dropdown options for enums"
92
+ puts " ✓ Status badges with colors"
93
+ puts " ✓ Parent-child filtering"
94
+ puts " ✓ Sorting by columns"
95
+ puts " ✓ Inline editing with Turbo"
96
+
97
+ puts "\nRake Tasks:"
98
+ puts " rake demo:setup - Initial database setup"
99
+ puts " rake demo:reset - Reset database with fresh data"
100
+ puts " rake demo:server - Start the demo server"
101
+ puts " rake demo:console - Open Rails console"
102
+ puts " rake demo:dbconsole - Open database console"
103
+ puts " rake demo:info - Show this information"
104
+
105
+ puts "\n" + "=" * 60
106
+ end
107
+ end
108
+
109
+ # Set demo:info as the default demo task
110
+ desc "Show ElaineCrud demo information"
111
+ task :demo => 'demo:info'
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ # Note: Main :spec task is defined in Rakefile to avoid duplication
7
+ # This file only defines namespaced spec tasks for more granular test running
8
+
9
+ namespace :spec do
10
+ desc 'Run integration tests'
11
+ RSpec::Core::RakeTask.new(:integration) do |t|
12
+ t.pattern = 'spec/integration/**/*_spec.rb'
13
+ t.rspec_opts = '--format documentation'
14
+ end
15
+
16
+ desc 'Run integration tests for a specific controller (e.g., rake spec:controller[libraries])'
17
+ task :controller, [:name] do |t, args|
18
+ controller_name = args[:name]
19
+ sh "bundle exec rspec spec/integration/#{controller_name}_crud_spec.rb --format documentation"
20
+ end
21
+ end
22
+
23
+ task default: :spec
24
+ rescue LoadError
25
+ # RSpec not available
26
+ end
metadata ADDED
@@ -0,0 +1,264 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elaine_crud
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Garo
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '6.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '6.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: kaminari
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ - !ruby/object:Gem::Dependency
41
+ name: caxlsx
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '4.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '4.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: csv
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: turbo-rails
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rspec
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rspec-rails
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '6.0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '6.0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: capybara
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.0'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.0'
124
+ - !ruby/object:Gem::Dependency
125
+ name: selenium-webdriver
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '4.0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '4.0'
138
+ - !ruby/object:Gem::Dependency
139
+ name: sqlite3
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '2.1'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '2.1'
152
+ - !ruby/object:Gem::Dependency
153
+ name: puma
154
+ requirement: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '6.0'
159
+ type: :development
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '6.0'
166
+ - !ruby/object:Gem::Dependency
167
+ name: roo
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '2.10'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '2.10'
180
+ description: ElaineCrud provides a reusable BaseController and views to quickly generate
181
+ CRUD interfaces for any ActiveRecord model with minimal configuration.
182
+ email:
183
+ - juho.makinen@gmail.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - ".rspec"
189
+ - LICENSE
190
+ - README.md
191
+ - Rakefile
192
+ - TODO.md
193
+ - app/controllers/elaine_crud/base_controller.rb
194
+ - app/helpers/elaine_crud/base_helper.rb
195
+ - app/helpers/elaine_crud/search_helper.rb
196
+ - app/javascript/controllers/dropdown_controller.js
197
+ - app/views/elaine_crud/base/_edit_row.html.erb
198
+ - app/views/elaine_crud/base/_export_button.html.erb
199
+ - app/views/elaine_crud/base/_foreign_key_select_refresh.html.erb
200
+ - app/views/elaine_crud/base/_form.html.erb
201
+ - app/views/elaine_crud/base/_form_fields.html.erb
202
+ - app/views/elaine_crud/base/_index_table.html.erb
203
+ - app/views/elaine_crud/base/_modal.html.erb
204
+ - app/views/elaine_crud/base/_pagination.html.erb
205
+ - app/views/elaine_crud/base/_per_page_selector.html.erb
206
+ - app/views/elaine_crud/base/_search_bar.html.erb
207
+ - app/views/elaine_crud/base/_show_details.html.erb
208
+ - app/views/elaine_crud/base/_view_row.html.erb
209
+ - app/views/elaine_crud/base/edit.html.erb
210
+ - app/views/elaine_crud/base/index.html.erb
211
+ - app/views/elaine_crud/base/new.html.erb
212
+ - app/views/elaine_crud/base/new_modal.html.erb
213
+ - app/views/elaine_crud/base/not_found.html.erb
214
+ - app/views/elaine_crud/base/show.html.erb
215
+ - docs/ARCHITECTURE.md
216
+ - docs/CSS_GRID_LAYOUT.md
217
+ - docs/DEMO.md
218
+ - docs/DSL_EXAMPLES.md
219
+ - docs/FOREIGN_KEY_EXAMPLE.rb
220
+ - docs/FOREIGN_KEY_SUPPORT.md
221
+ - docs/HAS_MANY_IMPLEMENTATION.md
222
+ - docs/LAYOUT_EXAMPLES.md
223
+ - docs/TROUBLESHOOTING.md
224
+ - elaine_crud.gemspec
225
+ - lib/elaine_crud.rb
226
+ - lib/elaine_crud/dsl_methods.rb
227
+ - lib/elaine_crud/engine.rb
228
+ - lib/elaine_crud/export_handling.rb
229
+ - lib/elaine_crud/field_configuration.rb
230
+ - lib/elaine_crud/field_configuration_methods.rb
231
+ - lib/elaine_crud/layout_calculation.rb
232
+ - lib/elaine_crud/parameter_handling.rb
233
+ - lib/elaine_crud/record_fetching.rb
234
+ - lib/elaine_crud/relationship_handling.rb
235
+ - lib/elaine_crud/routing.rb
236
+ - lib/elaine_crud/search_and_filtering.rb
237
+ - lib/elaine_crud/sorting_concern.rb
238
+ - lib/elaine_crud/version.rb
239
+ - lib/tasks/demo.rake
240
+ - lib/tasks/spec.rake
241
+ homepage: https://github.com/garo/elaine_crud
242
+ licenses:
243
+ - MIT
244
+ metadata:
245
+ homepage_uri: https://github.com/garo/elaine_crud
246
+ source_code_uri: https://github.com/garo/elaine_crud
247
+ rdoc_options: []
248
+ require_paths:
249
+ - lib
250
+ required_ruby_version: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - ">="
253
+ - !ruby/object:Gem::Version
254
+ version: '0'
255
+ required_rubygems_version: !ruby/object:Gem::Requirement
256
+ requirements:
257
+ - - ">="
258
+ - !ruby/object:Gem::Version
259
+ version: '0'
260
+ requirements: []
261
+ rubygems_version: 3.6.7
262
+ specification_version: 4
263
+ summary: A Rails engine for generating CRUD UIs for ActiveRecord models
264
+ test_files: []