gnuside-custom_fields 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.textile +70 -0
  4. data/config/locales/de.yml +15 -0
  5. data/config/locales/en.yml +21 -0
  6. data/config/locales/fr.yml +25 -0
  7. data/config/locales/pt-BR.yml +9 -0
  8. data/config/locales/ru.yml +15 -0
  9. data/lib/custom_fields/extensions/active_support.rb +28 -0
  10. data/lib/custom_fields/extensions/carrierwave.rb +25 -0
  11. data/lib/custom_fields/extensions/mongoid/document.rb +21 -0
  12. data/lib/custom_fields/extensions/mongoid/factory.rb +20 -0
  13. data/lib/custom_fields/extensions/mongoid/fields/i18n.rb +55 -0
  14. data/lib/custom_fields/extensions/mongoid/fields/localized.rb +39 -0
  15. data/lib/custom_fields/extensions/mongoid/fields.rb +31 -0
  16. data/lib/custom_fields/extensions/mongoid/relations/referenced/in.rb +22 -0
  17. data/lib/custom_fields/extensions/mongoid/relations/referenced/many.rb +34 -0
  18. data/lib/custom_fields/extensions/mongoid/validations/collection_size.rb +43 -0
  19. data/lib/custom_fields/extensions/mongoid/validations/macros.rb +25 -0
  20. data/lib/custom_fields/extensions/origin/smash.rb +33 -0
  21. data/lib/custom_fields/field.rb +106 -0
  22. data/lib/custom_fields/source.rb +347 -0
  23. data/lib/custom_fields/target.rb +99 -0
  24. data/lib/custom_fields/target_helpers.rb +192 -0
  25. data/lib/custom_fields/types/belongs_to.rb +65 -0
  26. data/lib/custom_fields/types/boolean.rb +55 -0
  27. data/lib/custom_fields/types/date.rb +97 -0
  28. data/lib/custom_fields/types/date_time.rb +97 -0
  29. data/lib/custom_fields/types/default.rb +103 -0
  30. data/lib/custom_fields/types/email.rb +60 -0
  31. data/lib/custom_fields/types/file.rb +74 -0
  32. data/lib/custom_fields/types/float.rb +52 -0
  33. data/lib/custom_fields/types/has_many.rb +74 -0
  34. data/lib/custom_fields/types/integer.rb +54 -0
  35. data/lib/custom_fields/types/many_to_many.rb +75 -0
  36. data/lib/custom_fields/types/money.rb +146 -0
  37. data/lib/custom_fields/types/relationship_default.rb +44 -0
  38. data/lib/custom_fields/types/select.rb +217 -0
  39. data/lib/custom_fields/types/string.rb +55 -0
  40. data/lib/custom_fields/types/tags.rb +35 -0
  41. data/lib/custom_fields/types/text.rb +65 -0
  42. data/lib/custom_fields/version.rb +6 -0
  43. data/lib/custom_fields.rb +74 -0
  44. metadata +244 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f86fd3a6c13622b1fe2e5bd94d46f9076554639d
4
+ data.tar.gz: d7b5676d0bf7cf6e845e1cf35cf4e0b67c60b4cb
5
+ SHA512:
6
+ metadata.gz: fa158bc35c5ee8b24870d941e6ebe07439a7e99ee1f4239bac8b8fb925aa12b20233d9b647906b93660f95a8a591c8263723bab6fc0a26d0e6d88bff64ff59d9
7
+ data.tar.gz: 17279f2aa0606472a81e468b01c39bffd77064faaf4e4e63a2c4e24aa4f275dfd22f82590b887d3c60ac9dd9b192526bb0b5eb716d359a7752d0a79b43fef772
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 [Didier Lafforgue]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,70 @@
1
+ "!https://secure.travis-ci.org/locomotivecms/custom_fields.png!":http://travis-ci.org/locomotivecms/custom_fields
2
+
3
+ h1. CustomFields
4
+
5
+ Manage custom fields to a mongoid document or a collection. This module is one of the core features we implemented in our custom cms, LocomotiveCMS.
6
+ Basically, its aim is to provide to editors a way to manage extra fields to a Mongoid document through, for instance, a web UI.
7
+
8
+ The main goals:
9
+
10
+ * offering a very secure way to add / edit / delete extra fields to a Mongoid document
11
+ * scoping the modifications added to a Mongoid document so that other documents of the same class won't be updated.
12
+
13
+ h2. Requirements
14
+
15
+ ActiveSupport 3.2.13, MongoDB 2.0 and Mongoid 3.1.3
16
+
17
+ h2. Examples
18
+
19
+ h3. On a has_many relationship
20
+
21
+ bc.. class Company
22
+ include CustomFields::Source
23
+
24
+ has_many :employees
25
+
26
+ custom_fields_for :employees
27
+ end
28
+
29
+ class Employee
30
+ include CustomFields::Target
31
+
32
+ field :name, String
33
+
34
+ belongs_to :company, :inverse_of => :employees
35
+ end
36
+
37
+ company = Company.new
38
+ company.employees_custom_fields.build :label => 'His/her position', :name => 'position', :type => 'string', :required => true
39
+
40
+ company.save
41
+
42
+ company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
43
+
44
+ another_company = Company.new
45
+ employee = another_company.employees.build
46
+ employee.position # returns a "not defined method" error
47
+
48
+ h3. On the class itself
49
+
50
+ [IN PROGRESS]
51
+
52
+ bc.. class Company
53
+ custom_fields_for_itself
54
+ end
55
+
56
+ company = Company.new
57
+ company.self_metadata_custom_fields.build :label => 'Shipping Address', :name => 'address', :type => 'text'
58
+
59
+ company.save
60
+
61
+ company.self_metadata.address = '700 S Laflin, 60607 Chicago'
62
+
63
+ another_company = Company.new
64
+ other_company.self_metadata.address # returns a "not defined method" error
65
+
66
+ h2. Contact
67
+
68
+ Feel free to contact me at didier at nocoffee dot fr.
69
+
70
+ Copyright (c) 2013 NoCoffee, released under the MIT license
@@ -0,0 +1,15 @@
1
+ de:
2
+ custom_fields:
3
+ type:
4
+ string: Einfacher Text
5
+ text: Formatierter Text
6
+ select: Auswahl-Liste
7
+ boolean: Auswahl-Box
8
+ integer: Ganzzahl
9
+ float: Fließkommazahl
10
+ money: Währung
11
+ date: Datum
12
+ file: Datei
13
+ belongs_to: gehört zu
14
+ has_many: Hat viele
15
+ many_to_many: Hat und gehört zu vielen
@@ -0,0 +1,21 @@
1
+ en:
2
+ custom_fields:
3
+ type:
4
+ string: Simple Input
5
+ text: Text
6
+ select: Select
7
+ boolean: Checkbox
8
+ date: Date
9
+ file: File
10
+ integer: Integer
11
+ float: Float
12
+ money: Money
13
+ email: E-mail
14
+ tags: Tags
15
+ belongs_to: Belongs to
16
+ has_many: Has many
17
+ many_to_many: Many To Many
18
+
19
+ errors:
20
+ messages:
21
+ at_least_one_element: "must have at least one element"
@@ -0,0 +1,25 @@
1
+ fr:
2
+ custom_fields:
3
+ type:
4
+ string: Texte
5
+ text: Zone de texte
6
+ select: Liste déroulante
7
+ boolean: Case à cocher
8
+ date: Date
9
+ integer: Nombre
10
+ file: Fichier
11
+ integer: Entier
12
+ float: Décimal
13
+ money: Monnaie
14
+ tags: Libellés
15
+ belongs_to: Appartient à
16
+ has_many: A plusieurs
17
+ many_to_many: A plusieurs et appartient à
18
+ text_formatting:
19
+ none: Aucun
20
+ html: HTML
21
+
22
+ errors:
23
+ messages:
24
+ blank: "doit être rempli(e)"
25
+ at_least_one_element: "doit avoir au moins un élément"
@@ -0,0 +1,9 @@
1
+ pt-BR:
2
+ custom_fields:
3
+ kind:
4
+ string: Texto Simples
5
+ text: Texto
6
+ category: Caixa de Seleção
7
+ boolean: Checkbox
8
+ date: Data
9
+ file: Arquivo
@@ -0,0 +1,15 @@
1
+ ru:
2
+ custom_fields:
3
+ type:
4
+ string: Простая строка
5
+ text: Текст
6
+ select: Выбор
7
+ boolean: Чекбокс
8
+ date: Дата
9
+ file: Файл
10
+ integer: Целое число
11
+ float: Число с дробной частью
12
+ money: Деньги
13
+ belongs_to: Относится к
14
+ has_many: Имеет много
15
+ many_to_many: Многие ко многим
@@ -0,0 +1,28 @@
1
+ class String
2
+
3
+ def constantize_with_custom_fields
4
+ begin
5
+ constantize_without_custom_fields
6
+ rescue NameError => exception
7
+ # DEBUG: puts "constantizing #{self.inspect}"
8
+ # alright, does it look like a custom_fields dynamic klass ?
9
+ if self =~ /(.*)([0-9a-fA-F]{24})$/
10
+ base = $1.constantize
11
+ # we can know it for sure
12
+ if base.with_custom_fields?
13
+ relation = base.relations.values.detect { |metadata| metadata[:custom_fields_parent_klass] == true }
14
+
15
+ # load the class which holds the recipe to build the dynamic klass
16
+ if relation && parent_instance = relation.klass.find($2)
17
+ # DEBUG: puts "re-building #{self}"
18
+ return parent_instance.klass_with_custom_fields(relation.inverse_of)
19
+ end
20
+ end
21
+ end
22
+ # not a custom_fields dynamic klass or unable to re-build it
23
+ raise exception
24
+ end
25
+ end
26
+
27
+ alias_method_chain :constantize, :custom_fields
28
+ end
@@ -0,0 +1,25 @@
1
+ require 'carrierwave/mongoid'
2
+
3
+ module CarrierWave
4
+
5
+ module Mongoid
6
+
7
+ def mount_uploader_with_localization(column, uploader=nil, options={}, &block)
8
+ mount_uploader_without_localization(column, uploader, options, &block)
9
+
10
+ define_method(:read_uploader) do |name|
11
+ # puts "read_uploader #{name} / #{read_attribute(name.to_sym).inspect}" # DEBUG
12
+
13
+ value = read_attribute(name.to_sym)
14
+ unless value.nil?
15
+ self.class.fields[name.to_s].demongoize(value)
16
+ else
17
+ nil
18
+ end
19
+ end
20
+ end
21
+
22
+ alias_method_chain :mount_uploader, :localization
23
+ end
24
+
25
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ module Document #:nodoc:
5
+
6
+ module ClassMethods #:nodoc:
7
+
8
+ # The mongoid default document returns always false.
9
+ # The documents with custom fields return true.
10
+ #
11
+ # @return [ Boolean ] False
12
+ #
13
+ def with_custom_fields?
14
+ false
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Instantiates documents that came from the database.
5
+ module Factory
6
+
7
+ def from_db_with_custom_fields(klass, attributes = {}, criteria_instance_id = nil)
8
+ if klass.with_custom_fields?
9
+ klass.klass_with_custom_fields(attributes['custom_fields_recipe'])
10
+ end
11
+ from_db_without_custom_fields(klass, attributes, criteria_instance_id)
12
+ end
13
+
14
+ # equivalent for "alias_method_chain :from_db, :custom_fields"
15
+ alias_method :from_db_without_custom_fields, :from_db unless method_defined?(:from_db_without_custom_fields)
16
+ alias_method :from_db, :from_db_with_custom_fields
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,55 @@
1
+ module Mongoid #:nodoc
2
+
3
+ # This module defines behaviour for fields.
4
+ module Fields
5
+
6
+ class I18n
7
+
8
+ attr_accessor :locale, :fallbacks
9
+
10
+ def self.instance
11
+ Thread.current[:mongoid_i18n] ||= Mongoid::Fields::I18n.new
12
+ end
13
+
14
+ def self.locale
15
+ self.instance.locale || ::I18n.locale
16
+ end
17
+
18
+ def self.locale=(value)
19
+ self.instance.locale = value.to_sym rescue nil
20
+ end
21
+
22
+ def self.fallbacks
23
+ if ::I18n.respond_to?(:fallbacks)
24
+ ::I18n.fallbacks
25
+ elsif !self.instance.fallbacks.blank?
26
+ self.instance.fallbacks
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ def self.fallbacks_for(locale, fallbacks)
33
+ self.instance.fallbacks ||= {}
34
+ self.instance.fallbacks[locale.to_sym] = fallbacks
35
+ end
36
+
37
+ def self.fallbacks?
38
+ ::I18n.respond_to?(:fallbacks) || !self.instance.fallbacks.blank?
39
+ end
40
+
41
+ def self.with_locale(new_locale = nil)
42
+ if new_locale
43
+ current_locale = self.locale
44
+ self.locale = new_locale
45
+ end
46
+ yield
47
+ ensure
48
+ self.locale = current_locale if new_locale
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Fields #:nodoc:
4
+
5
+ # The behaviour of the Localized fields in the custom fields gem is different
6
+ # because we do not rely on I18n directly but on a slight version Mongoid::Fields::I18n.
7
+ # The main reason is only practical to handle the following case:
8
+ # -> Back-office in English and editing content in French.
9
+ #
10
+ # TODO: use this gem instead https://github.com/simi/mongoid-localizer
11
+ #
12
+ class Localized < Standard
13
+
14
+ def mongoize(object)
15
+ { locale.to_s => type.mongoize(object) }
16
+ end
17
+
18
+ private
19
+
20
+ def lookup(object)
21
+ if !object.respond_to?(:keys) # if no translation hash is given, we return the object itself
22
+ object
23
+ elsif object.has_key?(locale.to_s)
24
+ object[locale.to_s]
25
+ elsif I18n.fallbacks?
26
+ object[I18n.fallbacks[locale].map(&:to_s).find { |loc| !object[loc].nil? }]
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ def locale
33
+ # be careful, it does not return ::I18n.locale
34
+ I18n.locale
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ module Mongoid #:nodoc
2
+
3
+ # This module defines behaviour for fields.
4
+ module Fields
5
+
6
+ module ClassMethods
7
+
8
+ # Replace a field with a new type.
9
+ #
10
+ # @example Replace the field.
11
+ # Model.replace_field("_id", String)
12
+ #
13
+ # @param [ String ] name The name of the field.
14
+ # @param [ Class ] type The new type of field.
15
+ # @param [ Boolean ] localize The option to localize or not the field.
16
+ #
17
+ # @return [ Serializable ] The new field.
18
+ #
19
+ # @since 2.1.0
20
+ def replace_field(name, type, localize = false)
21
+ # puts "fields[#{name}] = #{fields[name.to_s].inspect} / #{fields.keys.inspect}" # DEBUG
22
+ #attribute_names.delete_one(name)
23
+ remove_defaults(name)
24
+ add_field(name, fields[name.to_s].options.merge(type: type, localize: localize))
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Referenced #:nodoc:
5
+
6
+ class In < Relations::One
7
+
8
+ class << self
9
+
10
+ def valid_options_with_parent_class
11
+ valid_options_without_parent_class.push :custom_fields_parent_klass
12
+ end
13
+
14
+ alias_method_chain :valid_options, :parent_class
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Relations #:nodoc:
4
+ module Referenced #:nodoc:
5
+
6
+ # This class defines the behaviour for all relations that are a
7
+ # one-to-many between documents in different collections.
8
+ class Many < Relations::Many
9
+
10
+ def build_with_custom_fields(attributes = {}, options = {}, type = nil)
11
+ if base.respond_to?(:custom_fields_for?) && base.custom_fields_for?(metadata.name)
12
+ # all the information about how to build the custom class are stored here
13
+ recipe = base.custom_fields_recipe_for(metadata.name)
14
+
15
+ attributes ||= {}
16
+
17
+ attributes.merge!(custom_fields_recipe: recipe)
18
+
19
+ # build the class with custom_fields for the first time
20
+ type = metadata.klass.klass_with_custom_fields(recipe)
21
+ end
22
+ build_without_custom_fields(attributes, options, type)
23
+
24
+ end
25
+
26
+ alias_method_chain :build, :custom_fields
27
+
28
+ # new should point to the new build method
29
+ alias :new :build_with_custom_fields
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ module Mongoid
3
+ module Validations
4
+
5
+ # Validates that the specified collections do or do not match a certain
6
+ # size.
7
+ #
8
+ # @example Set up the collection size validator.
9
+ #
10
+ # class Person
11
+ # include Mongoid::Document
12
+ # has_many :addresses
13
+ #
14
+ # validates_collection_size_of :addresses, in: 1..10
15
+ # end
16
+ class CollectionSizeValidator < LengthValidator
17
+
18
+ def validate_each_with_collection(record, attribute, value)
19
+ value = collection_to_size(record, attribute)
20
+
21
+ self.validate_each_without_collection(record, attribute, value)
22
+ end
23
+
24
+ alias_method_chain :validate_each, :collection
25
+
26
+ private
27
+
28
+ def collection_to_size(record, attribute)
29
+ relation = record.relations[attribute.to_s]
30
+
31
+ source = case relation.macro
32
+ when :embeds_many, :has_many
33
+ record.send(attribute)
34
+ when :has_and_belongs_to_many
35
+ record.send(relation.key.to_sym)
36
+ end
37
+
38
+ OpenStruct.new(length: source.try(:size) || 0)
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ module Mongoid
2
+ module Validations
3
+ module Macros
4
+ extend ActiveSupport::Concern
5
+
6
+ # Validates the size of a collection.
7
+ #
8
+ # @example
9
+ # class Person
10
+ # include Mongoid::Document
11
+ # has_many :addresses
12
+ #
13
+ # validates_collection_size_of :addresses, minimum: 1
14
+ # end
15
+ #
16
+ # @param [ Array ] args The names of the fields to validate.
17
+ #
18
+ # @since 2.4.0
19
+ def validates_collection_size_of(*args)
20
+ validates_with(Mongoid::Validations::CollectionSizeValidator, _merge_attributes(args))
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ module Origin
3
+
4
+ # This is a smart hash for use with options and selectors.
5
+ class Smash < Hash
6
+
7
+ private
8
+
9
+ # Get the normalized value for the key. If localization is in play the
10
+ # current locale will be appended to the key in MongoDB dot notation.
11
+ #
12
+ # FIXME (Did).
13
+ # This version DOES NOT USE ::I18n.locale directly.
14
+ # See the localized.rb file for more explanation.
15
+ #
16
+ # @api private
17
+ #
18
+ # @example Get the normalized key name.
19
+ # smash.normalized_key("field", serializer)
20
+ #
21
+ # @param [ String ] name The name of the field.
22
+ # @param [ Object ] serializer The optional field serializer.
23
+ #
24
+ # @return [ String ] The normalized key.
25
+ #
26
+ # @since 1.0.0
27
+ def normalized_key(name, serializer)
28
+ # serializer && serializer.localized? ? "#{name}.#{::I18n.locale}" : name
29
+ serializer && serializer.localized? ? "#{name}.#{::Mongoid::Fields::I18n.locale}" : name
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,106 @@
1
+ module CustomFields
2
+
3
+ class Field
4
+
5
+ include ::Mongoid::Document
6
+ include ::Mongoid::Timestamps
7
+
8
+ AVAILABLE_TYPES = %w(default string text email date date_time boolean file select float integer
9
+ money tags relationship_default belongs_to has_many many_to_many)
10
+
11
+ ## types ##
12
+ AVAILABLE_TYPES.each do |type|
13
+ include "CustomFields::Types::#{type.camelize}::Field".constantize
14
+ end
15
+
16
+ ## fields ##
17
+ field :label
18
+ field :name
19
+ field :type
20
+ field :hint
21
+ field :position, type: ::Integer, default: 0
22
+ field :required, type: ::Boolean, default: false
23
+ field :unique, type: ::Boolean, default: false
24
+ field :localized, type: ::Boolean, default: false
25
+
26
+ ## validations ##
27
+ validates_presence_of :label, :type
28
+ validates_exclusion_of :name, in: lambda { |f| CustomFields.options[:reserved_names].map(&:to_s) }
29
+ validates_inclusion_of :type, in: AVAILABLE_TYPES, allow_blank: true
30
+ validates_format_of :name, with: /^[a-z]([A-Za-z0-9_]+)?$/
31
+ validate :uniqueness_of_label_and_name
32
+
33
+ ## callbacks ##
34
+ before_validation :set_name
35
+
36
+ ## methods ##
37
+
38
+ # Builds the mongodb updates based on
39
+ # the new state of the field.
40
+ # Call a different method if the field has a different behaviour.
41
+ #
42
+ # @param [ Hash ] memo Store the updates
43
+ #
44
+ # @return [ Hash ] The memo object upgraded
45
+ #
46
+ def collect_diff(memo)
47
+ method_name = :"collect_#{self.type}_diff"
48
+
49
+ if self.respond_to?(method_name)
50
+ self.send(method_name, memo)
51
+ else
52
+ collect_default_diff(memo)
53
+ end
54
+ end
55
+
56
+ # Returns the information (name, type, required, ...etc) needed to build
57
+ # the custom class.
58
+ # That will be stored into the target instance.
59
+ #
60
+ # @return [ Hash ] The hash
61
+ #
62
+ def to_recipe
63
+ method_name = :"#{self.type}_to_recipe"
64
+ custom_to_recipe = self.send(method_name) rescue {}
65
+
66
+ { 'name' => self.name,
67
+ 'type' => self.type,
68
+ 'required' => self.required?,
69
+ 'unique' => self.unique?,
70
+ 'localized' => self.localized? }.merge(custom_to_recipe)
71
+ end
72
+
73
+ def as_json(options = {})
74
+ method_name = :"#{self.type}_as_json"
75
+ custom_as_json = self.send(method_name) rescue {}
76
+
77
+ super(options).merge(custom_as_json)
78
+ end
79
+
80
+ protected
81
+
82
+ def uniqueness_of_label_and_name
83
+ if self.siblings.any? { |f| f.label == self.label && f._id != self._id }
84
+ self.errors.add(:label, :taken)
85
+ end
86
+
87
+ if self.siblings.any? { |f| f.name == self.name && f._id != self._id }
88
+ self.errors.add(:name, :taken)
89
+ end
90
+ end
91
+
92
+ def set_name
93
+ return if self.label.blank? && self.name.blank?
94
+
95
+ if self.name.blank?
96
+ self.name = self.label.parameterize('_').gsub('-', '_').downcase
97
+ end
98
+ end
99
+
100
+ def siblings
101
+ self._parent.send(self.metadata.name)
102
+ end
103
+
104
+ end
105
+
106
+ end