hot-glue 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/FUNDING.yml +2 -0
- data/.gitignore +16 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +196 -0
- data/LICENCE +13 -0
- data/README.md +262 -0
- data/Rakefile +32 -0
- data/app/helpers/hot_glue/controller_helper.rb +105 -0
- data/app/helpers/hot_glue_helper.rb +4 -0
- data/bin/rails +14 -0
- data/lib/generators/hot_glue/install_generator.rb +21 -0
- data/lib/generators/hot_glue/scaffold_generator.rb +674 -0
- data/lib/generators/hot_glue/templates/_errors.haml +5 -0
- data/lib/generators/hot_glue/templates/_flash_notices.haml +7 -0
- data/lib/generators/hot_glue/templates/_form.haml +4 -0
- data/lib/generators/hot_glue/templates/_line.haml +6 -0
- data/lib/generators/hot_glue/templates/_list.haml +9 -0
- data/lib/generators/hot_glue/templates/_new_button.haml +2 -0
- data/lib/generators/hot_glue/templates/_show.haml +7 -0
- data/lib/generators/hot_glue/templates/base_controller.rb +3 -0
- data/lib/generators/hot_glue/templates/controller.rb +125 -0
- data/lib/generators/hot_glue/templates/controller_spec.rb +110 -0
- data/lib/generators/hot_glue/templates/create.turbo_stream.haml +5 -0
- data/lib/generators/hot_glue/templates/destroy.turbo_stream.haml +2 -0
- data/lib/generators/hot_glue/templates/edit.haml +19 -0
- data/lib/generators/hot_glue/templates/edit.turbo_stream.haml +4 -0
- data/lib/generators/hot_glue/templates/index.haml +9 -0
- data/lib/generators/hot_glue/templates/new.haml +10 -0
- data/lib/generators/hot_glue/templates/update.turbo_stream.haml +5 -0
- data/lib/hot-glue.rb +28 -0
- data/lib/hotglue/engine.rb +6 -0
- data/lib/hotglue/version.rb +3 -0
- metadata +178 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails/generators/erb/scaffold/scaffold_generator'
|
2
|
+
require 'ffaker'
|
3
|
+
|
4
|
+
module HotGlue
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
hook_for :form_builder, :as => :scaffold
|
7
|
+
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
9
|
+
|
10
|
+
|
11
|
+
def initialize(*args) #:nodoc:
|
12
|
+
super
|
13
|
+
# copy_file "common_core.js", "app/javascript/common_core.js"
|
14
|
+
# copy_file "common_core.scss", "app/assets/stylesheets/common_core.scss"
|
15
|
+
copy_file "_flash_notices.haml", "app/views/layouts/_flash_notices.haml"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,674 @@
|
|
1
|
+
require 'rails/generators/erb/scaffold/scaffold_generator'
|
2
|
+
require 'ffaker'
|
3
|
+
|
4
|
+
|
5
|
+
module HotGlue
|
6
|
+
module GeneratorHelper
|
7
|
+
def text_area_output(col, field_length, col_identifier )
|
8
|
+
lines = field_length % 40
|
9
|
+
if lines > 5
|
10
|
+
lines = 5
|
11
|
+
end
|
12
|
+
|
13
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
14
|
+
= f.text_area :#{col.to_s}, class: 'form-control', cols: 40, rows: '#{lines}'
|
15
|
+
%label.form-text
|
16
|
+
#{col.to_s.humanize}\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
def field_output(col, type = nil, width, col_identifier )
|
22
|
+
|
23
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
24
|
+
= f.text_field :#{col.to_s}, value: @#{singular}.#{col.to_s}, size: #{width}, class: 'form-control', type: '#{type}'
|
25
|
+
%label.form-text
|
26
|
+
#{col.to_s.humanize}\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
class ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
32
|
+
hook_for :form_builder, :as => :scaffold
|
33
|
+
|
34
|
+
source_root File.expand_path('templates', __dir__)
|
35
|
+
attr_accessor :path, :singular, :plural, :singular_class, :nest_with
|
36
|
+
|
37
|
+
|
38
|
+
include GeneratorHelper
|
39
|
+
|
40
|
+
|
41
|
+
def initialize(*meta_args) #:nodoc:
|
42
|
+
super
|
43
|
+
|
44
|
+
begin
|
45
|
+
object = eval(class_name)
|
46
|
+
rescue StandardError => e
|
47
|
+
puts "*** Oops: It looks like there is no object for #{class_name}. Please define the object + database table first."
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
args = meta_args[0]
|
54
|
+
@singular = args[0].tableize.singularize # should be in form hello_world
|
55
|
+
|
56
|
+
|
57
|
+
@plural = @singular + "s" # supply to override; leave blank to use default
|
58
|
+
@singular_class = @singular.titleize.gsub(" ", "")
|
59
|
+
@nest = nil
|
60
|
+
@namespace = nil
|
61
|
+
@nested_args = []
|
62
|
+
|
63
|
+
@auth = "current_user"
|
64
|
+
@auth_identifier = nil
|
65
|
+
|
66
|
+
args[1..-1].each do |a|
|
67
|
+
var_name, var_value = a.split("=")
|
68
|
+
case (var_name)
|
69
|
+
|
70
|
+
when "plural"
|
71
|
+
@plural = var_value
|
72
|
+
when "nest"
|
73
|
+
@nest = var_value
|
74
|
+
when "namespace"
|
75
|
+
@namespace = var_value
|
76
|
+
when "auth"
|
77
|
+
@auth = var_value
|
78
|
+
when "auth_identifier"
|
79
|
+
@auth_identifier = var_value || ""
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
auth_assoc = @auth.gsub("current_","")
|
84
|
+
|
85
|
+
@no_delete = false
|
86
|
+
@no_create = false
|
87
|
+
|
88
|
+
flags = meta_args[1]
|
89
|
+
flags.each do |f|
|
90
|
+
case (f)
|
91
|
+
when "--god"
|
92
|
+
@auth = nil
|
93
|
+
# when "--with-index"
|
94
|
+
# @with_index = true
|
95
|
+
when "--specs-only"
|
96
|
+
@specs_only = true
|
97
|
+
when "--no-specs"
|
98
|
+
@no_specs = true
|
99
|
+
when "--no-delete"
|
100
|
+
@no_delete = true
|
101
|
+
when "--no-create"
|
102
|
+
@no_create = true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if @specs_only && @no_specs
|
107
|
+
puts "*** Oops: You seem to have specified both the --specs-only flag and --no-specs flags. this doesn't make any sense, so I am aborting. sorry."
|
108
|
+
exit
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# only used for the before_action
|
113
|
+
if @auth_identifier.nil? && !@auth.nil?
|
114
|
+
@auth_identifier = @auth.gsub("current_", "")
|
115
|
+
end
|
116
|
+
|
117
|
+
# when in self auth, the object is the same as the authenticated object
|
118
|
+
if @auth && auth_identifier == @singular
|
119
|
+
@self_auth = true
|
120
|
+
end
|
121
|
+
|
122
|
+
if !@nest.nil?
|
123
|
+
@nested_args = @nest.split("/")
|
124
|
+
@nested_args_plural = {}
|
125
|
+
@nested_args.each do |a|
|
126
|
+
@nested_args_plural[a] = a + "s"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# the @object_owner will always be object that will 'own' the object
|
131
|
+
# for new and create
|
132
|
+
|
133
|
+
if @auth && ! @self_auth && @nested_args.none?
|
134
|
+
@object_owner_sym = @auth.gsub("current_", "").to_sym
|
135
|
+
@object_owner_eval = @auth
|
136
|
+
else
|
137
|
+
|
138
|
+
if @nested_args.any?
|
139
|
+
@object_owner_sym = @nested_args.last.to_sym
|
140
|
+
@object_owner_eval = "@#{@nested_args.last}"
|
141
|
+
else
|
142
|
+
@object_owner_sym = ""
|
143
|
+
@object_owner_eval = ""
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
# create the columns
|
150
|
+
if !@object_owner_sym.empty?
|
151
|
+
auth_assoc_field = auth_assoc + "_id"
|
152
|
+
assoc = eval("#{singular_class}.reflect_on_association(:#{@object_owner_sym})")
|
153
|
+
if assoc
|
154
|
+
ownership_field = assoc.name.to_s + "_id"
|
155
|
+
else
|
156
|
+
if @auth
|
157
|
+
puts "*** Oops: It looks like is no association from current_#{@object_owner_sym} to a class called #{singular_class}. If your user is called something else, pass with flag auth=current_X where X is the model for your users as lowercase. Also, be sure to implement current_X as a method on your controller. (If you really don't want to implement a current_X on your controller and want me to check some other method for your current user, see the section in the docs for auth_identifier.) To make a controller that can read all records, specify with --god."
|
158
|
+
else
|
159
|
+
puts "*** Oops: god mode could not find the association(?). something is wrong."
|
160
|
+
end
|
161
|
+
exit
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
exclude_fields = [ :id, :created_at, :updated_at, :encrypted_password, :reset_password_token,
|
166
|
+
:reset_password_sent_at, :remember_created_at, :confirmation_token, :confirmed_at,
|
167
|
+
:confirmation_sent_at, :unconfirmed_email]
|
168
|
+
|
169
|
+
exclude_fields << auth_assoc_field.to_sym if !auth_assoc_field.nil?
|
170
|
+
exclude_fields << ownership_field.to_sym if !ownership_field.nil?
|
171
|
+
|
172
|
+
|
173
|
+
begin
|
174
|
+
@columns = object.columns.map(&:name).map(&:to_sym).reject{|field| exclude_fields.include?(field) }
|
175
|
+
rescue StandardError => e
|
176
|
+
puts "Ooops... it looks like is an object for #{class_name}. Please create the database table with fields first. "
|
177
|
+
exit
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
def formats
|
185
|
+
[format]
|
186
|
+
end
|
187
|
+
|
188
|
+
def format
|
189
|
+
nil
|
190
|
+
end
|
191
|
+
|
192
|
+
def copy_controller_and_spec_files
|
193
|
+
@default_colspan = @columns.size
|
194
|
+
|
195
|
+
unless @specs_only
|
196
|
+
template "controller.rb", File.join("app/controllers#{namespace_with_dash}", "#{plural}_controller.rb")
|
197
|
+
if @namespace && defined?(controller_descends_from) == nil
|
198
|
+
template "base_controller.rb", File.join("app/controllers#{namespace_with_dash}", "base_controller.rb")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
unless @no_specs
|
203
|
+
template "controller_spec.rb", File.join("spec/controllers#{namespace_with_dash}", "#{plural}_controller_spec.rb")
|
204
|
+
end
|
205
|
+
|
206
|
+
template "_errors.haml", File.join("app/views#{namespace_with_dash}", "_errors.haml")
|
207
|
+
end
|
208
|
+
|
209
|
+
def list_column_headings
|
210
|
+
@columns.map(&:to_s).map{|col_name| ' .col ' + col_name.humanize}.join("\n")
|
211
|
+
end
|
212
|
+
|
213
|
+
def columns_spec_with_sample_data
|
214
|
+
@columns.map { |c|
|
215
|
+
if eval("#{singular_class}.columns_hash['#{c}']").nil?
|
216
|
+
byebug
|
217
|
+
end
|
218
|
+
type = eval("#{singular_class}.columns_hash['#{c}']").type
|
219
|
+
random_data = case type
|
220
|
+
when :integer
|
221
|
+
rand(1...1000)
|
222
|
+
when :string
|
223
|
+
FFaker::AnimalUS.common_name
|
224
|
+
when :text
|
225
|
+
FFaker::AnimalUS.common_name
|
226
|
+
when :datetime
|
227
|
+
Time.now + rand(1..5).days
|
228
|
+
end
|
229
|
+
c.to_s + ": '" + random_data.to_s + "'"
|
230
|
+
}.join(", ")
|
231
|
+
end
|
232
|
+
|
233
|
+
def object_parent_mapping_as_argument_for_specs
|
234
|
+
if @nested_args.any?
|
235
|
+
", " + @nested_args.last + ": " + @nested_args.last
|
236
|
+
elsif @auth
|
237
|
+
", #{@auth_identifier}: #{@auth}"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def objest_nest_factory_setup
|
242
|
+
res = ""
|
243
|
+
if @auth
|
244
|
+
last_parent = ", #{@auth_identifier}: #{@auth}"
|
245
|
+
end
|
246
|
+
|
247
|
+
@nested_args.each do |arg|
|
248
|
+
res << " let(:#{arg}) {create(:#{arg} #{last_parent} )}\n"
|
249
|
+
last_parent = ", #{arg}: #{arg}"
|
250
|
+
end
|
251
|
+
res
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
def objest_nest_params_by_id_for_specs
|
256
|
+
@nested_args.map{|arg|
|
257
|
+
"#{arg}_id: #{arg}.id"
|
258
|
+
}.join(",\n ")
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
def controller_class_name
|
263
|
+
res = ""
|
264
|
+
res << @namespace.titleize + "::" if @namespace
|
265
|
+
res << plural.titleize.gsub(" ", "") + "Controller"
|
266
|
+
res
|
267
|
+
end
|
268
|
+
|
269
|
+
def singular_name
|
270
|
+
@singular
|
271
|
+
end
|
272
|
+
|
273
|
+
def plural_name
|
274
|
+
plural
|
275
|
+
end
|
276
|
+
|
277
|
+
def auth_identifier
|
278
|
+
@auth_identifier
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
def path_helper_full
|
283
|
+
"#{@namespace+"_" if @namespace}#{(@nested_args.join("_") + "_" if @nested_args.any?)}#{singular}_path"
|
284
|
+
end
|
285
|
+
|
286
|
+
def path_helper_args
|
287
|
+
if @nested_args.any?
|
288
|
+
[(@nested_args).collect{|a| "@#{a}"} , singular].join(",")
|
289
|
+
else
|
290
|
+
singular
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def path_helper_singular
|
295
|
+
"#{@namespace+"_" if @namespace}#{(@nested_args.join("_") + "_" if @nested_args.any?)}#{singular}_path"
|
296
|
+
end
|
297
|
+
|
298
|
+
def path_helper_plural
|
299
|
+
"#{@namespace+"_" if @namespace}#{(@nested_args.join("_") + "_" if @nested_args.any?)}#{plural}_path"
|
300
|
+
end
|
301
|
+
|
302
|
+
def path_arity
|
303
|
+
res = ""
|
304
|
+
if @nested_args.any?
|
305
|
+
res << nested_objects_arity + ", "
|
306
|
+
end
|
307
|
+
res << "@" + singular
|
308
|
+
end
|
309
|
+
|
310
|
+
def line_path_partial
|
311
|
+
"#{@namespace+"/" if @namespace}#{plural}/line"
|
312
|
+
end
|
313
|
+
|
314
|
+
def nested_assignments
|
315
|
+
@nested_args.map{|a| "#{a}: @#{a}"}.join(", ") #metaprgramming into Ruby hash
|
316
|
+
end
|
317
|
+
|
318
|
+
def nested_assignments_with_leading_comma
|
319
|
+
if @nested_args.any?
|
320
|
+
", #{nested_assignments}"
|
321
|
+
else
|
322
|
+
""
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def nested_objects_arity
|
327
|
+
@nested_args.map{|a| "@#{a}"}.join(", ")
|
328
|
+
end
|
329
|
+
|
330
|
+
def nested_arity_for_path
|
331
|
+
[@nested_args[0..-1].collect{|a| "@#{a}"}].join(", ") #metaprgramming into arity for the Rails path helper
|
332
|
+
end
|
333
|
+
|
334
|
+
def object_scope
|
335
|
+
if @auth
|
336
|
+
if @nested_args.none?
|
337
|
+
@auth + ".#{plural}"
|
338
|
+
else
|
339
|
+
"@" + @nested_args.last + ".#{plural}"
|
340
|
+
end
|
341
|
+
else
|
342
|
+
@singular_class
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
def all_objects_root
|
348
|
+
if @auth
|
349
|
+
if @self_auth
|
350
|
+
@singular_class + ".where(id: #{@auth}.id)"
|
351
|
+
elsif @nested_args.none?
|
352
|
+
@auth + ".#{plural}"
|
353
|
+
else
|
354
|
+
"@" + @nested_args.last + ".#{plural}"
|
355
|
+
end
|
356
|
+
else
|
357
|
+
@singular_class + ".all"
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def any_nested?
|
362
|
+
@nested_args.any?
|
363
|
+
end
|
364
|
+
|
365
|
+
def all_objects_variable
|
366
|
+
|
367
|
+
# needs the authenticated root user
|
368
|
+
# "#{@auth}.#{ @nested_args.map{|a| "#{@nested_args_plural[a]}.find(@#{a})"}.join('.') + "." if @nested_args.any?}#{plural}"
|
369
|
+
|
370
|
+
all_objects_root + ".page(params[:page])"
|
371
|
+
|
372
|
+
end
|
373
|
+
|
374
|
+
def auth_object
|
375
|
+
@auth
|
376
|
+
end
|
377
|
+
|
378
|
+
|
379
|
+
def no_devise_installed
|
380
|
+
!Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }['devise']
|
381
|
+
end
|
382
|
+
|
383
|
+
|
384
|
+
def copy_view_files
|
385
|
+
return if @specs_only
|
386
|
+
haml_views.each do |view|
|
387
|
+
formats.each do |format|
|
388
|
+
filename = cc_filename_with_extensions(view, "haml")
|
389
|
+
template filename, File.join("app/views#{namespace_with_dash}", controller_file_path, filename)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
turbo_stream_views.each do |view|
|
394
|
+
formats.each do |format|
|
395
|
+
filename = cc_filename_with_extensions(view, 'turbo_stream.haml')
|
396
|
+
template filename, File.join("app/views#{namespace_with_dash}", controller_file_path, filename)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def namespace_with_dash
|
402
|
+
if @namespace
|
403
|
+
"/#{@namespace}"
|
404
|
+
else
|
405
|
+
""
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def namespace_with_trailing_dash
|
410
|
+
if @namespace
|
411
|
+
"#{@namespace}/"
|
412
|
+
else
|
413
|
+
""
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def haml_views
|
418
|
+
res = %w(index edit new _form _line _list _new_button _show)
|
419
|
+
|
420
|
+
res
|
421
|
+
end
|
422
|
+
|
423
|
+
def turbo_stream_views
|
424
|
+
res = %w(create destroy edit update)
|
425
|
+
end
|
426
|
+
|
427
|
+
def handler
|
428
|
+
:erb
|
429
|
+
end
|
430
|
+
|
431
|
+
def model_has_strings?
|
432
|
+
false
|
433
|
+
end
|
434
|
+
|
435
|
+
|
436
|
+
def model_search_fields # an array of fields we can search on
|
437
|
+
[]
|
438
|
+
end
|
439
|
+
|
440
|
+
def all_form_fields
|
441
|
+
col_identifier = " .col"
|
442
|
+
col_spaces_prepend = " "
|
443
|
+
|
444
|
+
res = @columns.map { |col|
|
445
|
+
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
446
|
+
limit = eval("#{singular_class}.columns_hash['#{col}']").limit
|
447
|
+
sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
|
448
|
+
|
449
|
+
case type
|
450
|
+
when :integer
|
451
|
+
# look for a belongs_to on this object
|
452
|
+
if col.to_s.ends_with?("_id")
|
453
|
+
# guess the association name label
|
454
|
+
|
455
|
+
|
456
|
+
assoc_name = col.to_s.gsub("_id","")
|
457
|
+
assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
|
458
|
+
if assoc.nil?
|
459
|
+
puts "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
|
460
|
+
exit
|
461
|
+
end
|
462
|
+
|
463
|
+
|
464
|
+
assoc_class = eval(assoc.class_name)
|
465
|
+
|
466
|
+
if assoc_class.column_names.include?("name")
|
467
|
+
display_column = "name"
|
468
|
+
elsif assoc_class.column_names.include?("to_label")
|
469
|
+
display_column = "to_label"
|
470
|
+
elsif assoc_class.column_names.include?("full_name")
|
471
|
+
display_column = "full_name"
|
472
|
+
elsif assoc_class.column_names.include?("display_name")
|
473
|
+
display_column = "display_name"
|
474
|
+
elsif assoc_class.column_names.include?("email")
|
475
|
+
display_column = "email"
|
476
|
+
else
|
477
|
+
puts "*** Oops: Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, or 5) email directly on your #{assoc.class_name} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
|
478
|
+
end
|
479
|
+
|
480
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{assoc_name.to_s})}\"}
|
481
|
+
#{col_spaces_prepend}= f.collection_select(:#{col.to_s}, #{assoc_class}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col.to_s} }, class: 'form-control')
|
482
|
+
#{col_spaces_prepend} %label.small.form-text.text-muted
|
483
|
+
#{col_spaces_prepend} #{col.to_s.humanize}"
|
484
|
+
|
485
|
+
else
|
486
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if @#{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
487
|
+
#{col_spaces_prepend}= f.text_field :#{col.to_s}, value: #{singular}.#{col.to_s}, class: 'form-control', size: 4, type: 'number'
|
488
|
+
#{col_spaces_prepend} %label.form-text
|
489
|
+
#{col_spaces_prepend} #{col.to_s.humanize}\n"
|
490
|
+
end
|
491
|
+
when :string
|
492
|
+
limit ||= 256
|
493
|
+
if limit <= 256
|
494
|
+
field_output(col, nil, limit, col_identifier)
|
495
|
+
else
|
496
|
+
text_area_output(col, limit, col_identifier)
|
497
|
+
end
|
498
|
+
|
499
|
+
when :text
|
500
|
+
limit ||= 256
|
501
|
+
if limit <= 256
|
502
|
+
field_output(col, nil, limit, col_identifier)
|
503
|
+
else
|
504
|
+
text_area_output(col, limit, col_identifier)
|
505
|
+
end
|
506
|
+
when :float
|
507
|
+
limit ||= 256
|
508
|
+
field_output(col, nil, limit, col_identifier)
|
509
|
+
|
510
|
+
|
511
|
+
when :datetime
|
512
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
513
|
+
#{col_spaces_prepend}= datetime_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
|
514
|
+
when :date
|
515
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
516
|
+
#{col_spaces_prepend}= date_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
|
517
|
+
when :time
|
518
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
519
|
+
#{col_spaces_prepend}= time_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
|
520
|
+
when :boolean
|
521
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
522
|
+
#{col_spaces_prepend}%span
|
523
|
+
#{col_spaces_prepend} #{col.to_s.humanize}
|
524
|
+
#{col_spaces_prepend}= f.radio_button(:#{col.to_s}, '0', checked: #{singular}.#{col.to_s} ? '' : 'checked')
|
525
|
+
#{col_spaces_prepend}= f.label(:#{col.to_s}, value: 'No', for: '#{singular}_#{col.to_s}_0')
|
526
|
+
|
527
|
+
#{col_spaces_prepend}= f.radio_button(:#{col.to_s}, '1', checked: #{singular}.#{col.to_s} ? 'checked' : '')
|
528
|
+
#{col_spaces_prepend}= f.label(:#{col.to_s}, value: 'Yes', for: '#{singular}_#{col.to_s}_1')
|
529
|
+
"
|
530
|
+
end
|
531
|
+
|
532
|
+
}.join("\n")
|
533
|
+
return res
|
534
|
+
end
|
535
|
+
|
536
|
+
|
537
|
+
def all_line_fields
|
538
|
+
columns = @columns.count + 1
|
539
|
+
perc_width = (100/columns).floor
|
540
|
+
|
541
|
+
col_identifer = ".col"
|
542
|
+
@columns.map { |col|
|
543
|
+
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
544
|
+
limit = eval("#{singular_class}.columns_hash['#{col}']").limit
|
545
|
+
sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
|
546
|
+
|
547
|
+
case type
|
548
|
+
when :integer
|
549
|
+
# look for a belongs_to on this object
|
550
|
+
if col.to_s.ends_with?("_id")
|
551
|
+
|
552
|
+
assoc_name = col.to_s.gsub("_id","")
|
553
|
+
|
554
|
+
|
555
|
+
assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
|
556
|
+
|
557
|
+
if assoc.nil?
|
558
|
+
puts "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
|
559
|
+
exit
|
560
|
+
end
|
561
|
+
|
562
|
+
assoc_class = eval(assoc.class_name)
|
563
|
+
|
564
|
+
if assoc_class.column_names.include?("name")
|
565
|
+
display_column = "name"
|
566
|
+
elsif assoc_class.column_names.include?("to_label")
|
567
|
+
display_column = "to_label"
|
568
|
+
elsif assoc_class.column_names.include?("full_name")
|
569
|
+
display_column = "full_name"
|
570
|
+
elsif assoc_class.column_names.include?("display_name")
|
571
|
+
display_column = "display_name"
|
572
|
+
elsif assoc_class.column_names.include?("email")
|
573
|
+
display_column = "email"
|
574
|
+
else
|
575
|
+
puts "*** Oops: Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, or 5) email directly on your #{assoc.class_name} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
|
576
|
+
end
|
577
|
+
|
578
|
+
"#{col_identifer}
|
579
|
+
= #{singular}.#{assoc.name.to_s}.try(:#{display_column}) || '<span class=\"content alert-danger\">MISSING</span>'.html_safe"
|
580
|
+
|
581
|
+
else
|
582
|
+
"#{col_identifer}
|
583
|
+
= #{singular}.#{col}"
|
584
|
+
end
|
585
|
+
when :float
|
586
|
+
width = (limit && limit < 40) ? limit : (40)
|
587
|
+
"#{col_identifer}
|
588
|
+
= #{singular}.#{col}"
|
589
|
+
|
590
|
+
when :string
|
591
|
+
width = (limit && limit < 40) ? limit : (40)
|
592
|
+
"#{col_identifer}
|
593
|
+
= #{singular}.#{col}"
|
594
|
+
when :text
|
595
|
+
"#{col_identifer}
|
596
|
+
= #{singular}.#{col}"
|
597
|
+
when :datetime
|
598
|
+
"#{col_identifer}
|
599
|
+
- unless #{singular}.#{col}.nil?
|
600
|
+
= #{singular}.#{col}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ') + timezonize(current_timezone)
|
601
|
+
- else
|
602
|
+
%span.alert-danger
|
603
|
+
MISSING
|
604
|
+
"
|
605
|
+
when :date
|
606
|
+
".cell
|
607
|
+
- unless #{singular}.#{col}.nil?
|
608
|
+
= #{singular}.#{col}
|
609
|
+
- else
|
610
|
+
%span.alert-danger
|
611
|
+
MISSING
|
612
|
+
"
|
613
|
+
when :time
|
614
|
+
"#{col_identifer}
|
615
|
+
- unless #{singular}.#{col}.nil?
|
616
|
+
= #{singular}.#{col}.in_time_zone(current_timezone).strftime('%l:%M %p ') + timezonize(current_timezone)
|
617
|
+
- else
|
618
|
+
%span.alert-danger
|
619
|
+
MISSING
|
620
|
+
"
|
621
|
+
when :boolean
|
622
|
+
"#{col_identifer}
|
623
|
+
- if #{singular}.#{col}.nil?
|
624
|
+
%span.alert-danger
|
625
|
+
MISSING
|
626
|
+
- elsif #{singular}.#{col}
|
627
|
+
YES
|
628
|
+
- else
|
629
|
+
NO
|
630
|
+
"
|
631
|
+
end
|
632
|
+
}.join("\n")
|
633
|
+
end
|
634
|
+
|
635
|
+
|
636
|
+
def controller_descends_from
|
637
|
+
if defined?(@namespace.titlecase + "::BaseController")
|
638
|
+
@namespace.titlecase + "::BaseController"
|
639
|
+
else
|
640
|
+
"ApplicationController"
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
|
645
|
+
def destroy_action
|
646
|
+
return false if @self_auth
|
647
|
+
return !@no_delete
|
648
|
+
end
|
649
|
+
|
650
|
+
def create_action
|
651
|
+
return false if @self_auth
|
652
|
+
return !@no_create
|
653
|
+
end
|
654
|
+
|
655
|
+
def namespace_with_slash
|
656
|
+
if @namespace
|
657
|
+
"#{@namespace}/"
|
658
|
+
else
|
659
|
+
""
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
private # thor does something fancy like sending the class all of its own methods during some strange run sequence
|
664
|
+
# does not like public methods
|
665
|
+
|
666
|
+
def cc_filename_with_extensions(name, file_format = format)
|
667
|
+
[name, file_format].compact.join(".")
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
end
|
672
|
+
|
673
|
+
|
674
|
+
|