Class: Scaffolding::Attribute

Inherits:
Object
  • Object
show all
Defined in:
lib/scaffolding/attribute.rb

Overview

This class provides helpful methods for determining when and how we should apply logic for each attribute when Super Scaffolding a new model.

For example, we determine which association to use based off of the attribute passed to ‘bin/super-scaffold` as opposed to the models (classes) themselves. Rails has ActiveRecord::Reflection::AssociationReflection, but this is only useful after we’ve declared the associations. Since we haven’t declared the associations in the models yet, we determine the association for the attribute based on its suffix.

i.e. - bin/super-scaffold crud Project tag_ids:super_selectclass_name=Projectsclass_name=Projects::Tag Here, we determine the association for the ‘tag_ids` attribute by its suffix, `_ids`.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attribute_definition, scaffolding_type, attribute_index) ⇒ Attribute

Returns a new instance of Attribute.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/scaffolding/attribute.rb', line 19

def initialize(attribute_definition, scaffolding_type, attribute_index)
  parts = attribute_definition.split(":")
  self.name = parts.shift
  self.type, self.options = get_type_and_options_from(parts)
  self.scaffolding_type = scaffolding_type
  self.attribute_index = attribute_index

  # We mutate `type` within the transformer, so `original_type` allows us
  # to access what the developer originally passed to bin/super-scaffold.
  # (Refer to sql_type_to_field_type_mapping in the transformer)
  self.original_type = type

  # Ensure `options` is a hash.
  self.options = if options
    options.split(",").map { |s|
      option_name, option_value = s.split("=")
      [option_name.to_sym, option_value || true]
    }.to_h
  else
    {}
  end

  options[:label] ||= "label_string"
end

Instance Attribute Details

#attribute_indexObject

Returns the value of attribute attribute_index.



14
15
16
# File 'lib/scaffolding/attribute.rb', line 14

def attribute_index
  @attribute_index
end

#nameObject

Returns the value of attribute name.



14
15
16
# File 'lib/scaffolding/attribute.rb', line 14

def name
  @name
end

#optionsObject

Returns the value of attribute options.



14
15
16
# File 'lib/scaffolding/attribute.rb', line 14

def options
  @options
end

#original_typeObject

Returns the value of attribute original_type.



14
15
16
# File 'lib/scaffolding/attribute.rb', line 14

def original_type
  @original_type
end

#scaffolding_typeObject

Returns the value of attribute scaffolding_type.



14
15
16
# File 'lib/scaffolding/attribute.rb', line 14

def scaffolding_type
  @scaffolding_type
end

#typeObject

Returns the value of attribute type.



14
15
16
# File 'lib/scaffolding/attribute.rb', line 14

def type
  @type
end

Instance Method Details

#active_storage_image?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/scaffolding/attribute.rb', line 111

def active_storage_image?
  image? && !cloudinary_enabled?
end

#association_class_nameObject



54
55
56
57
58
59
# File 'lib/scaffolding/attribute.rb', line 54

def association_class_name
  if options[:class_name].present?
    return options[:class_name].underscore.split("/").last
  end
  name.split("_id").first
end

#class_name_matches?Boolean

Returns:

  • (Boolean)


65
66
67
68
69
70
71
72
73
# File 'lib/scaffolding/attribute.rb', line 65

def class_name_matches?
  # if namespaces are involved, just don't...
  # TODO: I'm not entirely sure that extracting this conditional was the right thing to do.
  # Are there scenarios where we want to assume a match even when namespaces are involved?
  if options[:class_name].include?("::")
    return false
  end
  name_without_id.tableize == options[:class_name].tableize.tr("/", "_")
end

#cloudinary_image?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/scaffolding/attribute.rb', line 107

def cloudinary_image?
  image? && cloudinary_enabled?
end

#collection_nameObject



158
159
160
# File 'lib/scaffolding/attribute.rb', line 158

def collection_name
  is_ids? ? name_without_ids : name_without_id.pluralize
end

#default_valueObject



214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/scaffolding/attribute.rb', line 214

def default_value
  case type
  when "text_field", "password_field", "text_area"
    "'Alternative String Value'"
  when "email_field"
    "'another.email@test.com'"
  when "phone_field"
    "'+19053871234'"
  when "color_picker"
    "'#47E37F'"
  end
end

#file_field?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/scaffolding/attribute.rb', line 99

def file_field?
  type == "file_field"
end

#image?Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/scaffolding/attribute.rb', line 103

def image?
  type == "image"
end

#is_association?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/scaffolding/attribute.rb', line 75

def is_association?
  is_belongs_to? || is_has_many?
end

#is_belongs_to?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/scaffolding/attribute.rb', line 79

def is_belongs_to?
  is_id? && !is_vanilla?
end

#is_boolean?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/scaffolding/attribute.rb', line 95

def is_boolean?
  original_type == "boolean"
end

#is_first_attribute?Boolean

Returns:

  • (Boolean)


44
45
46
# File 'lib/scaffolding/attribute.rb', line 44

def is_first_attribute?
  attribute_index == 0 && scaffolding_type == :crud
end

#is_has_many?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/scaffolding/attribute.rb', line 83

def is_has_many?
  is_ids? && !is_vanilla?
end

#is_id?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/scaffolding/attribute.rb', line 121

def is_id?
  name.match?(/_id$/)
end

#is_ids?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/scaffolding/attribute.rb', line 125

def is_ids?
  name.match?(/_ids$/)
end

#is_multiple?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/scaffolding/attribute.rb', line 91

def is_multiple?
  options&.key?(:multiple) || is_has_many?
end

#is_required?Boolean

if this is the first attribute of a newly scaffolded model, that field is required.

Returns:

  • (Boolean)


49
50
51
52
# File 'lib/scaffolding/attribute.rb', line 49

def is_required?
  return false if type == "file_field"
  options[:required] || is_first_attribute?
end

#is_unscoped?Boolean

Sometimes we need all the magic of a ‘*_id` field, but without the scoping stuff. Possibly only ever used internally by `join-model`.

Returns:

  • (Boolean)


117
118
119
# File 'lib/scaffolding/attribute.rb', line 117

def is_unscoped?
  options[:unscoped]
end

#is_vanilla?Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/scaffolding/attribute.rb', line 87

def is_vanilla?
  options&.key?(:vanilla)
end

#name_without_idObject



129
130
131
# File 'lib/scaffolding/attribute.rb', line 129

def name_without_id
  name.delete_suffix("_id")
end

#name_without_id_suffixObject



137
138
139
140
141
142
143
144
145
# File 'lib/scaffolding/attribute.rb', line 137

def name_without_id_suffix
  if is_ids?
    name_without_ids
  elsif is_id?
    name_without_id
  else
    name
  end
end

#name_without_idsObject



133
134
135
# File 'lib/scaffolding/attribute.rb', line 133

def name_without_ids
  name.delete_suffix("_ids").pluralize
end

#partial_nameObject

Field on the show view.



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/scaffolding/attribute.rb', line 163

def partial_name
  return options[:attribute] if options[:attribute]

  case type
  when "trix_editor", "ckeditor"
    "html"
  when "buttons", "super_select", "options", "boolean"
    if is_ids?
      "has_many"
    elsif is_id?
      "belongs_to"
    else
      "option#{"s" if is_multiple?}"
    end
  when "cloudinary_image"
    # TODO: We're preserving cloudinary_image here for backwards compatibility.
    # Remove it in a future major release.
    options[:height] = 200
    "image#{"s" if is_multiple?}"
  when "image"
    options[:height] = 200
    "image#{"s" if is_multiple?}"
  when "phone_field"
    "phone_number"
  when "date_field"
    "date"
  when "date_and_time_field"
    "date_and_time"
  when "email_field"
    "email"
  when "emoji_field"
    "text"
  when "color_picker"
    "code"
  when "text_field"
    "text"
  when "text_area"
    "text"
  when "file_field"
    "file#{"s" if is_multiple?}"
  when "password_field"
    "text"
  when "number_field"
    "number"
  when "address_field"
    "address"
  else
    raise "Invalid field type: #{type}."
  end
end

#plural_association_nameObject



61
62
63
# File 'lib/scaffolding/attribute.rb', line 61

def plural_association_name
  association_class_name.tableize
end

#special_processingObject



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/scaffolding/attribute.rb', line 227

def special_processing
  case type
  when "date_field"
    "assign_date(strong_params, :#{name})"
  when "date_and_time_field"
    "assign_date_and_time(strong_params, :#{name})"
  when "buttons"
    if is_boolean?
      "assign_boolean(strong_params, :#{name})"
    elsif is_multiple?
      "assign_checkboxes(strong_params, :#{name})"
    end
  when "options"
    if is_multiple?
      "assign_checkboxes(strong_params, :#{name})"
    end
  when "super_select"
    if is_boolean?
      "assign_boolean(strong_params, :#{name})"
    elsif is_multiple?
      "assign_select_options(strong_params, :#{name})"
    end
  end
end

#title_caseObject



147
148
149
150
151
152
153
154
155
156
# File 'lib/scaffolding/attribute.rb', line 147

def title_case
  if is_ids?
    # user_ids should be 'Users'
    name_without_ids.humanize.titlecase
  elsif is_id? && is_vanilla?
    "#{name.humanize.titlecase} ID"
  else
    name.humanize.titlecase
  end
end