Class: Locomotive::Mounter::Models::ContentEntry

Inherits:
Base
  • Object
show all
Defined in:
lib/locomotive/mounter/models/content_entry.rb

Instance Attribute Summary collapse

Attributes inherited from Base

#_id, #created_at, #mounting_point, #updated_at

Instance Method Summary collapse

Methods inherited from Base

#persisted?

Methods included from Fields

#attributes, #attributes_with_translations, #localized_field?, #to_yaml, #translated_in, #translated_in?

Constructor Details

#initializeObject

callbacks ##



23
# File 'lib/locomotive/mounter/models/content_entry.rb', line 23

set_callback :initialize, :after, :set_default_main_locale

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

The magic of dynamic fields happens within this method. It calls the getter/setter of a dynamic field if it is one of them.



213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/locomotive/mounter/models/content_entry.rb', line 213

def method_missing(name, *args, &block)
  if self.is_dynamic_field?(name)
    if name.to_s.ends_with?('=')
      name = find_dynamic_name(name)
      self.dynamic_setter(name, args.first)
    else
      self.dynamic_getter(name)
    end
  else
    super
  end
end

Instance Attribute Details

#dynamic_attributesObject

Returns the value of attribute dynamic_attributes.



17
18
19
# File 'lib/locomotive/mounter/models/content_entry.rb', line 17

def dynamic_attributes
  @dynamic_attributes
end

#errorsObject

Returns the value of attribute errors.



17
18
19
# File 'lib/locomotive/mounter/models/content_entry.rb', line 17

def errors
  @errors
end

#main_localeObject

Returns the value of attribute main_locale.



17
18
19
# File 'lib/locomotive/mounter/models/content_entry.rb', line 17

def main_locale
  @main_locale
end

Instance Method Details

#[](name) ⇒ Object



203
204
205
206
207
208
209
# File 'lib/locomotive/mounter/models/content_entry.rb', line 203

def [](name)
  if is_dynamic_field?(name)
    self.dynamic_getter(name.to_sym)
  else
    super
  end
end

#_labelString

Return the internal label used to identify a content entry in a YAML file for instance. It is based on the first field of the related content type.

Returns:

  • (String)

    The internal label



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/locomotive/mounter/models/content_entry.rb', line 44

def _label
  field = self.content_type.label_field
  value = self.dynamic_getter(field.name)

  if field.type == :belongs_to
    value.try(:_label)
  elsif field.type == :file
    value['url']
  else
    value
  end
end

#_slugObject Also known as: _permalink

fields ##



8
# File 'lib/locomotive/mounter/models/content_entry.rb', line 8

field :_slug,               localized: true

#dynamic_fieldsArray

Return the list of the fields defined in the content type for which there is a value assigned.

Returns:

  • (Array)

    The list of fields



79
80
81
82
83
# File 'lib/locomotive/mounter/models/content_entry.rb', line 79

def dynamic_fields
  self.dynamic_attributes.keys.map do |name|
    self.content_type.find_field(name)
  end
end

#dynamic_getter(name) ⇒ Object

Return the value of a dynamic field and cast it depending on the type of the field (string, date, belongs_to, …etc).

Parameters:

  • name (String/Symbol)

    Name of the dynamic field

Returns:

  • (Object)

    The casted value (String, Date, ContentEntry, …etc)



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/locomotive/mounter/models/content_entry.rb', line 136

def dynamic_getter(name)
  field = self.content_type.find_field(name)
  value = self.localized_dynamic_attribute_value(field)

  case field.type
  when :date, :date_time
    value.is_a?(String) ? Chronic.parse(value) : value
  when :file
    value.present? ? { 'url' => value, 'filename' => File.basename(value) } : nil
  when :belongs_to
    field.klass.find_entry(value)
  when :has_many
    field.klass.find_entries_by(field.inverse_of, [self._label, self._permalink])
  when :many_to_many
    field.klass.find_entries_among(value)
  else
    # :string, :text, :select, :boolean, :email, :integer, :float, :tags
    value
  end
end

#dynamic_setter(name, value) ⇒ Object

Set the value of a dynamic field. If the value is a hash, it assumes that it represents the translations.

Parameters:

  • name (String/Symbol)

    Name of the dynamic field

  • value (Object)

    Value to set



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/locomotive/mounter/models/content_entry.rb', line 163

def dynamic_setter(name, value)
  self.dynamic_attributes ||= {}
  self.dynamic_attributes[name.to_sym] ||= {}

  field = self.content_type.find_field(name)

  if value.is_a?(Hash) # already localized
    value.keys.each { |locale| self.add_locale(locale) }
    self.dynamic_attributes[name.to_sym].merge!(value.symbolize_keys)
  else
    if field.is_relationship? || !field.localized
      self.dynamic_attributes[name.to_sym] = value
    else
      self.add_locale(Locomotive::Mounter.locale)
      self.dynamic_attributes[name.to_sym][Locomotive::Mounter.locale] = value
    end
  end
end

#each_dynamic_field(&block) ⇒ Object

Loop over the list of dynamic fields defined in the content type for which there is a value assigned.

@example: each_dynamic_field { |field, value| .… }



90
91
92
93
94
95
96
97
# File 'lib/locomotive/mounter/models/content_entry.rb', line 90

def each_dynamic_field(&block)
  return unless block_given?

  self.dynamic_fields.each do |field|
    value = self.localized_dynamic_attribute_value(field)
    block.call(field, value)
  end
end

#find_dynamic_name(name) ⇒ Object

Find the name of a dynamic field from a String

Examples:

"name" references the name field
"name=" references the name field
"author_id" references the author field (belongs_to)
"article_ids" references the articles field (many_to_many)


118
119
120
121
122
123
124
125
126
127
# File 'lib/locomotive/mounter/models/content_entry.rb', line 118

def find_dynamic_name(name)
  name = name.to_s.gsub(/\=$/, '')

  # _id or _ids (belongs_to or many_to_many)
  if name =~ /(.+)_ids\Z/
    name = $1.pluralize
  end

  name.to_sym
end

#is_dynamic_field?(name) ⇒ Boolean

Determine if field passed in parameter is one of the dynamic fields.

Parameters:

  • name (String/Symbol)

    Name of the dynamic field

Returns:

  • (Boolean)

    True if it is a dynamic field



105
106
107
108
# File 'lib/locomotive/mounter/models/content_entry.rb', line 105

def is_dynamic_field?(name)
  name = find_dynamic_name(name)
  !self.content_type.try(:find_field, name).nil?
end

#localized?Boolean

By definition, if the label field defined in the content type is localized, then the content entry will be considered as localized.

Returns:

  • (Boolean)

    True if the label field is localized.



33
34
35
36
# File 'lib/locomotive/mounter/models/content_entry.rb', line 33

def localized?
  field = self.content_type.label_field
  !!field.try(:localized)
end

#to_hash(nested = true) ⇒ Hash

Return a hash with the label_field value as the key and the other fields as the value

Parameters:

  • nested (Boolean) (defaults to: true)

    True to have a hash of hash (whose key is the label)

Returns:

  • (Hash)

    A simple hash (nested to false) or a hash of hash



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/locomotive/mounter/models/content_entry.rb', line 232

def to_hash(nested = true)
  # no need of _position and _visible (unless it's false)
  hash = super.delete_if { |k, v| k == '_position' || (k == '_visible' && v == true) }

  # also no need of the content type
  hash.delete('content_type')

  # dynamic attributes
  hash.merge!(self.dynamic_attributes.deep_stringify_keys)

  # no need of the translation of the field name in the current locale
  label_field = self.content_type.label_field

  if label_field.localized
    if !hash[label_field.name].empty?
      hash[label_field.name].delete(Locomotive::Mounter.locale.to_s)

      hash.delete(label_field.name) if hash[label_field.name].empty?
    end
  else
    hash.delete(label_field.name)
  end

  nested ? { self._label => hash } : hash
end

#to_paramsHash

Return the main default params used for the API, meaning all except the dynamic fields which have to be defined outside the model.

Returns:

  • (Hash)

    The params



263
264
265
# File 'lib/locomotive/mounter/models/content_entry.rb', line 263

def to_params
  self.filter_attributes %w(_slug _position _visible seo_title meta_keywords meta_description)
end

#to_sObject



267
268
269
# File 'lib/locomotive/mounter/models/content_entry.rb', line 267

def to_s
  "#{self.content_type.slug} / #{self._slug}"
end

#valid?Boolean

Process a minimal validation by checking if the required fields are filled in or not.

Returns:

  • (Boolean)

    False if one of the required fields is missing.



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/locomotive/mounter/models/content_entry.rb', line 62

def valid?
  self.errors = []
  self.content_type.fields.each do |field|
    if field.required
      if self.dynamic_getter(field.name).blank?
        self.errors << field.name
      end
    end
  end
  self.errors.blank?
end

#write_attributes(attributes) ⇒ Object Also known as: attributes=

We also have to deal with dynamic attributes so that it does not raise an exception when calling the attributes= method.

Parameters:

  • attributes (Hash)

    The new attributes



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/locomotive/mounter/models/content_entry.rb', line 188

def write_attributes(attributes)
  _attributes = attributes.select do |name, value|
    if self.is_dynamic_field?(name)
      self.dynamic_setter(name, value)
      false
    else
      true
    end
  end

  super(_attributes)
end