hot-glue 0.5.11 → 0.5.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +17 -2
- data/README.md +13 -6
- data/lib/generators/hot_glue/default_config_loader.rb +12 -0
- data/lib/generators/hot_glue/field_factory.rb +2 -0
- data/lib/generators/hot_glue/fields/association_field.rb +1 -1
- data/lib/generators/hot_glue/fields/attachment_field.rb +27 -0
- data/lib/generators/hot_glue/fields/field.rb +1 -1
- data/lib/generators/hot_glue/hot_glue.rb +5 -0
- data/lib/generators/hot_glue/layout/builder.rb +38 -55
- data/lib/generators/hot_glue/markup_templates/erb.rb +9 -15
- data/lib/generators/hot_glue/scaffold_generator.rb +953 -1010
- data/lib/generators/hot_glue/templates/erb/_list.erb +1 -2
- data/lib/generators/hot_glue/templates/erb/_show.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/edit.erb +35 -6
- data/lib/hot-glue.rb +78 -0
- data/lib/hotglue/version.rb +1 -1
- data/script/test +2 -4
- metadata +4 -2
@@ -1,4 +1,6 @@
|
|
1
|
+
|
1
2
|
require 'rails/generators/erb/scaffold/scaffold_generator'
|
3
|
+
require_relative './default_config_loader'
|
2
4
|
require 'ffaker'
|
3
5
|
require_relative './fields/field'
|
4
6
|
require_relative './field_factory'
|
@@ -10,1225 +12,1167 @@ require_relative './layout_strategy/bootstrap'
|
|
10
12
|
require_relative './layout_strategy/hot_glue'
|
11
13
|
require_relative './layout_strategy/tailwind'
|
12
14
|
|
13
|
-
module HotGlue
|
14
|
-
class Error < StandardError
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.construct_downnest_object(input)
|
18
|
-
res = input.split(",").map { |child|
|
19
|
-
child_name = child.gsub("+","")
|
20
|
-
extra_size = child.count("+")
|
21
|
-
{child_name => 4+extra_size}
|
22
|
-
}
|
23
|
-
Hash[*res.collect{|hash| hash.collect{|key,value| [key,value].flatten}.flatten}.flatten]
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.optionalized_ternary(namespace: nil,
|
27
|
-
target:,
|
28
|
-
nested_set:,
|
29
|
-
modifier: "",
|
30
|
-
with_params: false,
|
31
|
-
top_level: false,
|
32
|
-
put_form: false)
|
33
|
-
instance_sym = top_level ? "@" : ""
|
34
|
-
if nested_set.nil? || nested_set.empty?
|
35
|
-
return modifier + "#{(namespace + '_') if namespace}#{target}_path" + (("(#{instance_sym}#{target})" if put_form) || "")
|
36
|
-
elsif nested_set[0][:optional] == false
|
37
|
-
return modifier + ((namespace + "_" if namespace) || "") + nested_set.collect{|x|
|
38
|
-
x[:singular] + "_"
|
39
|
-
}.join() + target + "_path" + (("(#{nested_set.collect{
|
40
|
-
|x| instance_sym + x[:singular] }.join(",")
|
41
|
-
}#{ put_form ? ',' + instance_sym + target : '' })" if with_params) || "")
|
42
|
-
|
43
|
-
else
|
44
|
-
# copy the first item, make a ternery in this cycle, and recursively move to both the
|
45
|
-
# is present path and the is optional path
|
46
|
-
|
47
|
-
nonoptional = nested_set[0].dup
|
48
|
-
nonoptional[:optional] = false
|
49
|
-
rest_of_nest = nested_set[1..-1]
|
50
|
-
|
51
|
-
is_present_path = HotGlue.optionalized_ternary(
|
52
|
-
namespace: namespace,
|
53
|
-
target: target,
|
54
|
-
modifier: modifier,
|
55
|
-
top_level: top_level,
|
56
|
-
with_params: with_params,
|
57
|
-
put_form: put_form,
|
58
|
-
nested_set: [nonoptional, *rest_of_nest])
|
59
|
-
|
60
|
-
is_missing_path = HotGlue.optionalized_ternary(
|
61
|
-
namespace: namespace,
|
62
|
-
target: target,
|
63
|
-
modifier: modifier,
|
64
|
-
top_level: top_level,
|
65
|
-
with_params: with_params,
|
66
|
-
put_form: put_form,
|
67
|
-
nested_set: rest_of_nest )
|
68
|
-
return "defined?(#{instance_sym + nested_set[0][:singular]}2) ? #{is_present_path} : #{is_missing_path}"
|
69
|
-
end
|
70
|
-
end
|
71
15
|
|
72
|
-
def self.derrive_reference_name(thing_as_string)
|
73
|
-
assoc_class = eval(thing_as_string)
|
74
16
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
17
|
+
class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
18
|
+
include DefaultConfigLoader
|
19
|
+
hook_for :form_builder, :as => :scaffold
|
20
|
+
|
21
|
+
source_root File.expand_path('templates', __dir__)
|
22
|
+
attr_accessor :alt_lookups, :attachments, :auth,
|
23
|
+
:big_edit, :bootstrap_column_width,
|
24
|
+
:columns,
|
25
|
+
:downnest_children, :downnest_object,
|
26
|
+
:button_icons,
|
27
|
+
:hawk_keys, :layout_object,
|
28
|
+
:nest_with,
|
29
|
+
:path, :plural,
|
30
|
+
:sample_file_path, :singular, :singular_class, :smart_layout,
|
31
|
+
:stacked_downnesting, :update_show_only
|
32
|
+
|
33
|
+
class_option :singular, type: :string, default: nil
|
34
|
+
class_option :plural, type: :string, default: nil
|
35
|
+
class_option :singular_class, type: :string, default: nil
|
36
|
+
class_option :nest, type: :string, default: nil # DEPRECATED —— DO NOT USE
|
37
|
+
class_option :nested, type: :string, default: ""
|
38
|
+
|
39
|
+
class_option :namespace, type: :string, default: nil
|
40
|
+
class_option :auth, type: :string, default: nil
|
41
|
+
class_option :auth_identifier, type: :string, default: nil
|
42
|
+
class_option :exclude, type: :string, default: ""
|
43
|
+
class_option :include, type: :string, default: ""
|
44
|
+
class_option :god, type: :boolean, default: false
|
45
|
+
class_option :gd, type: :boolean, default: false # alias for god
|
46
|
+
|
47
|
+
class_option :specs_only, type: :boolean, default: false
|
48
|
+
class_option :no_specs, type: :boolean, default: false
|
49
|
+
class_option :no_delete, type: :boolean, default: false
|
50
|
+
class_option :no_create, type: :boolean, default: false
|
51
|
+
class_option :no_edit, type: :boolean, default: false
|
52
|
+
class_option :no_list, type: :boolean, default: false
|
53
|
+
class_option :no_paginate, type: :boolean, default: false
|
54
|
+
class_option :big_edit, type: :boolean, default: false
|
55
|
+
class_option :show_only, type: :string, default: ""
|
56
|
+
class_option :update_show_only, type: :string, default: ""
|
57
|
+
|
58
|
+
class_option :ujs_syntax, type: :boolean, default: nil
|
59
|
+
class_option :downnest, type: :string, default: nil
|
60
|
+
class_option :magic_buttons, type: :string, default: nil
|
61
|
+
class_option :small_buttons, type: :boolean, default: nil
|
62
|
+
class_option :display_list_after_update, type: :boolean, default: false
|
63
|
+
class_option :smart_layout, type: :boolean, default: false
|
64
|
+
class_option :markup, type: :string, default: nil # deprecated -- use in app config instead
|
65
|
+
class_option :layout, type: :string, default: nil # if used here it will override what is in the config
|
66
|
+
class_option :hawk, type: :string, default: nil
|
67
|
+
class_option :with_turbo_streams, type: :boolean, default: false
|
68
|
+
|
69
|
+
class_option :label, default: nil
|
70
|
+
class_option :list_label_heading, default: nil
|
71
|
+
class_option :new_button_label, default: nil
|
72
|
+
class_option :new_form_heading, default: nil
|
73
|
+
|
74
|
+
class_option :no_list_label, type: :boolean, default: false
|
75
|
+
class_option :no_list_heading, type: :boolean, default: false
|
76
|
+
|
77
|
+
# determines if the labels show up BEFORE or AFTER on the NEW/EDIT (form)
|
78
|
+
class_option :form_labels_position, type: :string, default: 'after' # choices are before, after, omit
|
79
|
+
class_option :form_placeholder_labels, type: :boolean, default: false # puts the field names into the placeholder labels
|
80
|
+
|
81
|
+
# determines if labels appear within the rows of the VIEWABLE list (does NOT affect the list heading)
|
82
|
+
class_option :inline_list_labels, default: 'omit' # choices are before, after, omit
|
83
|
+
class_option :factory_creation, default: ''
|
84
|
+
class_option :alt_foreign_key_lookup, default: '' #
|
85
|
+
class_option :attachments, default: ''
|
86
|
+
class_option :stacked_downnesting, default: false
|
87
|
+
class_option :bootstrap_column_width, default: nil #must be nil to detect if user has not passed
|
88
|
+
class_option :button_icons, default: nil
|
89
|
+
|
90
|
+
def initialize(*meta_args)
|
91
|
+
super
|
92
|
+
|
93
|
+
begin
|
94
|
+
@the_object = eval(class_name)
|
95
|
+
rescue StandardError => e
|
96
|
+
message = "*** Oops: It looks like there is no object for #{class_name}. Please define the object + database table first."
|
97
|
+
puts message
|
98
|
+
raise(HotGlue::Error, message)
|
99
|
+
end
|
100
|
+
|
101
|
+
@meta_args = meta_args
|
102
|
+
|
103
|
+
if options['specs_only'] && options['no_specs']
|
104
|
+
raise(HotGlue::Error, "*** 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. Aborting.")
|
105
|
+
end
|
106
|
+
|
107
|
+
if !options['exclude'].empty? && !options['include'].empty?
|
108
|
+
exit_message = "*** Oops: You seem to have specified both --include and --exclude. Please use one or the other. Aborting."
|
109
|
+
puts exit_message
|
110
|
+
|
111
|
+
raise(HotGlue::Error, exit_message)
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
if @stimulus_syntax.nil?
|
116
|
+
@stimulus_syntax = true
|
117
|
+
end
|
118
|
+
|
119
|
+
if !options['markup'].nil?
|
120
|
+
message = "Using --markup flag in the generator is deprecated; instead, use a file at config/hot_glue.yml with a key markup set to `erb` or `haml`"
|
121
|
+
raise(HotGlue::Error, message)
|
122
|
+
end
|
123
|
+
|
124
|
+
@markup = get_default_from_config(key: :markup)
|
125
|
+
@sample_file_path = get_default_from_config(key: :sample_file_path)
|
126
|
+
@bootstrap_column_width ||= get_default_from_config(key: :bootstrap_column_width) || 2
|
127
|
+
|
128
|
+
if options['layout']
|
129
|
+
layout = options['layout']
|
130
|
+
else
|
131
|
+
layout = get_default_from_config(key: :layout)
|
154
132
|
|
155
|
-
|
156
|
-
|
157
|
-
rescue StandardError => e
|
158
|
-
message = "*** Oops: It looks like there is no object for #{class_name}. Please define the object + database table first."
|
159
|
-
puts message
|
160
|
-
raise(HotGlue::Error, message)
|
133
|
+
if !['hotglue', 'bootstrap', 'tailwind'].include? layout
|
134
|
+
raise "Invalid option #{layout} in Hot glue config (config/hot_glue.yml). You must either use --layout= when generating or have a file config/hotglue.yml; specify layout as either 'hotglue' or 'bootstrap'"
|
161
135
|
end
|
136
|
+
end
|
162
137
|
|
163
|
-
|
138
|
+
@button_icons = get_default_from_config(key: :button_icons) || 'none'
|
164
139
|
|
165
|
-
|
166
|
-
|
140
|
+
@layout_strategy =
|
141
|
+
case layout
|
142
|
+
when 'bootstrap'
|
143
|
+
LayoutStrategy::Bootstrap.new(self)
|
144
|
+
when 'tailwind'
|
145
|
+
LayoutStrategy::Tailwind.new(self)
|
146
|
+
when 'hotglue'
|
147
|
+
LayoutStrategy::HotGlue.new(self)
|
167
148
|
end
|
168
149
|
|
169
|
-
|
170
|
-
|
171
|
-
puts exit_message
|
150
|
+
args = meta_args[0]
|
151
|
+
@singular = args.first.tableize.singularize # should be in form hello_world
|
172
152
|
|
173
|
-
|
174
|
-
|
153
|
+
if @singular.include?("/")
|
154
|
+
@singular = @singular.split("/").last
|
155
|
+
end
|
175
156
|
|
157
|
+
@plural = options['plural'] || @singular.pluralize # respects what you set in inflections.rb, to override, use plural option
|
158
|
+
@namespace = options['namespace'] || nil
|
159
|
+
use_controller_name = plural.titleize.gsub(" ", "")
|
160
|
+
@controller_build_name = (( @namespace.titleize.gsub(" ","") + "::" if @namespace) || "") + use_controller_name + "Controller"
|
161
|
+
@controller_build_folder = use_controller_name.underscore
|
162
|
+
@controller_build_folder_singular = singular
|
176
163
|
|
177
|
-
|
178
|
-
|
179
|
-
end
|
164
|
+
@auth = options['auth'] || "current_user"
|
165
|
+
@auth_identifier = options['auth_identifier'] || (! @god && @auth.gsub("current_", "")) || nil
|
180
166
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
167
|
+
if options['nest']
|
168
|
+
raise HotGlue::Error, "STOP: the flag --nest has been replaced with --nested; please re-run using the --nested flag"
|
169
|
+
end
|
170
|
+
@nested = (!options['nested'].empty? && options['nested']) || nil
|
171
|
+
@singular_class = args.first # note this is the full class name with a model namespace
|
185
172
|
|
186
|
-
|
187
|
-
@markup = yaml_from_config[:markup]
|
188
|
-
@sample_file_path = yaml_from_config[:sample_file_path]
|
173
|
+
setup_attachments
|
189
174
|
|
190
|
-
|
191
|
-
|
192
|
-
else
|
193
|
-
layout = yaml_from_config[:layout]
|
175
|
+
@exclude_fields = []
|
176
|
+
@exclude_fields += options['exclude'].split(",").collect(&:to_sym)
|
194
177
|
|
195
|
-
|
196
|
-
|
197
|
-
end
|
198
|
-
end
|
178
|
+
if !options['include'].empty?
|
179
|
+
@include_fields = []
|
199
180
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
LayoutStrategy::Bootstrap.new(self)
|
204
|
-
when 'tailwind'
|
205
|
-
LayoutStrategy::Tailwind.new(self)
|
206
|
-
when 'hotglue'
|
207
|
-
LayoutStrategy::HotGlue.new(self)
|
208
|
-
end
|
181
|
+
# semicolon to denote layout columns; commas separate fields
|
182
|
+
@include_fields += options['include'].split(":").collect{|x|x.split(",")}.flatten.collect(&:to_sym)
|
183
|
+
end
|
209
184
|
|
210
|
-
|
211
|
-
|
185
|
+
@show_only = []
|
186
|
+
if !options['show_only'].empty?
|
187
|
+
@show_only += options['show_only'].split(",").collect(&:to_sym)
|
188
|
+
end
|
212
189
|
|
213
|
-
|
214
|
-
|
215
|
-
|
190
|
+
@update_show_only = []
|
191
|
+
if !options['update_show_only'].empty?
|
192
|
+
@update_show_only += options['update_show_only'].split(",").collect(&:to_sym)
|
193
|
+
end
|
216
194
|
|
217
|
-
@plural = options['plural'] || @singular.pluralize # respects what you set in inflections.rb, to override, use plural option
|
218
|
-
@namespace = options['namespace'] || nil
|
219
|
-
use_controller_name = plural.titleize.gsub(" ", "")
|
220
|
-
@controller_build_name = (( @namespace.titleize.gsub(" ","") + "::" if @namespace) || "") + use_controller_name + "Controller"
|
221
|
-
@controller_build_folder = use_controller_name.underscore
|
222
|
-
@controller_build_folder_singular = singular
|
223
195
|
|
224
|
-
|
225
|
-
|
196
|
+
# syntax should be xyz_id{xyz_email},abc_id{abc_email}
|
197
|
+
# instead of a drop-down for the foreign entity, a text field will be presented
|
198
|
+
# You must ALSO use a factory that contains a parameter of the same name as the 'value' (for example, `xyz_email`)
|
226
199
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
200
|
+
alt_lookups_entry = options['alt_foreign_key_lookup'].split(",")
|
201
|
+
@alt_lookups = {}
|
202
|
+
@alt_foreign_key_lookup = alt_lookups_entry.each do |setting|
|
203
|
+
setting =~ /(.*){(.*)}/
|
204
|
+
key, lookup_as = $1, $2
|
205
|
+
assoc = eval("#{class_name}.reflect_on_association(:#{key.to_s.gsub("_id","")}).class_name")
|
232
206
|
|
233
|
-
|
207
|
+
data = {lookup_as: lookup_as.gsub("+",""),
|
208
|
+
assoc: assoc,
|
209
|
+
with_create: lookup_as.include?("+")}
|
210
|
+
@alt_lookups[key] = data
|
211
|
+
end
|
234
212
|
|
235
|
-
|
236
|
-
@exclude_fields += options['exclude'].split(",").collect(&:to_sym)
|
213
|
+
puts "------ ALT LOOKUPS for #{@alt_lookups}"
|
237
214
|
|
238
|
-
|
239
|
-
|
215
|
+
@update_alt_lookups = @alt_lookups.collect{|key, value|
|
216
|
+
@update_show_only.include?(key) ?
|
217
|
+
{ key: value }
|
218
|
+
: nil}.compact
|
240
219
|
|
241
|
-
|
242
|
-
|
243
|
-
end
|
220
|
+
@label = options['label'] || ( eval("#{class_name}.class_variable_defined?(:@@table_label_singular)") ? eval("#{class_name}.class_variable_get(:@@table_label_singular)") : singular.gsub("_", " ").titleize )
|
221
|
+
@list_label_heading = options['list_label_heading'] || ( eval("#{class_name}.class_variable_defined?(:@@table_label_plural)") ? eval("#{class_name}.class_variable_get(:@@table_label_plural)") : plural.gsub("_", " ").upcase )
|
244
222
|
|
245
|
-
|
246
|
-
|
247
|
-
@show_only += options['show_only'].split(",").collect(&:to_sym)
|
248
|
-
end
|
223
|
+
@new_button_label = options['new_button_label'] || ( eval("#{class_name}.class_variable_defined?(:@@table_label_singular)") ? "New " + eval("#{class_name}.class_variable_get(:@@table_label_singular)") : "New " + singular.gsub("_", " ").titleize )
|
224
|
+
@new_form_heading = options['new_form_heading'] || "New #{@label}"
|
249
225
|
|
250
|
-
@update_show_only = []
|
251
|
-
if !options['update_show_only'].empty?
|
252
|
-
@update_show_only += options['update_show_only'].split(",").collect(&:to_sym)
|
253
|
-
end
|
254
226
|
|
255
227
|
|
256
|
-
|
257
|
-
|
258
|
-
|
228
|
+
setup_hawk_keys
|
229
|
+
@form_placeholder_labels = options['form_placeholder_labels'] # true or false
|
230
|
+
@inline_list_labels = options['inline_list_labels'] || 'omit' # 'before','after','omit'
|
259
231
|
|
260
|
-
alt_lookups_entry = options['alt_foreign_key_lookup'].split(",")
|
261
|
-
@alt_lookups = {}
|
262
|
-
@alt_foreign_key_lookup = alt_lookups_entry.each do |setting|
|
263
|
-
setting =~ /(.*){(.*)}/
|
264
|
-
key, lookup_as = $1, $2
|
265
|
-
assoc = eval("#{class_name}.reflect_on_association(:#{key.to_s.gsub("_id","")}).class_name")
|
266
232
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
end
|
233
|
+
@form_labels_position = options['form_labels_position']
|
234
|
+
if !['before','after','omit'].include?(@form_labels_position)
|
235
|
+
raise HotGlue::Error, "You passed '#{@form_labels_position}' as the setting for --form-labels-position but the only allowed options are before, after (default), and omit"
|
236
|
+
end
|
272
237
|
|
273
|
-
|
238
|
+
if !['before','after','omit'].include?(@inline_list_labels)
|
239
|
+
raise HotGlue::Error, "You passed '#{@inline_list_labels}' as the setting for --inline-list-labels but the only allowed options are before, after, and omit (default)"
|
240
|
+
end
|
274
241
|
|
275
|
-
@update_alt_lookups = @alt_lookups.collect{|key, value|
|
276
|
-
@update_show_only.include?(key) ?
|
277
|
-
{ key: value }
|
278
|
-
: nil}.compact
|
279
242
|
|
280
|
-
@label = options['label'] || ( eval("#{class_name}.class_variable_defined?(:@@table_label_singular)") ? eval("#{class_name}.class_variable_get(:@@table_label_singular)") : singular.gsub("_", " ").titleize )
|
281
|
-
@list_label_heading = options['list_label_heading'] || ( eval("#{class_name}.class_variable_defined?(:@@table_label_plural)") ? eval("#{class_name}.class_variable_get(:@@table_label_plural)") : plural.gsub("_", " ").upcase )
|
282
243
|
|
283
|
-
@new_button_label = options['new_button_label'] || ( eval("#{class_name}.class_variable_defined?(:@@table_label_singular)") ? "New " + eval("#{class_name}.class_variable_get(:@@table_label_singular)") : "New " + singular.gsub("_", " ").titleize )
|
284
|
-
@new_form_heading = options['new_form_heading'] || "New #{@label}"
|
285
244
|
|
286
245
|
|
287
246
|
|
288
|
-
|
289
|
-
|
290
|
-
@inline_list_labels = options['inline_list_labels'] || 'omit' # 'before','after','omit'
|
247
|
+
@god = options['god'] || options['gd'] || false
|
248
|
+
@specs_only = options['specs_only'] || false
|
291
249
|
|
250
|
+
@no_specs = options['no_specs'] || false
|
251
|
+
@no_delete = options['no_delete'] || false
|
292
252
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
end
|
253
|
+
@no_create = options['no_create'] || false
|
254
|
+
@no_paginate = options['no_paginate'] || false
|
255
|
+
@big_edit = options['big_edit']
|
297
256
|
|
298
|
-
|
299
|
-
|
300
|
-
|
257
|
+
@no_edit = options['no_edit'] || false
|
258
|
+
@no_list = options['no_list'] || false
|
259
|
+
@no_list_label = options['no_list_label'] || false
|
260
|
+
@no_list_heading = options['no_list_heading'] || false
|
261
|
+
@stacked_downnesting = options['stacked_downnesting']
|
301
262
|
|
302
263
|
|
303
264
|
|
304
|
-
if @markup == "erb"
|
305
|
-
@template_builder = HotGlue::ErbTemplate.new(
|
306
|
-
layout_strategy: @layout_strategy,
|
307
|
-
magic_buttons: @magic_buttons,
|
308
|
-
small_buttons: @small_buttons,
|
309
|
-
inline_list_labels: @inline_list_labels,
|
310
|
-
show_only: @show_only,
|
311
|
-
update_show_only: @update_show_only,
|
312
|
-
singular_class: singular_class,
|
313
|
-
singular: singular,
|
314
|
-
hawk_keys: @hawk_keys,
|
315
|
-
ownership_field: @ownership_field,
|
316
|
-
form_labels_position: @form_labels_position,
|
317
|
-
form_placeholder_labels: @form_placeholder_labels,
|
318
|
-
alt_lookups: @alt_lookups,
|
319
|
-
attachments: @attachments,
|
320
|
-
)
|
321
|
-
elsif @markup == "slim"
|
322
|
-
raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
|
323
|
-
elsif @markup == "haml"
|
324
|
-
raise(HotGlue::Error, "HAML IS NOT IMPLEMENTED")
|
325
|
-
end
|
326
265
|
|
327
|
-
|
328
|
-
|
266
|
+
@display_list_after_update = options['display_list_after_update'] || false
|
267
|
+
@smart_layout = options['smart_layout']
|
329
268
|
|
330
|
-
|
331
|
-
|
269
|
+
if options['include'].include?(":") && @smart_layout
|
270
|
+
raise HotGlue::Error, "You specified both --smart-layout and also specified grouping mode (there is a : character in your field include list); you must remove the colon(s) from your --include tag or remove the --smart-layout option"
|
271
|
+
end
|
332
272
|
|
333
|
-
|
334
|
-
|
335
|
-
@big_edit = options['big_edit']
|
273
|
+
@container_name = @layout_strategy.container_name
|
274
|
+
@downnest = options['downnest'] || false
|
336
275
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
@
|
341
|
-
@
|
276
|
+
@downnest_children = [] # TODO: defactor @downnest_children in favor of downnest_object
|
277
|
+
@downnest_object = {}
|
278
|
+
if @downnest
|
279
|
+
@downnest_children = @downnest.split(",").map{|child| child.gsub("+","")}
|
280
|
+
@downnest_object = HotGlue.construct_downnest_object(@downnest)
|
281
|
+
end
|
342
282
|
|
283
|
+
if @god
|
284
|
+
@auth = nil
|
285
|
+
end
|
343
286
|
|
287
|
+
# when in self auth, the object is the same as the authenticated object
|
344
288
|
|
289
|
+
if @auth && auth_identifier == @singular
|
290
|
+
@self_auth = true
|
291
|
+
end
|
345
292
|
|
346
|
-
|
347
|
-
|
293
|
+
if @self_auth && !@no_create
|
294
|
+
raise "This controller appears to be the same as the authentication object but in this context you cannot build a new/create action; please re-run with --no-create flag"
|
295
|
+
end
|
348
296
|
|
349
|
-
|
350
|
-
|
351
|
-
|
297
|
+
@magic_buttons = []
|
298
|
+
if options['magic_buttons']
|
299
|
+
@magic_buttons = options['magic_buttons'].split(',')
|
300
|
+
end
|
352
301
|
|
353
|
-
@container_name = @layout_strategy.container_name
|
354
|
-
@downnest = options['downnest'] || false
|
355
302
|
|
356
|
-
|
357
|
-
@downnest_object = {}
|
358
|
-
if @downnest
|
359
|
-
@downnest_children = @downnest.split(",").map{|child| child.gsub("+","")}
|
360
|
-
@downnest_object = HotGlue.construct_downnest_object(@downnest)
|
361
|
-
end
|
303
|
+
@small_buttons = options['small_buttons'] || false
|
362
304
|
|
363
|
-
|
364
|
-
|
365
|
-
end
|
305
|
+
@build_update_action = !@no_edit || !@magic_buttons.empty?
|
306
|
+
# if the magic buttons are present, build the update action anyway
|
366
307
|
|
367
|
-
|
308
|
+
@ujs_syntax = options['ujs_syntax']
|
309
|
+
if !@ujs_syntax
|
310
|
+
@ujs_syntax = !defined?(Turbo::Engine)
|
311
|
+
end
|
368
312
|
|
369
|
-
if @auth && auth_identifier == @singular
|
370
|
-
@self_auth = true
|
371
|
-
end
|
372
313
|
|
373
|
-
|
374
|
-
|
375
|
-
|
314
|
+
# NEST CHAIN
|
315
|
+
# new syntax
|
316
|
+
# @nested_set = [
|
317
|
+
# {
|
318
|
+
# singular: ...,
|
319
|
+
# plural: ...,
|
320
|
+
# optional: false
|
321
|
+
# }]
|
322
|
+
@nested_set = []
|
376
323
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
324
|
+
if ! @nested.nil?
|
325
|
+
@nested_set = @nested.split("/").collect { |arg|
|
326
|
+
is_optional = arg.start_with?("~")
|
327
|
+
arg.gsub!("~","")
|
328
|
+
{
|
329
|
+
singular: arg,
|
330
|
+
plural: arg.pluralize,
|
331
|
+
optional: is_optional
|
332
|
+
}
|
333
|
+
}
|
334
|
+
puts "NESTING: #{@nested_set}"
|
335
|
+
end
|
381
336
|
|
337
|
+
# OBJECT OWNERSHIP & NESTING
|
338
|
+
@reference_name = HotGlue.derrive_reference_name(singular_class)
|
339
|
+
if @auth && @self_auth
|
340
|
+
@object_owner_sym = @auth.gsub("current_", "").to_sym
|
341
|
+
@object_owner_eval = @auth
|
342
|
+
@object_owner_optional = false
|
343
|
+
@object_owner_name = @auth.gsub("current_", "").to_s
|
382
344
|
|
383
|
-
@small_buttons = options['small_buttons'] || false
|
384
345
|
|
385
|
-
|
386
|
-
|
346
|
+
elsif @auth && ! @self_auth && @nested_set.none? && !@auth.include?(".")
|
347
|
+
@object_owner_sym = @auth.gsub("current_", "").to_sym
|
348
|
+
@object_owner_eval = @auth
|
349
|
+
@object_owner_optional = false
|
350
|
+
@object_owner_name = @auth.gsub("current_", "").to_s
|
387
351
|
|
388
|
-
|
389
|
-
|
390
|
-
|
352
|
+
elsif @auth && @auth.include?(".")
|
353
|
+
@object_owner_sym = nil
|
354
|
+
@object_owner_eval = @auth
|
355
|
+
else
|
356
|
+
if @nested_set.any?
|
357
|
+
@object_owner_sym = @nested_set.last[:singular].to_sym
|
358
|
+
@object_owner_eval = "@#{@nested_set.last[:singular]}"
|
359
|
+
@object_owner_name = @nested_set.last[:singular]
|
360
|
+
@object_owner_optional = @nested_set.last[:optional]
|
361
|
+
else
|
362
|
+
@object_owner_sym = nil
|
363
|
+
@object_owner_eval = ""
|
391
364
|
end
|
365
|
+
end
|
392
366
|
|
393
367
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
# {
|
398
|
-
# singular: ...,
|
399
|
-
# plural: ...,
|
400
|
-
# optional: false
|
401
|
-
# }]
|
402
|
-
@nested_set = []
|
403
|
-
|
404
|
-
if ! @nested.nil?
|
405
|
-
@nested_set = @nested.split("/").collect { |arg|
|
406
|
-
is_optional = arg.start_with?("~")
|
407
|
-
arg.gsub!("~","")
|
408
|
-
{
|
409
|
-
singular: arg,
|
410
|
-
plural: arg.pluralize,
|
411
|
-
optional: is_optional
|
412
|
-
}
|
413
|
-
}
|
414
|
-
puts "NESTING: #{@nested_set}"
|
415
|
-
end
|
416
|
-
|
417
|
-
# OBJECT OWNERSHIP & NESTING
|
418
|
-
@reference_name = HotGlue.derrive_reference_name(singular_class)
|
419
|
-
if @auth && @self_auth
|
420
|
-
@object_owner_sym = @auth.gsub("current_", "").to_sym
|
421
|
-
@object_owner_eval = @auth
|
422
|
-
@object_owner_optional = false
|
423
|
-
@object_owner_name = @auth.gsub("current_", "").to_s
|
368
|
+
@factory_creation = options['factory_creation'].gsub(";", "\n")
|
369
|
+
identify_object_owner
|
370
|
+
setup_fields
|
424
371
|
|
372
|
+
if (@columns - @show_only - (@ownership_field ? [@ownership_field.to_sym] : [])).empty?
|
373
|
+
@no_field_form = true
|
374
|
+
end
|
425
375
|
|
426
|
-
|
427
|
-
@object_owner_sym = @auth.gsub("current_", "").to_sym
|
428
|
-
@object_owner_eval = @auth
|
429
|
-
@object_owner_optional = false
|
430
|
-
@object_owner_name = @auth.gsub("current_", "").to_s
|
376
|
+
buttons_width = ((!@no_edit && 1) || 0) + ((!@no_delete && 1) || 0) + @magic_buttons.count
|
431
377
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
@object_owner_eval = "@#{@nested_set.last[:singular]}"
|
439
|
-
@object_owner_name = @nested_set.last[:singular]
|
440
|
-
@object_owner_optional = @nested_set.last[:optional]
|
441
|
-
else
|
442
|
-
@object_owner_sym = nil
|
443
|
-
@object_owner_eval = ""
|
444
|
-
end
|
378
|
+
# build a new polymorphic object
|
379
|
+
@associations = []
|
380
|
+
@columns_map = {}
|
381
|
+
@columns.each do |col|
|
382
|
+
if !(@the_object.columns_hash.keys.include?(col.to_s) || @attachments.keys.include?(col))
|
383
|
+
raise "couldn't find #{col} in either field list or attachments list"
|
445
384
|
end
|
446
385
|
|
447
|
-
|
448
|
-
|
449
|
-
identify_object_owner
|
450
|
-
setup_fields
|
451
|
-
|
452
|
-
if (@columns - @show_only - (@ownership_field ? [@ownership_field.to_sym] : [])).empty?
|
453
|
-
@no_field_form = true
|
386
|
+
if col.to_s.starts_with?("_")
|
387
|
+
@show_only << col
|
454
388
|
end
|
455
389
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
390
|
+
if @the_object.columns_hash.keys.include?(col.to_s)
|
391
|
+
type = @the_object.columns_hash[col.to_s].type
|
392
|
+
elsif @attachments.keys.include?(col)
|
393
|
+
type = :attachment
|
394
|
+
end
|
395
|
+
this_column_object = FieldFactory.new(name: col.to_s,
|
396
|
+
generator: self,
|
397
|
+
type: type)
|
398
|
+
field = this_column_object.field
|
399
|
+
if field.is_a?(AssociationField)
|
400
|
+
@associations << field.assoc_name.to_sym
|
401
|
+
end
|
402
|
+
@columns_map[col] = this_column_object.field
|
403
|
+
end
|
466
404
|
|
467
405
|
|
468
|
-
@menu_file_exists = true if @nested_set.none? && File.exist?("#{Rails.root}/app/views/#{namespace_with_trailing_dash}_menu.#{@markup}")
|
469
406
|
|
470
|
-
|
407
|
+
# create the template object
|
408
|
+
if @markup == "erb"
|
409
|
+
@template_builder = HotGlue::ErbTemplate.new(
|
410
|
+
layout_strategy: @layout_strategy,
|
411
|
+
magic_buttons: @magic_buttons,
|
412
|
+
small_buttons: @small_buttons,
|
413
|
+
inline_list_labels: @inline_list_labels,
|
414
|
+
show_only: @show_only,
|
415
|
+
update_show_only: @update_show_only,
|
416
|
+
singular_class: singular_class,
|
417
|
+
singular: singular,
|
418
|
+
hawk_keys: @hawk_keys,
|
419
|
+
ownership_field: @ownership_field,
|
420
|
+
form_labels_position: @form_labels_position,
|
421
|
+
form_placeholder_labels: @form_placeholder_labels,
|
422
|
+
alt_lookups: @alt_lookups,
|
423
|
+
attachments: @attachments,
|
424
|
+
columns_map: @columns_map
|
425
|
+
)
|
426
|
+
elsif @markup == "slim"
|
427
|
+
raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
|
428
|
+
elsif @markup == "haml"
|
429
|
+
raise(HotGlue::Error, "HAML IS NOT IMPLEMENTED")
|
471
430
|
end
|
472
431
|
|
432
|
+
builder = HotGlue::Layout::Builder.new(generator: self,
|
433
|
+
include_setting: options['include'],
|
434
|
+
buttons_width: buttons_width )
|
435
|
+
@layout_object = builder.construct
|
473
436
|
|
474
437
|
|
475
|
-
def setup_hawk_keys
|
476
|
-
@hawk_keys = {}
|
477
438
|
|
478
|
-
|
479
|
-
options['hawk'].split(",").each do |hawk_entry|
|
480
|
-
# format is: abc_id[thing]
|
439
|
+
@menu_file_exists = true if @nested_set.none? && File.exist?("#{Rails.root}/app/views/#{namespace_with_trailing_dash}_menu.#{@markup}")
|
481
440
|
|
482
|
-
|
483
|
-
|
484
|
-
key, hawk_to = $1, $2
|
485
|
-
else
|
486
|
-
key = hawk_entry
|
487
|
-
hawk_to = @auth
|
488
|
-
end
|
441
|
+
@turbo_streams = !!options['with_turbo_streams']
|
442
|
+
end
|
489
443
|
|
490
|
-
hawk_scope = key.gsub("_id", "").pluralize
|
491
|
-
optional = eval(singular_class + ".reflect_on_association(:#{key.gsub('_id','')})").options[:optional]
|
492
444
|
|
493
|
-
@hawk_keys[key.to_sym] = {bind_to: [hawk_to], optional: optional}
|
494
|
-
use_shorthand = !options["hawk"].include?("{")
|
495
445
|
|
496
|
-
|
497
|
-
|
498
|
-
end
|
499
|
-
|
500
|
-
end
|
446
|
+
def setup_hawk_keys
|
447
|
+
@hawk_keys = {}
|
501
448
|
|
502
|
-
|
503
|
-
|
504
|
-
|
449
|
+
if options["hawk"]
|
450
|
+
options['hawk'].split(",").each do |hawk_entry|
|
451
|
+
# format is: abc_id[thing]
|
505
452
|
|
453
|
+
if hawk_entry.include?("{")
|
454
|
+
hawk_entry =~ /(.*){(.*)}/
|
455
|
+
key, hawk_to = $1, $2
|
456
|
+
else
|
457
|
+
key = hawk_entry
|
458
|
+
hawk_to = @auth
|
459
|
+
end
|
506
460
|
|
507
|
-
|
508
|
-
|
461
|
+
hawk_scope = key.gsub("_id", "").pluralize
|
462
|
+
optional = eval(singular_class + ".reflect_on_association(:#{key.gsub('_id','')})").options[:optional]
|
509
463
|
|
510
|
-
|
464
|
+
@hawk_keys[key.to_sym] = {bind_to: [hawk_to], optional: optional}
|
465
|
+
use_shorthand = !options["hawk"].include?("{")
|
511
466
|
|
512
|
-
|
513
|
-
|
467
|
+
if use_shorthand # only include the hawk scope if using the shorthand
|
468
|
+
@hawk_keys[key.to_sym][:bind_to] << hawk_scope
|
469
|
+
end
|
514
470
|
|
515
|
-
|
516
|
-
num_params = attachment_entry.split("|").count
|
517
|
-
if num_params == 1
|
518
|
-
attachment_entry =~ /(.*){(.*)}/
|
519
|
-
key, thumbnail = $1, $2
|
520
|
-
elsif num_params == 2
|
521
|
-
attachment_entry =~ /(.*){(.*)\|(.*)}/
|
522
|
-
key, thumbnail, field_for_original_filename = $1, $2, $3
|
523
|
-
elsif num_params > 2
|
524
|
-
if num_params == 3
|
525
|
-
attachment_entry =~ /(.*){(.*)\|(.*)\|(.*)}/
|
526
|
-
key, thumbnail, field_for_original_filename, direct_upload = $1, $2, $3, $4
|
527
|
-
elsif num_params > 3
|
528
|
-
attachment_entry =~ /(.*){(.*)\|(.*)\|(.*)\|(.*)}/
|
529
|
-
key, thumbnail, field_for_original_filename, direct_upload, dropzone = $1, $2, $3, $4, $5
|
530
|
-
end
|
471
|
+
end
|
531
472
|
|
532
|
-
|
473
|
+
puts "HAWKING: #{@hawk_keys}"
|
474
|
+
end
|
475
|
+
end
|
533
476
|
|
534
|
-
if thumbnail == ''
|
535
|
-
thumbnail = nil
|
536
|
-
end
|
537
477
|
|
538
|
-
|
539
|
-
|
540
|
-
|
478
|
+
def setup_attachments
|
479
|
+
@attachments = {}
|
480
|
+
|
481
|
+
if options["attachments"]
|
482
|
+
|
483
|
+
options['attachments'].split(",").each do |attachment_entry|
|
484
|
+
# format is: avatar{thumbnail|field_for_original_filename}
|
485
|
+
|
486
|
+
if attachment_entry.include?("{")
|
487
|
+
num_params = attachment_entry.split("|").count
|
488
|
+
if num_params == 1
|
489
|
+
attachment_entry =~ /(.*){(.*)}/
|
490
|
+
key, thumbnail = $1, $2
|
491
|
+
elsif num_params == 2
|
492
|
+
attachment_entry =~ /(.*){(.*)\|(.*)}/
|
493
|
+
key, thumbnail, field_for_original_filename = $1, $2, $3
|
494
|
+
elsif num_params > 2
|
495
|
+
if num_params == 3
|
496
|
+
attachment_entry =~ /(.*){(.*)\|(.*)\|(.*)}/
|
497
|
+
key, thumbnail, field_for_original_filename, direct_upload = $1, $2, $3, $4
|
498
|
+
elsif num_params > 3
|
499
|
+
attachment_entry =~ /(.*){(.*)\|(.*)\|(.*)\|(.*)}/
|
500
|
+
key, thumbnail, field_for_original_filename, direct_upload, dropzone = $1, $2, $3, $4, $5
|
501
|
+
end
|
541
502
|
|
542
|
-
|
543
|
-
raise HotGlue::Error, "received 4th parameter in attachme long form specification that was not 'dropzone'; for dropzone, just use 'dropzone' or leave off to disable"
|
544
|
-
end
|
503
|
+
field_for_original_filename = nil if field_for_original_filename == ""
|
545
504
|
|
546
|
-
|
547
|
-
|
548
|
-
|
505
|
+
if thumbnail == ''
|
506
|
+
thumbnail = nil
|
507
|
+
end
|
549
508
|
|
550
|
-
|
551
|
-
|
552
|
-
|
509
|
+
if !direct_upload.nil? && direct_upload != "direct"
|
510
|
+
raise HotGlue::Error, "received 3rd parameter in attachment long form specification that was not 'direct'; for direct uploads, just use 'direct' or leave off to disable"
|
511
|
+
end
|
553
512
|
|
554
|
-
|
555
|
-
dropzone
|
513
|
+
if !dropzone.nil? && dropzone != "dropzone"
|
514
|
+
raise HotGlue::Error, "received 4th parameter in attachme long form specification that was not 'dropzone'; for dropzone, just use 'dropzone' or leave off to disable"
|
556
515
|
end
|
557
|
-
else
|
558
|
-
key = attachment_entry
|
559
516
|
|
560
|
-
if !
|
561
|
-
raise HotGlue::Error, "
|
517
|
+
if dropzone && !direct_upload
|
518
|
+
raise HotGlue::Error, "dropzone requires direct_upload"
|
562
519
|
end
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
thumbnail = nil
|
520
|
+
|
521
|
+
if field_for_original_filename && direct_upload
|
522
|
+
raise HotGlue::Error, "Unfortunately orig filename extraction doesn't work with direct upload; please set 2nd parameter to empty string to disable"
|
567
523
|
end
|
568
524
|
|
569
|
-
direct_upload =
|
570
|
-
|
571
|
-
|
525
|
+
direct_upload = !!direct_upload
|
526
|
+
dropzone = !!dropzone
|
527
|
+
end
|
528
|
+
else
|
529
|
+
key = attachment_entry
|
530
|
+
|
531
|
+
if !(eval("#{singular_class}.reflect_on_attachment(:#{attachment_entry})"))
|
532
|
+
raise HotGlue::Error, "Could not find #{attachment_entry} attachment on #{singular_class}"
|
533
|
+
end
|
534
|
+
if eval("#{singular_class}.reflect_on_attachment(:#{attachment_entry}).variants.include?(:thumb)")
|
535
|
+
thumbnail = "thumb"
|
536
|
+
else
|
537
|
+
thumbnail = nil
|
572
538
|
end
|
573
539
|
|
574
|
-
|
575
|
-
|
540
|
+
direct_upload = nil
|
541
|
+
field_for_original_filename = nil
|
542
|
+
dropzone = nil
|
543
|
+
end
|
544
|
+
|
545
|
+
if thumbnail && !eval("#{singular_class}.reflect_on_attachment(:#{key}).variants.include?(:#{thumbnail})")
|
546
|
+
raise HotGlue::Error, "you specified to use #{thumbnail} as the thumbnail but could not find any such variant on the #{key} attachment; add to your #{singular}.rb file:
|
576
547
|
has_one_attached :#{key} do |attachable|
|
577
548
|
attachable.variant :#{thumbnail}, resize_to_limit: [100, 100]
|
578
549
|
end
|
579
550
|
"
|
580
|
-
end
|
581
|
-
|
582
|
-
|
583
|
-
@attachments[key.to_sym] = {thumbnail: thumbnail,
|
584
|
-
field_for_original_filename: field_for_original_filename,
|
585
|
-
direct_upload: direct_upload,
|
586
|
-
dropzone: dropzone}
|
587
551
|
end
|
588
552
|
|
589
|
-
|
553
|
+
|
554
|
+
@attachments[key.to_sym] = {thumbnail: thumbnail,
|
555
|
+
field_for_original_filename: field_for_original_filename,
|
556
|
+
direct_upload: direct_upload,
|
557
|
+
dropzone: dropzone}
|
590
558
|
end
|
559
|
+
|
560
|
+
puts "ATTACHMENTS: #{@attachments}"
|
591
561
|
end
|
562
|
+
end
|
592
563
|
|
593
|
-
|
594
|
-
|
564
|
+
def identify_object_owner
|
565
|
+
auth_assoc = @auth && @auth.gsub("current_","")
|
595
566
|
|
596
|
-
|
597
|
-
|
598
|
-
|
567
|
+
if @object_owner_sym && ! @self_auth
|
568
|
+
auth_assoc_field = auth_assoc + "_id" unless @god
|
569
|
+
assoc = eval("#{singular_class}.reflect_on_association(:#{@object_owner_sym})")
|
599
570
|
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
571
|
+
if assoc
|
572
|
+
@ownership_field = assoc.name.to_s + "_id"
|
573
|
+
elsif ! @nested_set.any?
|
574
|
+
exit_message = "*** Oops: It looks like is no association `#{@object_owner_sym}` from the object #{@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."
|
575
|
+
raise(HotGlue::Error, exit_message)
|
605
576
|
|
606
|
-
|
607
|
-
|
608
|
-
|
577
|
+
else
|
578
|
+
if eval(singular_class + ".reflect_on_association(:#{@object_owner_sym.to_s})").nil? && !eval(singular_class + ".reflect_on_association(:#{@object_owner_sym.to_s.singularize})").nil?
|
579
|
+
exit_message = "*** Oops: you tried to nest #{singular_class} within a route for `#{@object_owner_sym}` but I can't find an association for this relationship. Did you mean `#{@object_owner_sym.to_s.singularize}` (singular) instead?"
|
609
580
|
# else # NOTE: not reachable
|
610
581
|
# exit_message = "*** Oops: Missing relationship from class #{singular_class} to :#{@object_owner_sym} maybe add `belongs_to :#{@object_owner_sym}` to #{singular_class}\n (If your user is called something else, pass with flag auth=current_X where X is the model for your auth object 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 flag). To make a controller that can read all records, specify with --god."
|
611
|
-
end
|
612
|
-
|
613
|
-
raise(HotGlue::Error, exit_message)
|
614
582
|
end
|
615
|
-
|
616
|
-
|
583
|
+
|
584
|
+
raise(HotGlue::Error, exit_message)
|
617
585
|
end
|
586
|
+
elsif @object_owner_sym && ! @object_owner_eval.include?(".")
|
587
|
+
@ownership_field = @object_owner_name + "_id"
|
618
588
|
end
|
589
|
+
end
|
619
590
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
@exclude_fields.push( @ownership_field.to_sym ) if ! @ownership_field.nil?
|
591
|
+
def setup_fields
|
592
|
+
if !@include_fields
|
593
|
+
@exclude_fields.push :id, :created_at, :updated_at, :encrypted_password,
|
594
|
+
:reset_password_token,
|
595
|
+
:reset_password_sent_at, :remember_created_at,
|
596
|
+
:confirmation_token, :confirmed_at,
|
597
|
+
:confirmation_sent_at, :unconfirmed_email
|
629
598
|
|
599
|
+
@exclude_fields.push( @ownership_field.to_sym ) if ! @ownership_field.nil?
|
630
600
|
|
631
|
-
@columns = @the_object.columns.map(&:name).map(&:to_sym).reject{|field| @exclude_fields.include?(field) }
|
632
601
|
|
602
|
+
@columns = @the_object.columns.map(&:name).map(&:to_sym).reject{|field| @exclude_fields.include?(field) }
|
633
603
|
|
634
|
-
else
|
635
|
-
@columns = @the_object.columns.map(&:name).map(&:to_sym).reject{|field| !@include_fields.include?(field) }
|
636
|
-
end
|
637
604
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
@columns << attachment if !@columns.include?(attachment)
|
642
|
-
end
|
605
|
+
else
|
606
|
+
@columns = @the_object.columns.map(&:name).map(&:to_sym).reject{|field| !@include_fields.include?(field) }
|
607
|
+
end
|
643
608
|
|
644
|
-
|
609
|
+
if @attachments.any?
|
610
|
+
puts "adding attachments-as-columns: #{@attachments}"
|
611
|
+
@attachments.keys.each do |attachment|
|
612
|
+
@columns << attachment if !@columns.include?(attachment)
|
645
613
|
end
|
646
614
|
|
615
|
+
check_if_sample_file_is_present
|
616
|
+
end
|
617
|
+
end
|
647
618
|
|
648
|
-
# build a new polymorphic object
|
649
|
-
@associations = []
|
650
|
-
@columns_map = {}
|
651
|
-
@columns.each do |col|
|
652
|
-
if !(@the_object.columns_hash.keys.include?(col.to_s) || @attachments.keys.include?(col))
|
653
|
-
raise "couldn't find #{col} in either field list or attachments list"
|
654
|
-
end
|
655
|
-
|
656
|
-
if col.to_s.starts_with?("_")
|
657
|
-
@show_only << col
|
658
|
-
end
|
659
|
-
|
660
|
-
if @the_object.columns_hash.keys.include?(col.to_s)
|
661
|
-
type = @the_object.columns_hash[col.to_s].type
|
662
|
-
elsif @attachments.keys.include?(col)
|
663
|
-
type = :attachment
|
664
|
-
end
|
665
|
-
this_column_object = FieldFactory.new(name: col.to_s,
|
666
|
-
generator: self,
|
667
|
-
type: type)
|
668
|
-
field = this_column_object.field
|
669
|
-
if field.is_a?(AssociationField)
|
670
|
-
@associations << field.assoc_name.to_sym
|
671
|
-
end
|
672
|
-
@columns_map[col] = this_column_object.field
|
673
619
|
|
674
620
|
|
675
621
|
|
676
|
-
end
|
677
|
-
end
|
678
|
-
|
679
622
|
|
680
|
-
def check_if_sample_file_is_present
|
681
|
-
if sample_file_path.nil?
|
682
|
-
puts "you have no sample file path set in config/hot_glue.yml"
|
683
|
-
settings = File.read("config/hot_glue.yml")
|
684
|
-
@sample_file_path = "spec/files/computer_code.jpg"
|
685
|
-
added_setting = ":sample_file_path: #{sample_file_path}"
|
686
|
-
File.open("config/hot_glue.yml", "w") { |f| f.write settings + "\n" + added_setting }
|
687
623
|
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
624
|
+
def check_if_sample_file_is_present
|
625
|
+
if sample_file_path.nil?
|
626
|
+
puts "you have no sample file path set in config/hot_glue.yml"
|
627
|
+
settings = File.read("config/hot_glue.yml")
|
628
|
+
@sample_file_path = "spec/files/computer_code.jpg"
|
629
|
+
added_setting = ":sample_file_path: #{sample_file_path}"
|
630
|
+
File.open("config/hot_glue.yml", "w") { |f| f.write settings + "\n" + added_setting }
|
693
631
|
|
694
|
-
puts ""
|
632
|
+
puts "adding `#{added_setting}` to config/hot_glue.yml"
|
633
|
+
elsif ! File.exist?(sample_file_path)
|
634
|
+
puts "NO SAMPLE FILE FOUND: adding sample file at #{sample_file_path}"
|
635
|
+
template "computer_code.jpg", File.join("#{filepath_prefix}spec/files/", "computer_code.jpg")
|
695
636
|
end
|
696
637
|
|
697
|
-
|
698
|
-
|
699
|
-
end
|
638
|
+
puts ""
|
639
|
+
end
|
700
640
|
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
}.join(", ")
|
641
|
+
def fields_filtered_for_email_lookups
|
642
|
+
@columns.reject{|c| @alt_lookups.keys.include?(c) } + @alt_lookups.values.map{|v| ("__lookup_#{v[:lookup_as]}").to_sym}
|
643
|
+
end
|
705
644
|
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
" @#{singular } = #{ class_name }.create(modified_params#{'.merge(' + merge_with + ')' if !merge_with.empty?})"
|
711
|
-
end
|
712
|
-
end
|
645
|
+
def creation_syntax
|
646
|
+
merge_with = @alt_lookups.collect{ |key, data|
|
647
|
+
"#{data[:assoc].downcase}: #{data[:assoc].downcase}_factory.#{data[:assoc].downcase}"
|
648
|
+
}.join(", ")
|
713
649
|
|
714
|
-
|
715
|
-
"
|
650
|
+
if @factory_creation == ''
|
651
|
+
"@#{singular } = #{ class_name }.create(modified_params)"
|
652
|
+
else
|
653
|
+
"#{@factory_creation}\n" +
|
654
|
+
" @#{singular } = #{ class_name }.create(modified_params#{'.merge(' + merge_with + ')' if !merge_with.empty?})"
|
716
655
|
end
|
656
|
+
end
|
717
657
|
|
718
|
-
|
719
|
-
|
720
|
-
|
658
|
+
def auth_root
|
659
|
+
"authenticate_" + @auth_identifier.split(".")[0] + "!"
|
660
|
+
end
|
721
661
|
|
722
|
-
|
723
|
-
|
724
|
-
|
662
|
+
def formats
|
663
|
+
[format]
|
664
|
+
end
|
725
665
|
|
726
|
-
|
727
|
-
|
728
|
-
|
666
|
+
def format
|
667
|
+
nil
|
668
|
+
end
|
729
669
|
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
670
|
+
def filepath_prefix
|
671
|
+
'spec/dummy/' if Rails.env.test?
|
672
|
+
end
|
673
|
+
|
674
|
+
def copy_controller_and_spec_files
|
675
|
+
@default_colspan = @columns.size
|
676
|
+
unless @specs_only
|
677
|
+
template "controller.rb.erb", File.join("#{filepath_prefix}app/controllers#{namespace_with_dash}", "#{@controller_build_folder}_controller.rb")
|
678
|
+
if @namespace
|
679
|
+
begin
|
680
|
+
eval(controller_descends_from)
|
681
|
+
rescue NameError => e
|
682
|
+
template "base_controller.rb.erb", File.join("#{filepath_prefix}app/controllers#{namespace_with_dash}", "base_controller.rb")
|
740
683
|
end
|
741
684
|
end
|
685
|
+
end
|
742
686
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
if File.exist?(dest_file)
|
747
|
-
existing_file = File.open(dest_file)
|
748
|
-
existing_content = existing_file.read
|
749
|
-
if existing_content =~ /\#HOTGLUE-SAVESTART/
|
750
|
-
if existing_content !~ /\#HOTGLUE-END/
|
751
|
-
raise "Your file at #{dest_file} contains a #HOTGLUE-SAVESTART marker without #HOTGLUE-END"
|
752
|
-
end
|
753
|
-
@existing_content = existing_content[(existing_content =~ /\#HOTGLUE-SAVESTART/) .. (existing_content =~ /\#HOTGLUE-END/)-1]
|
754
|
-
@existing_content << "#HOTGLUE-END"
|
687
|
+
unless @no_specs
|
688
|
+
dest_file = File.join("#{filepath_prefix}spec/features#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
|
755
689
|
|
690
|
+
if File.exist?(dest_file)
|
691
|
+
existing_file = File.open(dest_file)
|
692
|
+
existing_content = existing_file.read
|
693
|
+
if existing_content =~ /\#HOTGLUE-SAVESTART/
|
694
|
+
if existing_content !~ /\#HOTGLUE-END/
|
695
|
+
raise "Your file at #{dest_file} contains a #HOTGLUE-SAVESTART marker without #HOTGLUE-END"
|
756
696
|
end
|
757
|
-
|
758
|
-
|
759
|
-
@existing_content = " #HOTGLUE-SAVESTART\n #HOTGLUE-END"
|
760
|
-
end
|
697
|
+
@existing_content = existing_content[(existing_content =~ /\#HOTGLUE-SAVESTART/) .. (existing_content =~ /\#HOTGLUE-END/)-1]
|
698
|
+
@existing_content << "#HOTGLUE-END"
|
761
699
|
|
762
|
-
|
763
|
-
|
700
|
+
end
|
701
|
+
existing_file.rewind
|
702
|
+
else
|
703
|
+
@existing_content = " #HOTGLUE-SAVESTART\n #HOTGLUE-END"
|
764
704
|
end
|
765
705
|
|
766
|
-
template "#{@markup}/_errors.#{@markup}", File.join("#{filepath_prefix}app/views#{namespace_with_dash}", "_errors.#{@markup}")
|
767
|
-
end
|
768
|
-
|
769
|
-
def spec_foreign_association_merge_hash
|
770
|
-
", #{testing_name}: #{testing_name}1"
|
771
|
-
end
|
772
706
|
|
773
|
-
|
774
|
-
singular_class.gsub("::","_").underscore
|
707
|
+
template "system_spec.rb.erb", dest_file
|
775
708
|
end
|
776
709
|
|
777
|
-
|
778
|
-
|
779
|
-
col_object.spec_related_column_lets
|
780
|
-
}.join("\n")
|
781
|
-
end
|
710
|
+
template "#{@markup}/_errors.#{@markup}", File.join("#{filepath_prefix}app/views#{namespace_with_dash}", "_errors.#{@markup}")
|
711
|
+
end
|
782
712
|
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
col_identifier: @layout_strategy.column_classes_for_column_headings,
|
787
|
-
column_width: @layout_strategy.column_width,
|
788
|
-
singular: @singular
|
789
|
-
)
|
790
|
-
end
|
713
|
+
def spec_foreign_association_merge_hash
|
714
|
+
", #{testing_name}: #{testing_name}1"
|
715
|
+
end
|
791
716
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
random_data = col_object.spec_random_data
|
796
|
-
col.to_s + ": '" + random_data.to_s + "'"
|
797
|
-
end
|
798
|
-
}.join(", ")
|
799
|
-
end
|
717
|
+
def testing_name
|
718
|
+
singular_class.gsub("::","_").underscore
|
719
|
+
end
|
800
720
|
|
801
|
-
|
802
|
-
|
803
|
-
|
721
|
+
def spec_related_column_lets
|
722
|
+
@columns_map.collect { |col, col_object|
|
723
|
+
col_object.spec_related_column_lets
|
724
|
+
}.join("\n")
|
725
|
+
end
|
804
726
|
|
805
|
-
|
727
|
+
def list_column_headings
|
728
|
+
@template_builder.list_column_headings(
|
729
|
+
layout_object: @layout_object,
|
730
|
+
col_identifier: @layout_strategy.column_classes_for_column_headings,
|
731
|
+
column_width: @layout_strategy.column_width,
|
732
|
+
singular: @singular
|
733
|
+
)
|
734
|
+
end
|
806
735
|
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
", #{@auth_identifier}: #{@auth}"
|
736
|
+
def columns_spec_with_sample_data
|
737
|
+
@columns_map.map { |col, col_object|
|
738
|
+
unless col_object.is_a?(AssociationField)
|
739
|
+
random_data = col_object.spec_random_data
|
740
|
+
col.to_s + ": '" + random_data.to_s + "'"
|
813
741
|
end
|
814
|
-
|
742
|
+
}.join(", ")
|
743
|
+
end
|
815
744
|
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
last_parent = ", #{@auth_identifier}: #{@auth}"
|
820
|
-
end
|
745
|
+
def regenerate_me_code
|
746
|
+
"rails generate hot_glue:scaffold #{ @meta_args[0][0] } #{@meta_args[1].collect{|x| x.gsub(/\s*=\s*([\S\s]+)/, '=\'\1\'')}.join(" ")}"
|
747
|
+
end
|
821
748
|
|
822
|
-
|
823
|
-
res << " let(:#{arg[:singular]}) {create(:#{arg[:singular]} #{last_parent} )}\n"
|
824
|
-
last_parent = ", #{arg[:singular]}: #{arg[:singular]}"
|
825
|
-
end
|
826
|
-
res
|
827
|
-
end
|
749
|
+
def object_parent_mapping_as_argument_for_specs
|
828
750
|
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
751
|
+
if @self_auth
|
752
|
+
""
|
753
|
+
elsif @nested_set.any? && ! @nested_set.last[:optional]
|
754
|
+
", " + @nested_set.last[:singular] + ": " + @nested_set.last[:singular]
|
755
|
+
elsif @auth && !@god
|
756
|
+
", #{@auth_identifier}: #{@auth}"
|
833
757
|
end
|
758
|
+
end
|
834
759
|
|
835
|
-
|
836
|
-
|
760
|
+
def objest_nest_factory_setup
|
761
|
+
res = ""
|
762
|
+
if @auth
|
763
|
+
last_parent = ", #{@auth_identifier}: #{@auth}"
|
837
764
|
end
|
838
765
|
|
839
|
-
|
840
|
-
|
766
|
+
@nested_set.each do |arg|
|
767
|
+
res << " let(:#{arg[:singular]}) {create(:#{arg[:singular]} #{last_parent} )}\n"
|
768
|
+
last_parent = ", #{arg[:singular]}: #{arg[:singular]}"
|
841
769
|
end
|
770
|
+
res
|
771
|
+
end
|
842
772
|
|
843
|
-
|
844
|
-
|
845
|
-
|
773
|
+
def objest_nest_params_by_id_for_specs
|
774
|
+
@nested_set.map{|arg|
|
775
|
+
"#{arg[:singular]}_id: #{arg[:singular]}.id"
|
776
|
+
}.join(",\n ")
|
777
|
+
end
|
846
778
|
|
847
|
-
|
848
|
-
|
849
|
-
|
779
|
+
def controller_class_name
|
780
|
+
@controller_build_name
|
781
|
+
end
|
850
782
|
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
col_obj.spec_setup_and_change_act(which_partial)
|
855
|
-
end
|
856
|
-
}.join("\n")
|
857
|
-
end
|
783
|
+
def plural_name
|
784
|
+
plural
|
785
|
+
end
|
858
786
|
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
787
|
+
def auth_identifier
|
788
|
+
@auth_identifier
|
789
|
+
end
|
790
|
+
|
791
|
+
def capybara_make_updates(which_partial = :create)
|
792
|
+
@columns_map.map { | col, col_obj|
|
793
|
+
show_only_list = which_partial == :create ? @show_only : (@update_show_only+@show_only)
|
866
794
|
|
867
|
-
|
868
|
-
|
869
|
-
"#{@namespace+"_" if @namespace}#{(@nested_set.collect{|x| x[:singular]}.join("_") + "_" if @nested_set.any?)}#{@controller_build_folder_singular}_path"
|
795
|
+
if show_only_list.include?(col)
|
796
|
+
" page.should have_no_selector(:css, \"[name='#{testing_name}[#{ col.to_s }]'\")"
|
870
797
|
else
|
871
|
-
|
798
|
+
col_obj.spec_setup_and_change_act(which_partial)
|
872
799
|
end
|
873
|
-
|
800
|
+
}.join("\n")
|
801
|
+
end
|
874
802
|
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
803
|
+
def path_helper_args
|
804
|
+
if @nested_set.any? && @nested
|
805
|
+
[(@nested_set).collect{|a| "#{a[:singular]}"} , singular].join(",")
|
806
|
+
else
|
807
|
+
singular
|
879
808
|
end
|
809
|
+
end
|
880
810
|
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
top_level: false)
|
811
|
+
def path_helper_singular
|
812
|
+
if @nested
|
813
|
+
"#{@namespace+"_" if @namespace}#{(@nested_set.collect{|x| x[:singular]}.join("_") + "_" if @nested_set.any?)}#{@controller_build_folder_singular}_path"
|
814
|
+
else
|
815
|
+
"#{@namespace+"_" if @namespace}#{@controller_build_folder_singular}_path"
|
887
816
|
end
|
817
|
+
end
|
888
818
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
put_form: true,
|
895
|
-
top_level: true)
|
896
|
-
end
|
819
|
+
def path_helper_plural
|
820
|
+
HotGlue.optionalized_ternary(namespace: @namespace,
|
821
|
+
target: @controller_build_folder,
|
822
|
+
nested_set: @nested_set)
|
823
|
+
end
|
897
824
|
|
825
|
+
def form_path_new_helper
|
826
|
+
HotGlue.optionalized_ternary(namespace: @namespace,
|
827
|
+
target: @controller_build_folder,
|
828
|
+
nested_set: @nested_set,
|
829
|
+
with_params: true,
|
830
|
+
top_level: false)
|
831
|
+
end
|
898
832
|
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
833
|
+
def form_path_edit_helper
|
834
|
+
HotGlue.optionalized_ternary(namespace: @namespace,
|
835
|
+
target: @singular,
|
836
|
+
nested_set: @nested_set,
|
837
|
+
with_params: true,
|
838
|
+
put_form: true,
|
839
|
+
top_level: true)
|
840
|
+
end
|
906
841
|
|
907
|
-
def edit_path_helper
|
908
|
-
HotGlue.optionalized_ternary(namespace: @namespace,
|
909
|
-
target: @singular,
|
910
|
-
nested_set: @nested_set,
|
911
|
-
modifier: "edit_",
|
912
|
-
with_params: true,
|
913
|
-
put_form: true)
|
914
|
-
end
|
915
842
|
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
843
|
+
def delete_path_helper
|
844
|
+
HotGlue.optionalized_ternary(namespace: @namespace,
|
845
|
+
target: @singular,
|
846
|
+
nested_set: @nested_set,
|
847
|
+
with_params: true,
|
848
|
+
put_form: true)
|
849
|
+
end
|
923
850
|
|
924
|
-
|
925
|
-
|
926
|
-
|
851
|
+
def edit_path_helper
|
852
|
+
HotGlue.optionalized_ternary(namespace: @namespace,
|
853
|
+
target: @singular,
|
854
|
+
nested_set: @nested_set,
|
855
|
+
modifier: "edit_",
|
856
|
+
with_params: true,
|
857
|
+
put_form: true)
|
858
|
+
end
|
927
859
|
|
928
|
-
|
929
|
-
|
860
|
+
def path_arity
|
861
|
+
res = ""
|
862
|
+
if @nested_set.any? && @nested
|
863
|
+
res << nested_objects_arity + ", "
|
930
864
|
end
|
865
|
+
res << "@" + singular
|
866
|
+
end
|
931
867
|
|
932
|
-
|
933
|
-
|
934
|
-
|
868
|
+
def line_path_partial
|
869
|
+
"#{@namespace+"/" if @namespace}#{@controller_build_folder}/line"
|
870
|
+
end
|
935
871
|
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
nested_set: @nested_set,
|
940
|
-
modifier: "new_",
|
941
|
-
with_params: true)
|
942
|
-
end
|
872
|
+
def show_path_partial
|
873
|
+
"#{@namespace+"/" if @namespace}#{@controller_build_folder}/show"
|
874
|
+
end
|
943
875
|
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
end
|
876
|
+
def list_path_partial
|
877
|
+
"#{@namespace+"/" if @namespace}#{@controller_build_folder}/list"
|
878
|
+
end
|
948
879
|
|
949
|
-
|
950
|
-
|
951
|
-
|
880
|
+
def new_path_name
|
881
|
+
HotGlue.optionalized_ternary(namespace: @namespace,
|
882
|
+
target: singular,
|
883
|
+
nested_set: @nested_set,
|
884
|
+
modifier: "new_",
|
885
|
+
with_params: true)
|
886
|
+
end
|
952
887
|
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
""
|
958
|
-
end
|
959
|
-
end
|
888
|
+
def nested_assignments
|
889
|
+
return "" if @nested_set.none?
|
890
|
+
@nested_set.map{|a| "#{a}: #{a}"}.join(", ") #metaprgramming into Ruby hash
|
891
|
+
end
|
960
892
|
|
961
|
-
|
962
|
-
|
963
|
-
|
893
|
+
def nested_assignments_top_level # this is by accessing the instance variable-- only use at top level
|
894
|
+
@nested_set.map{|a| "#{a[:singular]}"}.join(", ") #metaprgramming into Ruby hash
|
895
|
+
end
|
964
896
|
|
965
|
-
|
966
|
-
|
897
|
+
def nest_assignments_operator(top_level = false, leading_comma = false)
|
898
|
+
if @nested_set.any?
|
899
|
+
"#{", " if leading_comma}#{top_level ? nested_assignments_top_level : nested_assignments }"
|
900
|
+
else
|
901
|
+
""
|
967
902
|
end
|
903
|
+
end
|
968
904
|
|
969
|
-
|
970
|
-
|
971
|
-
|
905
|
+
def nested_assignments_with_leading_comma
|
906
|
+
nest_assignments_operator(false, true)
|
907
|
+
end
|
972
908
|
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
909
|
+
def nested_objects_arity
|
910
|
+
@nested_set.map{|a| "@#{a[:singular]}"}.join(", ")
|
911
|
+
end
|
912
|
+
|
913
|
+
def nested_arity_for_path
|
914
|
+
[@nested_set[0..-1].collect{|a| "@#{a[:singular]}"}].join(", ") #metaprgramming into arity for the Rails path helper
|
915
|
+
end
|
916
|
+
|
917
|
+
def object_scope
|
918
|
+
if @auth
|
919
|
+
if @nested_set.none?
|
920
|
+
@auth + ".#{plural}"
|
980
921
|
else
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
922
|
+
"@" + @nested_set.last[:singular] + ".#{plural}"
|
923
|
+
end
|
924
|
+
else
|
925
|
+
if @nested_set.none?
|
926
|
+
@singular_class
|
927
|
+
else
|
928
|
+
"@" + @nested_set.last[:singular] + ".#{plural}"
|
986
929
|
end
|
987
930
|
end
|
931
|
+
end
|
988
932
|
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
else
|
996
|
-
"@" + @nested_set.last[:singular] + ".#{plural}"
|
997
|
-
end
|
933
|
+
def all_objects_root
|
934
|
+
if @auth
|
935
|
+
if @self_auth
|
936
|
+
@singular_class + ".where(id: #{@auth}.id)"
|
937
|
+
elsif @nested_set.none?
|
938
|
+
@auth + ".#{plural}"
|
998
939
|
else
|
999
|
-
@
|
940
|
+
"@" + @nested_set.last[:singular] + ".#{plural}"
|
1000
941
|
end
|
942
|
+
else
|
943
|
+
@singular_class + ".all"
|
1001
944
|
end
|
945
|
+
end
|
1002
946
|
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
947
|
+
def any_nested?
|
948
|
+
@nested_set.any?
|
949
|
+
end
|
1006
950
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
951
|
+
def all_objects_variable
|
952
|
+
all_objects_root + ".page(params[:page])"
|
953
|
+
end
|
1010
954
|
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
955
|
+
def auth_object
|
956
|
+
@auth
|
957
|
+
end
|
1014
958
|
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
959
|
+
def no_devise_installed
|
960
|
+
!Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }['devise']
|
961
|
+
end
|
1018
962
|
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
963
|
+
def magic_button_output
|
964
|
+
@template_builder.magic_button_output(
|
965
|
+
path: HotGlue.optionalized_ternary(namespace: @namespace,
|
966
|
+
target: @singular,
|
967
|
+
nested_set: @nested_set,
|
968
|
+
with_params: true,
|
969
|
+
put_form: true),
|
970
|
+
singular: singular,
|
971
|
+
magic_buttons: @magic_buttons,
|
972
|
+
small_buttons: @small_buttons
|
973
|
+
)
|
974
|
+
end
|
1031
975
|
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
976
|
+
def nav_template
|
977
|
+
"#{namespace_with_trailing_dash}nav"
|
978
|
+
end
|
1035
979
|
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
980
|
+
def include_nav_template
|
981
|
+
File.exist?("#{Rails.root}/app/views/#{namespace_with_trailing_dash}_nav.html.#{@markup}")
|
982
|
+
end
|
1039
983
|
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
984
|
+
def copy_view_files
|
985
|
+
return if @specs_only
|
986
|
+
all_views.each do |view|
|
987
|
+
formats.each do |format|
|
988
|
+
source_filename = cc_filename_with_extensions("#{@markup}/#{view}", "#{@markup}")
|
989
|
+
dest_filename = cc_filename_with_extensions("#{view}", "#{@markup}")
|
1046
990
|
|
1047
991
|
|
1048
|
-
|
1049
|
-
|
992
|
+
dest_filepath = File.join("#{filepath_prefix}app/views#{namespace_with_dash}",
|
993
|
+
@controller_build_folder, dest_filename)
|
1050
994
|
|
1051
995
|
|
1052
|
-
|
1053
|
-
|
996
|
+
template source_filename, dest_filepath
|
997
|
+
gsub_file dest_filepath, '\%', '%'
|
1054
998
|
|
1055
|
-
end
|
1056
999
|
end
|
1000
|
+
end
|
1057
1001
|
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1002
|
+
turbo_stream_views.each do |view|
|
1003
|
+
formats.each do |format|
|
1004
|
+
source_filename = cc_filename_with_extensions( "#{@markup}/#{view}.turbo_stream.#{@markup}")
|
1005
|
+
dest_filename = cc_filename_with_extensions("#{view}", "turbo_stream.#{@markup}")
|
1006
|
+
dest_filepath = File.join("#{filepath_prefix}app/views#{namespace_with_dash}",
|
1007
|
+
@controller_build_folder, dest_filename)
|
1064
1008
|
|
1065
1009
|
|
1066
|
-
|
1067
|
-
|
1010
|
+
template source_filename, dest_filepath
|
1011
|
+
gsub_file dest_filepath, '\%', '%'
|
1068
1012
|
|
1069
|
-
end
|
1070
1013
|
end
|
1071
1014
|
end
|
1015
|
+
end
|
1072
1016
|
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
if options['with_turbo_streams'] == true
|
1077
|
-
dest_filename = cc_filename_with_extensions("#{singular_class.underscore}", "rb")
|
1078
|
-
dest_filepath = File.join("#{filepath_prefix}app/models", dest_filename)
|
1017
|
+
def append_model_callbacks
|
1018
|
+
# somehow the generator invokes this
|
1079
1019
|
|
1020
|
+
if options['with_turbo_streams'] == true
|
1021
|
+
dest_filename = cc_filename_with_extensions("#{singular_class.underscore}", "rb")
|
1022
|
+
dest_filepath = File.join("#{filepath_prefix}app/models", dest_filename)
|
1080
1023
|
|
1081
|
-
puts "appending turbo callbacks to #{dest_filepath}"
|
1082
1024
|
|
1083
|
-
|
1025
|
+
puts "appending turbo callbacks to #{dest_filepath}"
|
1084
1026
|
|
1085
|
-
|
1086
|
-
if !text.include?("include ActionView::RecordIdentifier")
|
1087
|
-
append_text << " include ActionView::RecordIdentifier\n"
|
1088
|
-
end
|
1089
|
-
append_text << " after_update_commit lambda { broadcast_replace_to self, target: \"#{@namespace}__\#{dom_id(self)}\", partial: \"#{@namespace}/#{@plural}/line\" }\n after_destroy_commit lambda { broadcast_remove_to self, target: \"#{@namespace}__\#{dom_id(self)}\"}\n"
|
1027
|
+
text = File.read(dest_filepath)
|
1090
1028
|
|
1091
|
-
|
1092
|
-
|
1029
|
+
append_text = "class #{singular_class} < ApplicationRecord\n"
|
1030
|
+
if !text.include?("include ActionView::RecordIdentifier")
|
1031
|
+
append_text << " include ActionView::RecordIdentifier\n"
|
1093
1032
|
end
|
1094
|
-
|
1033
|
+
append_text << " after_update_commit lambda { broadcast_replace_to self, target: \"#{@namespace}__\#{dom_id(self)}\", partial: \"#{@namespace}/#{@plural}/line\" }\n after_destroy_commit lambda { broadcast_remove_to self, target: \"#{@namespace}__\#{dom_id(self)}\"}\n"
|
1095
1034
|
|
1096
|
-
|
1097
|
-
|
1098
|
-
"/#{@namespace}"
|
1099
|
-
else
|
1100
|
-
""
|
1101
|
-
end
|
1035
|
+
replace = text.gsub(/class #{singular_class} < ApplicationRecord/, append_text)
|
1036
|
+
File.open(dest_filepath, "w") {|file| file.puts replace}
|
1102
1037
|
end
|
1038
|
+
end
|
1103
1039
|
|
1104
|
-
|
1105
|
-
|
1040
|
+
def namespace_with_dash
|
1041
|
+
if @namespace
|
1042
|
+
"/#{@namespace}"
|
1043
|
+
else
|
1044
|
+
""
|
1106
1045
|
end
|
1046
|
+
end
|
1107
1047
|
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
unless @no_create
|
1112
|
-
res += %w(new _new_form _new_button)
|
1113
|
-
end
|
1048
|
+
def namespace_with_trailing_dash
|
1049
|
+
@namespace ? "#{@namespace}/" : ""
|
1050
|
+
end
|
1114
1051
|
|
1115
|
-
|
1116
|
-
|
1117
|
-
end
|
1052
|
+
def all_views
|
1053
|
+
res = %w(index _line _list _show _errors)
|
1118
1054
|
|
1119
|
-
|
1120
|
-
|
1121
|
-
end
|
1122
|
-
res
|
1055
|
+
unless @no_create
|
1056
|
+
res += %w(new _new_form _new_button)
|
1123
1057
|
end
|
1124
1058
|
|
1125
|
-
|
1126
|
-
res
|
1127
|
-
unless @no_delete
|
1128
|
-
res << 'destroy'
|
1129
|
-
end
|
1130
|
-
|
1131
|
-
unless @no_create
|
1132
|
-
res << 'create'
|
1133
|
-
end
|
1134
|
-
|
1135
|
-
unless @no_edit
|
1136
|
-
res << 'edit'
|
1137
|
-
res << 'update'
|
1138
|
-
end
|
1139
|
-
|
1140
|
-
res
|
1059
|
+
unless @no_edit
|
1060
|
+
res << 'edit'
|
1141
1061
|
end
|
1142
1062
|
|
1143
|
-
|
1144
|
-
|
1063
|
+
if !( @no_edit && @no_create)
|
1064
|
+
res << '_form'
|
1145
1065
|
end
|
1066
|
+
res
|
1067
|
+
end
|
1146
1068
|
|
1147
|
-
|
1148
|
-
|
1069
|
+
def turbo_stream_views
|
1070
|
+
res = []
|
1071
|
+
unless @no_delete
|
1072
|
+
res << 'destroy'
|
1149
1073
|
end
|
1150
1074
|
|
1151
|
-
|
1152
|
-
|
1075
|
+
unless @no_create
|
1076
|
+
res << 'create'
|
1153
1077
|
end
|
1154
1078
|
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1079
|
+
unless @no_edit
|
1080
|
+
res << 'edit'
|
1081
|
+
res << 'update'
|
1158
1082
|
end
|
1159
1083
|
|
1160
|
-
|
1161
|
-
|
1162
|
-
end
|
1084
|
+
res
|
1085
|
+
end
|
1163
1086
|
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1087
|
+
def handler
|
1088
|
+
:erb
|
1089
|
+
end
|
1167
1090
|
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1091
|
+
def model_has_strings?
|
1092
|
+
false
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
def model_search_fields # an array of fields we can search on
|
1096
|
+
[]
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
def form_fields_html
|
1100
|
+
@template_builder.all_form_fields(layout_strategy: @layout_strategy,
|
1101
|
+
layout_object: @layout_object)
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
def list_label
|
1105
|
+
@list_label_heading
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def new_thing_label
|
1109
|
+
@new_thing_label
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def all_line_fields
|
1113
|
+
@template_builder.all_line_fields(
|
1114
|
+
col_identifier: @layout_strategy.column_classes_for_line_fields,
|
1115
|
+
perc_width: @layout_strategy.each_col, #undefined method `each_col'
|
1116
|
+
layout_strategy: @layout_strategy,
|
1117
|
+
layout_object: @layout_object
|
1118
|
+
)
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
def controller_descends_from
|
1122
|
+
if defined?(@namespace.titlecase.gsub(" ", "") + "::BaseController")
|
1123
|
+
@namespace.titlecase.gsub(" ", "") + "::BaseController"
|
1124
|
+
else
|
1125
|
+
"ApplicationController"
|
1175
1126
|
end
|
1127
|
+
end
|
1176
1128
|
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1129
|
+
def display_class
|
1130
|
+
me = eval(singular_class)
|
1131
|
+
|
1132
|
+
@display_class ||=
|
1133
|
+
if me.column_names.include?("name") || me.instance_methods(false).include?(:name)
|
1134
|
+
# note that all class object respond_to?(:name) with the name of their own class
|
1135
|
+
# this one is unique
|
1136
|
+
"name"
|
1137
|
+
elsif me.column_names.include?("to_label") || me.instance_methods(false).include?(:to_label)
|
1138
|
+
"to_label"
|
1139
|
+
elsif me.column_names.include?("full_name") || me.instance_methods(false).include?(:full_name)
|
1140
|
+
"full_name"
|
1141
|
+
elsif me.column_names.include?("display_name") || me.instance_methods(false).include?(:display_name)
|
1142
|
+
"display_name"
|
1143
|
+
elsif me.column_names.include?("email") || me.instance_methods(false).include?(:email)
|
1144
|
+
"email"
|
1180
1145
|
else
|
1181
|
-
"
|
1146
|
+
exit_message = "*** Oops: Can't find any column to use as the display label on #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, 5) email, or 6) number directly on your #{singular_class} 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)"
|
1147
|
+
raise(HotGlue::Error, exit_message)
|
1182
1148
|
end
|
1183
|
-
|
1184
|
-
|
1185
|
-
def display_class
|
1186
|
-
me = eval(singular_class)
|
1187
|
-
|
1188
|
-
@display_class ||=
|
1189
|
-
if me.column_names.include?("name") || me.instance_methods(false).include?(:name)
|
1190
|
-
# note that all class object respond_to?(:name) with the name of their own class
|
1191
|
-
# this one is unique
|
1192
|
-
"name"
|
1193
|
-
elsif me.column_names.include?("to_label") || me.instance_methods(false).include?(:to_label)
|
1194
|
-
"to_label"
|
1195
|
-
elsif me.column_names.include?("full_name") || me.instance_methods(false).include?(:full_name)
|
1196
|
-
"full_name"
|
1197
|
-
elsif me.column_names.include?("display_name") || me.instance_methods(false).include?(:display_name)
|
1198
|
-
"display_name"
|
1199
|
-
elsif me.column_names.include?("email") || me.instance_methods(false).include?(:email)
|
1200
|
-
"email"
|
1201
|
-
else
|
1202
|
-
exit_message = "*** Oops: Can't find any column to use as the display label on #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, 5) email, or 6) number directly on your #{singular_class} 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)"
|
1203
|
-
raise(HotGlue::Error, exit_message)
|
1204
|
-
end
|
1205
|
-
end
|
1149
|
+
end
|
1206
1150
|
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1151
|
+
def destroy_action
|
1152
|
+
return false if @self_auth
|
1153
|
+
return !@no_delete
|
1154
|
+
end
|
1211
1155
|
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1156
|
+
def create_action
|
1157
|
+
return false if @self_auth
|
1158
|
+
return !@no_create
|
1159
|
+
end
|
1216
1160
|
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
end
|
1161
|
+
def namespace_with_slash
|
1162
|
+
if @namespace
|
1163
|
+
"#{@namespace}/"
|
1164
|
+
else
|
1165
|
+
""
|
1223
1166
|
end
|
1167
|
+
end
|
1224
1168
|
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1169
|
+
def paginate
|
1170
|
+
@template_builder.paginate(plural: plural)
|
1171
|
+
end
|
1228
1172
|
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1173
|
+
def controller_magic_button_update_actions
|
1174
|
+
@magic_buttons.collect{ |magic_button|
|
1175
|
+
" if #{singular}_params[:#{magic_button}]
|
1232
1176
|
begin
|
1233
1177
|
res = @#{singular}.#{magic_button}!
|
1234
1178
|
res = \"#{magic_button.titleize}ed.\" if res === true
|
@@ -1239,79 +1183,78 @@ module HotGlue
|
|
1239
1183
|
end
|
1240
1184
|
end"
|
1241
1185
|
|
1242
|
-
|
1243
|
-
|
1186
|
+
}.join("\n") + "\n"
|
1187
|
+
end
|
1244
1188
|
|
1245
1189
|
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1190
|
+
def controller_update_params_tap_away_magic_buttons
|
1191
|
+
@magic_buttons.collect{ |magic_button|
|
1192
|
+
".tap{ |ary| ary.delete('__#{magic_button}') }"
|
1193
|
+
}.join("")
|
1194
|
+
end
|
1251
1195
|
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1196
|
+
def controller_update_params_tap_away_alt_lookups
|
1197
|
+
@alt_lookups.collect{ |key, data|
|
1198
|
+
".tap{ |ary| ary.delete('__lookup_#{data[:lookup_as]}') }"
|
1199
|
+
}.join("")
|
1200
|
+
end
|
1257
1201
|
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
end
|
1202
|
+
def nested_for_turbo_id_list_constructor
|
1203
|
+
if @nested_set.any?
|
1204
|
+
'+ (((\'__\' + nested_for) if defined?(nested_for)) || "")'
|
1205
|
+
else
|
1206
|
+
""
|
1264
1207
|
end
|
1208
|
+
end
|
1265
1209
|
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
end
|
1210
|
+
def n_plus_one_includes
|
1211
|
+
if @associations.any? || @attachments.any?
|
1212
|
+
".includes(" + (@associations.map{|x| x} + @attachments.collect{|k,v| "#{k}_attachment"}).map{|x| ":#{x.to_s}"}.join(", ") + ")"
|
1213
|
+
else
|
1214
|
+
""
|
1272
1215
|
end
|
1216
|
+
end
|
1273
1217
|
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
end
|
1218
|
+
def nested_for_turbo_nested_constructor(top_level = true)
|
1219
|
+
instance_symbol = "@" if top_level
|
1220
|
+
instance_symbol = "" if !top_level
|
1221
|
+
if @nested_set.none?
|
1222
|
+
"\"\""
|
1223
|
+
else
|
1224
|
+
@nested_set.collect{|arg|
|
1225
|
+
"(((\"__#{arg[:singular]}-\#{" + "@" + arg[:singular] + ".id}\") if @" + arg[:singular] + ") || \"\")"
|
1226
|
+
}.join(" + ")
|
1284
1227
|
end
|
1228
|
+
end
|
1285
1229
|
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
end
|
1230
|
+
def nested_for_assignments_constructor(top_level = true)
|
1231
|
+
instance_symbol = "@" if top_level
|
1232
|
+
instance_symbol = "" if !top_level
|
1233
|
+
if @nested_set.none?
|
1234
|
+
""
|
1235
|
+
else
|
1236
|
+
", \n nested_for: \"" + @nested_set.collect{|a| "#{a[:singular]}-" + '#{' + instance_symbol + a[:singular] + ".id}"}.join("__") + "\""
|
1294
1237
|
end
|
1238
|
+
end
|
1295
1239
|
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1240
|
+
private # thor does something fancy like sending the class all of its own methods during some strange run sequence
|
1241
|
+
# does not like public methods
|
1242
|
+
def cc_filename_with_extensions(name, file_format = format)
|
1243
|
+
[name, file_format].compact.join(".")
|
1244
|
+
end
|
1301
1245
|
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1246
|
+
def hawk_to_ruby
|
1247
|
+
res = @hawk_keys.collect{ |k,v|
|
1248
|
+
"#{k.to_s}: [#{v[:bind_to].join(".")}]"
|
1249
|
+
}.join(", ")
|
1250
|
+
res
|
1251
|
+
end
|
1308
1252
|
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1253
|
+
def controller_attachment_orig_filename_pickup_syntax
|
1254
|
+
@attachments.collect{ |key, attachment| "\n" + " modified_params[:#{ attachment[:field_for_original_filename] }] = #{singular}_params['#{ key }'].original_filename" if attachment[:field_for_original_filename] }.compact.join("\n")
|
1255
|
+
end
|
1312
1256
|
|
1313
|
-
|
1314
|
-
|
1315
|
-
end
|
1257
|
+
def any_datetime_fields?
|
1258
|
+
(@columns - @attachments.keys.collect(&:to_sym)).collect{|col| eval("#{singular_class}.columns_hash['#{col}']").type}.include?(:datetime)
|
1316
1259
|
end
|
1317
1260
|
end
|