b4um_generators 0.2.17 → 0.4.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 +4 -4
- data/CHANGELOG.md +30 -0
- data/README.de.md +418 -4
- data/README.md +405 -5
- data/lib/b4um_generators/version.rb +1 -1
- data/lib/generators/b4um/admin/admin_generator.rb +614 -0
- data/lib/generators/b4um/admin/templates/add_admin_fields_migration.rb.tt +10 -0
- data/lib/generators/b4um/admin/templates/admin_base_controller.rb.tt +5 -0
- data/lib/generators/b4um/admin/templates/admin_dashboard.html.erb.tt +19 -0
- data/lib/generators/b4um/admin/templates/admin_dashboard_controller.rb.tt +6 -0
- data/lib/generators/b4um/admin/templates/admin_users_controller.rb.tt +70 -0
- data/lib/generators/b4um/admin/templates/admin_users_index.html.erb.tt +110 -0
- data/lib/generators/b4um/admin/templates/b4um_admin.rake.tt +106 -0
- data/lib/generators/b4um/authentication/authentication_generator.rb +90 -1
- data/lib/generators/b4um/guest/guest_generator.rb +673 -0
- data/lib/generators/b4um/guest/templates/add_guest_fields_migration.rb.tt +12 -0
- data/lib/generators/b4um/guest/templates/b4um_guests.rake.tt +12 -0
- data/lib/generators/b4um/guest/templates/edit.html.erb.tt +156 -0
- data/lib/generators/b4um/guest/templates/guest_expiration_warning.html.erb.tt +12 -0
- data/lib/generators/b4um/guest/templates/guests_controller.rb.tt +88 -0
- data/lib/generators/b4um/guest/templates/new.html.erb.tt +136 -0
- data/lib/generators/b4um/help/help_generator.rb +228 -0
- data/lib/generators/b4um/install/templates/b4um/sortable.css +158 -0
- data/lib/generators/b4um/install/templates/b4um.css +1 -0
- data/lib/generators/b4um/pagination/pagination_generator.rb +32 -5
- data/lib/generators/b4um/scaffold/scaffold_generator.rb +50 -0
- data/lib/generators/b4um/scaffold/templates/_form.html.erb.tt +18 -14
- data/lib/generators/b4um/search/search_generator.rb +22 -8
- data/lib/generators/b4um/sortable/sortable_generator.rb +529 -0
- data/lib/generators/b4um/sortable/templates/_sortable.html.erb.tt +40 -0
- data/lib/generators/b4um/sortable/templates/add_position_migration.rb.tt +26 -0
- data/lib/generators/b4um/sortable/templates/sort.html.erb.tt +3 -0
- data/lib/generators/b4um/sortable/templates/sortable_controller.js +166 -0
- metadata +22 -1
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/named_base"
|
|
5
|
+
|
|
6
|
+
module B4um
|
|
7
|
+
module Generators
|
|
8
|
+
class SortableGenerator < Rails::Generators::NamedBase
|
|
9
|
+
include Rails::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
class_option :path,
|
|
14
|
+
type: :string,
|
|
15
|
+
default: nil,
|
|
16
|
+
desc: "Creates a separate sortable page under the given path."
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def desc(_description = nil)
|
|
20
|
+
"Adds sortable positioning to an existing B4UM resource."
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def validate_model
|
|
25
|
+
return if File.exist?(model_path)
|
|
26
|
+
|
|
27
|
+
raise Thor::Error,
|
|
28
|
+
"Model not found: app/models/#{file_name}.rb"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def validate_controller
|
|
32
|
+
return if File.exist?(controller_path)
|
|
33
|
+
|
|
34
|
+
raise Thor::Error,
|
|
35
|
+
"Controller not found: app/controllers/#{plural_table_name}_controller.rb"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def validate_index_view
|
|
39
|
+
return if File.exist?(index_view_path)
|
|
40
|
+
|
|
41
|
+
raise Thor::Error,
|
|
42
|
+
"Index view not found: app/views/#{plural_table_name}/index.html.erb"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def create_position_migration
|
|
46
|
+
return if position_column_exists?
|
|
47
|
+
|
|
48
|
+
migration_template(
|
|
49
|
+
"add_position_migration.rb.tt",
|
|
50
|
+
"db/migrate/add_position_to_#{plural_table_name}.rb"
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def update_model
|
|
55
|
+
model_content = File.read(model_path)
|
|
56
|
+
|
|
57
|
+
return if model_content.include?("before_create :b4um_set_sortable_position")
|
|
58
|
+
|
|
59
|
+
inject_into_class(
|
|
60
|
+
model_path,
|
|
61
|
+
class_name,
|
|
62
|
+
<<~RUBY.indent(2)
|
|
63
|
+
before_create :b4um_set_sortable_position
|
|
64
|
+
after_destroy :b4um_compact_sortable_positions
|
|
65
|
+
|
|
66
|
+
def b4um_set_sortable_position
|
|
67
|
+
return if position.present?
|
|
68
|
+
|
|
69
|
+
self.position = self.class.maximum(:position).to_i + 1
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def b4um_compact_sortable_positions
|
|
73
|
+
self.class
|
|
74
|
+
.where("position > ?", position)
|
|
75
|
+
.update_all("position = position - 1")
|
|
76
|
+
end
|
|
77
|
+
RUBY
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
say_status(
|
|
81
|
+
:sortable,
|
|
82
|
+
"#{class_name} now assigns sortable positions",
|
|
83
|
+
:green
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def update_controller
|
|
88
|
+
controller_content = File.read(controller_path)
|
|
89
|
+
|
|
90
|
+
update_index_order(controller_content)
|
|
91
|
+
add_sort_action
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def add_sort_route
|
|
95
|
+
routes_path = File.join(
|
|
96
|
+
destination_root,
|
|
97
|
+
"config/routes.rb"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
unless File.exist?(routes_path)
|
|
101
|
+
raise Thor::Error,
|
|
102
|
+
"Routes not found: config/routes.rb"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
routes = File.read(routes_path)
|
|
106
|
+
|
|
107
|
+
if options[:path].present?
|
|
108
|
+
add_separate_sort_routes(routes)
|
|
109
|
+
return
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return if sort_route_exists?(routes)
|
|
113
|
+
return if separate_sort_route_exists?(routes)
|
|
114
|
+
|
|
115
|
+
add_sort_route_to_resources(routes)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def create_sortable_controller
|
|
119
|
+
copy_file(
|
|
120
|
+
File.expand_path(
|
|
121
|
+
"templates/sortable_controller.js",
|
|
122
|
+
__dir__
|
|
123
|
+
),
|
|
124
|
+
"app/javascript/controllers/sortable_controller.js"
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def create_sortable_partial
|
|
129
|
+
template(
|
|
130
|
+
"_sortable.html.erb.tt",
|
|
131
|
+
File.join(
|
|
132
|
+
"app/views",
|
|
133
|
+
plural_table_name,
|
|
134
|
+
"_sortable.html.erb"
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def create_sortable_view
|
|
140
|
+
return unless options[:path].present?
|
|
141
|
+
|
|
142
|
+
template(
|
|
143
|
+
"sort.html.erb.tt",
|
|
144
|
+
File.join(
|
|
145
|
+
"app/views",
|
|
146
|
+
plural_table_name,
|
|
147
|
+
"sort.html.erb"
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def update_index_layout
|
|
153
|
+
return unless File.exist?(index_path)
|
|
154
|
+
|
|
155
|
+
index = File.read(index_path)
|
|
156
|
+
|
|
157
|
+
if options[:path].present?
|
|
158
|
+
restore_index_layout(index)
|
|
159
|
+
else
|
|
160
|
+
use_sortable_index_layout(index)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def self.next_migration_number(_dirname)
|
|
165
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
def use_sortable_index_layout(index)
|
|
171
|
+
updated_index = index.sub(
|
|
172
|
+
/render\s+["'](?:bento|table|list|alternating|sortable)["']/,
|
|
173
|
+
'render "sortable"'
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return if updated_index == index
|
|
177
|
+
|
|
178
|
+
File.write(index_path, updated_index)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def restore_index_layout(index)
|
|
182
|
+
return unless index.match?(
|
|
183
|
+
/render\s+["']sortable["']/
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
layout = original_index_layout
|
|
187
|
+
|
|
188
|
+
return unless layout
|
|
189
|
+
|
|
190
|
+
updated_index = index.sub(
|
|
191
|
+
/render\s+["']sortable["']/,
|
|
192
|
+
%(render "#{layout}")
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
File.write(index_path, updated_index)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def original_index_layout
|
|
199
|
+
%w[bento table list alternating].find do |layout|
|
|
200
|
+
File.exist?(
|
|
201
|
+
File.join(
|
|
202
|
+
destination_root,
|
|
203
|
+
"app/views",
|
|
204
|
+
plural_table_name,
|
|
205
|
+
"_#{layout}.html.erb"
|
|
206
|
+
)
|
|
207
|
+
)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def index_path
|
|
212
|
+
File.join(
|
|
213
|
+
destination_root,
|
|
214
|
+
"app/views",
|
|
215
|
+
plural_table_name,
|
|
216
|
+
"index.html.erb"
|
|
217
|
+
)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def model_path
|
|
221
|
+
File.join(
|
|
222
|
+
destination_root,
|
|
223
|
+
"app/models",
|
|
224
|
+
"#{file_name}.rb"
|
|
225
|
+
)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def controller_path
|
|
229
|
+
File.join(
|
|
230
|
+
destination_root,
|
|
231
|
+
"app/controllers",
|
|
232
|
+
"#{plural_table_name}_controller.rb"
|
|
233
|
+
)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def index_view_path
|
|
237
|
+
File.join(
|
|
238
|
+
destination_root,
|
|
239
|
+
"app/views",
|
|
240
|
+
plural_table_name,
|
|
241
|
+
"index.html.erb"
|
|
242
|
+
)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def update_index_order(controller_content)
|
|
246
|
+
return if controller_content.include?(
|
|
247
|
+
"#{class_name}.order(:position, :id)"
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
old_scope = "#{class_name}.all"
|
|
251
|
+
|
|
252
|
+
unless controller_content.include?(old_scope)
|
|
253
|
+
raise Thor::Error,
|
|
254
|
+
"Could not find #{class_name}.all in app/controllers/#{plural_table_name}_controller.rb"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
gsub_file(
|
|
258
|
+
controller_path,
|
|
259
|
+
old_scope,
|
|
260
|
+
"#{class_name}.order(:position, :id)"
|
|
261
|
+
)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def add_sort_action
|
|
265
|
+
controller_content = File.read(controller_path)
|
|
266
|
+
|
|
267
|
+
if controller_content.match?(/^\s*def\s+sort\b/)
|
|
268
|
+
add_sort_page_support(controller_content)
|
|
269
|
+
return
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
get_handling =
|
|
273
|
+
if options[:path].present?
|
|
274
|
+
<<~RUBY
|
|
275
|
+
if request.get?
|
|
276
|
+
@#{plural_table_name} = #{class_name}.order(:position, :id)
|
|
277
|
+
return
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
RUBY
|
|
281
|
+
else
|
|
282
|
+
""
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
action = <<~RUBY.indent(2)
|
|
286
|
+
def sort
|
|
287
|
+
#{get_handling.indent(2)} record = #{class_name}.find_by(id: params[:id])
|
|
288
|
+
target_position = params[:position].to_i
|
|
289
|
+
maximum_position = #{class_name}.count
|
|
290
|
+
|
|
291
|
+
unless record &&
|
|
292
|
+
target_position.between?(1, maximum_position)
|
|
293
|
+
head :unprocessable_content
|
|
294
|
+
return
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
if target_position == record.position
|
|
298
|
+
head :no_content
|
|
299
|
+
return
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
old_position = record.position
|
|
303
|
+
|
|
304
|
+
#{class_name}.transaction do
|
|
305
|
+
if target_position < old_position
|
|
306
|
+
#{class_name}
|
|
307
|
+
.where(position: target_position...old_position)
|
|
308
|
+
.where.not(id: record.id)
|
|
309
|
+
.update_all("position = position + 1")
|
|
310
|
+
elsif target_position > old_position
|
|
311
|
+
#{class_name}
|
|
312
|
+
.where(position: (old_position + 1)..target_position)
|
|
313
|
+
.where.not(id: record.id)
|
|
314
|
+
.update_all("position = position - 1")
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
record.update_columns(
|
|
318
|
+
position: target_position,
|
|
319
|
+
updated_at: Time.current
|
|
320
|
+
)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
head :no_content
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
RUBY
|
|
327
|
+
|
|
328
|
+
private_marker = "\n private\n"
|
|
329
|
+
|
|
330
|
+
if controller_content.include?(private_marker)
|
|
331
|
+
insert_into_file(
|
|
332
|
+
controller_path,
|
|
333
|
+
action,
|
|
334
|
+
before: private_marker
|
|
335
|
+
)
|
|
336
|
+
else
|
|
337
|
+
controller_end = /\nend\s*\z/
|
|
338
|
+
|
|
339
|
+
unless controller_content.match?(controller_end)
|
|
340
|
+
raise Thor::Error,
|
|
341
|
+
"Could not find the end of app/controllers/#{plural_table_name}_controller.rb"
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
insert_into_file(
|
|
345
|
+
controller_path,
|
|
346
|
+
"\n#{action}",
|
|
347
|
+
before: controller_end
|
|
348
|
+
)
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def add_sort_page_support(controller_content)
|
|
353
|
+
return unless options[:path].present?
|
|
354
|
+
return if controller_content.include?("if request.get?")
|
|
355
|
+
|
|
356
|
+
sort_action =
|
|
357
|
+
/^(\s*)def sort\s*$/
|
|
358
|
+
|
|
359
|
+
unless controller_content.match?(sort_action)
|
|
360
|
+
raise Thor::Error,
|
|
361
|
+
"Could not find sort action in app/controllers/#{plural_table_name}_controller.rb"
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
gsub_file(
|
|
365
|
+
controller_path,
|
|
366
|
+
sort_action
|
|
367
|
+
) do |match|
|
|
368
|
+
indentation = match[/\A\s*/]
|
|
369
|
+
|
|
370
|
+
<<~RUBY.chomp
|
|
371
|
+
#{match}
|
|
372
|
+
#{indentation} if request.get?
|
|
373
|
+
#{indentation} @#{plural_table_name} = #{class_name}.order(:position, :id)
|
|
374
|
+
#{indentation} return
|
|
375
|
+
#{indentation} end
|
|
376
|
+
RUBY
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def add_separate_sort_routes(routes)
|
|
381
|
+
path = options[:path].to_s
|
|
382
|
+
|
|
383
|
+
remove_default_sort_route(routes)
|
|
384
|
+
|
|
385
|
+
routes = File.read(
|
|
386
|
+
File.join(
|
|
387
|
+
destination_root,
|
|
388
|
+
"config/routes.rb"
|
|
389
|
+
)
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
get_route =
|
|
393
|
+
%(get "#{path}", to: "#{plural_table_name}#sort")
|
|
394
|
+
|
|
395
|
+
patch_route =
|
|
396
|
+
%(patch "#{path}", to: "#{plural_table_name}#sort", as: :sort_#{plural_table_name})
|
|
397
|
+
|
|
398
|
+
routes_to_add = []
|
|
399
|
+
|
|
400
|
+
routes_to_add << get_route unless routes.include?(get_route)
|
|
401
|
+
|
|
402
|
+
routes_to_add << patch_route unless routes.include?(patch_route)
|
|
403
|
+
|
|
404
|
+
return if routes_to_add.empty?
|
|
405
|
+
|
|
406
|
+
routes_end = /^end\s*\z/
|
|
407
|
+
|
|
408
|
+
unless routes.match?(routes_end)
|
|
409
|
+
raise Thor::Error,
|
|
410
|
+
"Could not find the end of config/routes.rb"
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
route_code = <<~RUBY
|
|
414
|
+
|
|
415
|
+
#{routes_to_add.join("\n ")}
|
|
416
|
+
RUBY
|
|
417
|
+
|
|
418
|
+
insert_into_file(
|
|
419
|
+
"config/routes.rb",
|
|
420
|
+
route_code,
|
|
421
|
+
before: routes_end
|
|
422
|
+
)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def remove_default_sort_route(routes)
|
|
426
|
+
return unless sort_route_exists?(routes)
|
|
427
|
+
|
|
428
|
+
gsub_file(
|
|
429
|
+
"config/routes.rb",
|
|
430
|
+
/^(\s*)patch :sort, on: :collection\s*\n/,
|
|
431
|
+
""
|
|
432
|
+
)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def sort_route_exists?(routes)
|
|
436
|
+
resource_block = sortable_resource_block(routes)
|
|
437
|
+
|
|
438
|
+
resource_block&.match?(
|
|
439
|
+
/^\s*patch\s+:sort,\s+on:\s+:collection\s*$/
|
|
440
|
+
) || false
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def separate_sort_route_exists?(routes)
|
|
444
|
+
routes.match?(
|
|
445
|
+
/^\s*patch\s+["'][^"']+["'],\s+to:\s+["']#{Regexp.escape(plural_table_name)}#sort["']/
|
|
446
|
+
)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def sortable_resource_block(routes)
|
|
450
|
+
pattern = /
|
|
451
|
+
^(?<indent>\s*)
|
|
452
|
+
resources\s+:#{Regexp.escape(plural_table_name)}\s+do\s*$
|
|
453
|
+
(?<body>.*?)
|
|
454
|
+
^\k<indent>end\s*$
|
|
455
|
+
/mx
|
|
456
|
+
|
|
457
|
+
routes[pattern]
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def add_sort_route_to_resources(routes)
|
|
461
|
+
block_pattern =
|
|
462
|
+
/^(\s*)resources :#{Regexp.escape(plural_table_name)} do\s*$/
|
|
463
|
+
|
|
464
|
+
plain_pattern =
|
|
465
|
+
/^(\s*)resources :#{Regexp.escape(plural_table_name)}\s*$/
|
|
466
|
+
|
|
467
|
+
if routes.match?(block_pattern)
|
|
468
|
+
gsub_file(
|
|
469
|
+
"config/routes.rb",
|
|
470
|
+
block_pattern
|
|
471
|
+
) do |match|
|
|
472
|
+
indentation = match[/\A\s*/]
|
|
473
|
+
|
|
474
|
+
[
|
|
475
|
+
match,
|
|
476
|
+
"#{indentation} patch :sort, on: :collection"
|
|
477
|
+
].join("\n")
|
|
478
|
+
end
|
|
479
|
+
elsif routes.match?(plain_pattern)
|
|
480
|
+
gsub_file(
|
|
481
|
+
"config/routes.rb",
|
|
482
|
+
plain_pattern
|
|
483
|
+
) do |match|
|
|
484
|
+
indentation = match[/\A\s*/]
|
|
485
|
+
|
|
486
|
+
[
|
|
487
|
+
"#{indentation}resources :#{plural_table_name} do",
|
|
488
|
+
"#{indentation} patch :sort, on: :collection",
|
|
489
|
+
"#{indentation}end"
|
|
490
|
+
].join("\n")
|
|
491
|
+
end
|
|
492
|
+
else
|
|
493
|
+
raise Thor::Error,
|
|
494
|
+
"Could not find resources :#{plural_table_name} in config/routes.rb"
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def position_column_exists?
|
|
499
|
+
migration_contains_position? ||
|
|
500
|
+
schema_contains_position?
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def migration_contains_position?
|
|
504
|
+
Dir.glob(
|
|
505
|
+
File.join(
|
|
506
|
+
destination_root,
|
|
507
|
+
"db/migrate/*_add_position_to_#{plural_table_name}.rb"
|
|
508
|
+
)
|
|
509
|
+
).any?
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
def schema_contains_position?
|
|
513
|
+
schema_path = File.join(destination_root, "db/schema.rb")
|
|
514
|
+
|
|
515
|
+
return false unless File.exist?(schema_path)
|
|
516
|
+
|
|
517
|
+
schema = File.read(schema_path)
|
|
518
|
+
|
|
519
|
+
table_pattern = /
|
|
520
|
+
create_table\s+"#{Regexp.escape(plural_table_name)}".*?^ end
|
|
521
|
+
/mx
|
|
522
|
+
|
|
523
|
+
table = schema[table_pattern]
|
|
524
|
+
|
|
525
|
+
table&.match?(/t\.integer\s+"position"/) || false
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<div class="b4um-sortable"
|
|
2
|
+
data-controller="sortable"
|
|
3
|
+
data-sortable-update-url-value="<%%= sort_<%= plural_table_name %>_path %>">
|
|
4
|
+
|
|
5
|
+
<%% <%= plural_table_name %>.each do |<%= singular_table_name %>| %>
|
|
6
|
+
<div class="b4um-sortable__item"
|
|
7
|
+
data-sortable-id="<%%= <%= singular_table_name %>.id %>"
|
|
8
|
+
data-action="dragover->sortable#dragOver drop->sortable#drop">
|
|
9
|
+
|
|
10
|
+
<div class="b4um-sortable__controls">
|
|
11
|
+
<input type="number"
|
|
12
|
+
class="b4um-sortable__position"
|
|
13
|
+
value="<%%= <%= singular_table_name %>.position %>"
|
|
14
|
+
min="1"
|
|
15
|
+
aria-label="Position"
|
|
16
|
+
data-action="change->sortable#positionChanged keydown->sortable#positionKeydown">
|
|
17
|
+
|
|
18
|
+
<button type="button"
|
|
19
|
+
class="b4um-sortable__handle"
|
|
20
|
+
draggable="true"
|
|
21
|
+
aria-label="Move <%= singular_table_name.humanize.downcase %>"
|
|
22
|
+
data-action="dragstart->sortable#dragStart dragend->sortable#dragEnd">
|
|
23
|
+
☰
|
|
24
|
+
</button>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="b4um-sortable__content">
|
|
28
|
+
<%%= render <%= singular_table_name %>,
|
|
29
|
+
compact: true,
|
|
30
|
+
preview_length: 100 %>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="b4um-sortable__actions">
|
|
34
|
+
<%%= link_to "Show",
|
|
35
|
+
<%= singular_table_name %>,
|
|
36
|
+
class: "button button--secondary" %>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<%% end %>
|
|
40
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddPositionTo<%= class_name.pluralize %> < ActiveRecord::Migration[8.0]
|
|
4
|
+
def up
|
|
5
|
+
add_column :<%= plural_table_name %>, :position, :integer
|
|
6
|
+
|
|
7
|
+
sortable_record = Class.new(ActiveRecord::Base) do
|
|
8
|
+
self.table_name = "<%= plural_table_name %>"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
sortable_record.reset_column_information
|
|
12
|
+
|
|
13
|
+
sortable_record.order(:id).find_each.with_index(1) do |record, position|
|
|
14
|
+
record.update_columns(position: position)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
change_column_null :<%= plural_table_name %>, :position, false
|
|
18
|
+
|
|
19
|
+
add_index :<%= plural_table_name %>, :position
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def down
|
|
23
|
+
remove_index :<%= plural_table_name %>, :position
|
|
24
|
+
remove_column :<%= plural_table_name %>, :position
|
|
25
|
+
end
|
|
26
|
+
end
|