custom_fields 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/MIT-LICENSE +1 -1
  2. data/README.textile +4 -4
  3. data/config/locales/de.yml +11 -5
  4. data/config/locales/en.yml +4 -0
  5. data/config/locales/fr.yml +4 -0
  6. data/config/locales/ru.yml +15 -0
  7. data/lib/custom_fields.rb +37 -27
  8. data/lib/custom_fields/extensions/active_support.rb +1 -1
  9. data/lib/custom_fields/extensions/carrierwave.rb +2 -2
  10. data/lib/custom_fields/extensions/mongoid/factory.rb +3 -3
  11. data/lib/custom_fields/extensions/mongoid/fields.rb +4 -3
  12. data/lib/custom_fields/extensions/mongoid/fields/localized.rb +39 -0
  13. data/lib/custom_fields/extensions/mongoid/relations/referenced/in.rb +1 -1
  14. data/lib/custom_fields/extensions/mongoid/relations/referenced/many.rb +3 -3
  15. data/lib/custom_fields/field.rb +14 -8
  16. data/lib/custom_fields/source.rb +23 -14
  17. data/lib/custom_fields/target.rb +16 -8
  18. data/lib/custom_fields/target_helpers.rb +6 -6
  19. data/lib/custom_fields/types/belongs_to.rb +4 -4
  20. data/lib/custom_fields/types/boolean.rb +1 -1
  21. data/lib/custom_fields/types/date.rb +2 -2
  22. data/lib/custom_fields/types/default.rb +5 -6
  23. data/lib/custom_fields/types/email.rb +60 -0
  24. data/lib/custom_fields/types/file.rb +2 -2
  25. data/lib/custom_fields/types/float.rb +52 -0
  26. data/lib/custom_fields/types/has_many.rb +6 -8
  27. data/lib/custom_fields/types/integer.rb +54 -0
  28. data/lib/custom_fields/types/many_to_many.rb +3 -3
  29. data/lib/custom_fields/types/money.rb +146 -0
  30. data/lib/custom_fields/types/relationship_default.rb +2 -2
  31. data/lib/custom_fields/types/select.rb +16 -13
  32. data/lib/custom_fields/types/tags.rb +35 -0
  33. data/lib/custom_fields/types/text.rb +1 -1
  34. data/lib/custom_fields/version.rb +1 -1
  35. metadata +65 -76
  36. data/init.rb +0 -2
  37. data/lib/custom_fields/extensions/mongoid/fields/internal/localized.rb +0 -86
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 [Didier Lafforgue]
1
+ Copyright (c) 2013 [Didier Lafforgue]
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.textile CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  h1. CustomFields
4
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 named Locomotive.
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
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
7
 
8
8
  The main goals:
@@ -12,7 +12,7 @@ The main goals:
12
12
 
13
13
  h2. Requirements
14
14
 
15
- ActiveSupport 3.2.9, MongoDB 2.0 and Mongoid 2.4.12
15
+ ActiveSupport 3.2.13, MongoDB 2.0 and Mongoid 3.1.3
16
16
 
17
17
  h2. Examples
18
18
 
@@ -42,7 +42,7 @@ company.save
42
42
  company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
43
43
 
44
44
  another_company = Company.new
45
- employee = company.employees.build
45
+ employee = another_company.employees.build
46
46
  employee.position # returns a "not defined method" error
47
47
 
48
48
  h3. On the class itself
@@ -67,4 +67,4 @@ h2. Contact
67
67
 
68
68
  Feel free to contact me at didier at nocoffee dot fr.
69
69
 
70
- Copyright (c) 2012 NoCoffee, released under the MIT license
70
+ Copyright (c) 2013 NoCoffee, released under the MIT license
@@ -1,9 +1,15 @@
1
1
  de:
2
2
  custom_fields:
3
3
  type:
4
- string: Einfache Texteingabe
5
- text: Text
6
- select: Auswahlbox
7
- boolean: Checkbox
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
8
11
  date: Datum
9
- file: Datei
12
+ file: Datei
13
+ belongs_to: gehört zu
14
+ has_many: Hat viele
15
+ many_to_many: Hat und gehört zu vielen
@@ -6,7 +6,11 @@ en:
6
6
  select: Select
7
7
  boolean: Checkbox
8
8
  date: Date
9
+ integer: Integer
9
10
  file: File
11
+ integer: Integer
12
+ float: Float
13
+ money: Money
10
14
  belongs_to: Belongs to
11
15
  has_many: Has many
12
16
  many_to_many: Many To Many
@@ -6,7 +6,11 @@ fr:
6
6
  select: Liste déroulante
7
7
  boolean: Case à cocher
8
8
  date: Date
9
+ integer: Nombre
9
10
  file: Fichier
11
+ integer: Entier
12
+ float: Décimal
13
+ money: Monnaie
10
14
  belongs_to: Appartient à
11
15
  has_many: A plusieurs
12
16
  many_to_many: A plusieurs et appartient à
@@ -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: Многие ко многим
data/lib/custom_fields.rb CHANGED
@@ -2,11 +2,13 @@ $:.unshift File.expand_path(File.dirname(__FILE__))
2
2
 
3
3
  require 'active_support'
4
4
  require 'carrierwave/mongoid'
5
+ require 'money'
5
6
 
6
7
  module CustomFields
7
8
 
8
9
  @@options = {
9
- :reserved_names => Mongoid.destructive_fields + %w(id _id send class)
10
+ reserved_names: Mongoid.destructive_fields + %w(id _id send class),
11
+ default_currency: 'EUR'
10
12
  }
11
13
 
12
14
  def self.options=(options)
@@ -19,31 +21,39 @@ module CustomFields
19
21
 
20
22
  end
21
23
 
22
- require 'custom_fields/version'
23
- require 'custom_fields/extensions/active_support'
24
- require 'custom_fields/extensions/carrierwave'
25
- require 'custom_fields/extensions/mongoid/document'
26
- require 'custom_fields/extensions/mongoid/factory'
27
- require 'custom_fields/extensions/mongoid/relations/referenced/many'
28
- require 'custom_fields/extensions/mongoid/relations/referenced/in'
29
- require 'custom_fields/extensions/mongoid/fields.rb'
30
- require 'custom_fields/extensions/mongoid/fields/i18n.rb'
31
- require 'custom_fields/extensions/mongoid/fields/internal/localized.rb'
32
- require 'custom_fields/types/default'
33
- require 'custom_fields/types/string'
34
- require 'custom_fields/types/text'
35
- require 'custom_fields/types/date'
36
- require 'custom_fields/types/boolean'
37
- require 'custom_fields/types/file'
38
- require 'custom_fields/types/select'
39
- require 'custom_fields/types/relationship_default'
40
- require 'custom_fields/types/belongs_to'
41
- require 'custom_fields/types/has_many'
42
- require 'custom_fields/types/many_to_many'
43
- require 'custom_fields/field'
44
- require 'custom_fields/source'
45
- require 'custom_fields/target_helpers'
46
- require 'custom_fields/target'
24
+ %w( version
25
+ extensions/active_support
26
+ extensions/carrierwave
27
+ extensions/mongoid/document
28
+ extensions/mongoid/factory
29
+ extensions/mongoid/relations/referenced/many
30
+ extensions/mongoid/relations/referenced/in
31
+ extensions/mongoid/fields.rb
32
+ extensions/mongoid/fields/i18n.rb
33
+ extensions/mongoid/fields/localized.rb
34
+ types/default
35
+ types/string
36
+ types/text
37
+ types/email
38
+ types/date
39
+ types/boolean
40
+ types/file
41
+ types/select
42
+ types/integer
43
+ types/float
44
+ types/money
45
+ types/relationship_default
46
+ types/belongs_to
47
+ types/has_many
48
+ types/many_to_many
49
+ types/tags
50
+ field
51
+ source
52
+ target_helpers
53
+ target
54
+ ).each do |lib|
55
+ require_relative "./custom_fields/#{lib}"
56
+ end
47
57
 
48
58
  # Load all the translation files
49
59
  I18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', 'config', 'locales', '*.yml')]
@@ -57,4 +67,4 @@ module MyBenchmark
57
67
  returned_value
58
68
  end
59
69
 
60
- end
70
+ end
@@ -25,4 +25,4 @@ class String
25
25
  end
26
26
 
27
27
  alias_method_chain :constantize, :custom_fields
28
- end
28
+ end
@@ -12,7 +12,7 @@ module CarrierWave
12
12
 
13
13
  value = read_attribute(name.to_sym)
14
14
  unless value.nil?
15
- self.class.fields[name.to_s].deserialize(value)
15
+ self.class.fields[name.to_s].demongoize(value)
16
16
  else
17
17
  nil
18
18
  end
@@ -22,4 +22,4 @@ module CarrierWave
22
22
  alias_method_chain :mount_uploader, :localization
23
23
  end
24
24
 
25
- end
25
+ end
@@ -4,11 +4,11 @@ module Mongoid #:nodoc:
4
4
  # Instantiates documents that came from the database.
5
5
  module Factory
6
6
 
7
- def from_db_with_custom_fields(klass, attributes = {})
7
+ def from_db_with_custom_fields(klass, attributes = {}, criteria_instance_id = nil)
8
8
  if klass.with_custom_fields?
9
9
  klass.klass_with_custom_fields(attributes['custom_fields_recipe'])
10
10
  end
11
- from_db_without_custom_fields(klass, attributes)
11
+ from_db_without_custom_fields(klass, attributes, criteria_instance_id)
12
12
  end
13
13
 
14
14
  # equivalent for "alias_method_chain :from_db, :custom_fields"
@@ -17,4 +17,4 @@ module Mongoid #:nodoc:
17
17
 
18
18
  end
19
19
 
20
- end
20
+ end
@@ -19,12 +19,13 @@ module Mongoid #:nodoc
19
19
  # @since 2.1.0
20
20
  def replace_field(name, type, localize = false)
21
21
  # puts "fields[#{name}] = #{fields[name.to_s].inspect} / #{fields.keys.inspect}" # DEBUG
22
- defaults.delete_one(name)
23
- add_field(name, fields[name.to_s].options.merge(:type => type, :localize => localize))
22
+ #attribute_names.delete_one(name)
23
+ remove_defaults(name)
24
+ add_field(name, fields[name.to_s].options.merge(type: type, localize: localize))
24
25
  end
25
26
 
26
27
  end
27
28
 
28
29
  end
29
30
 
30
- end
31
+ 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
@@ -17,4 +17,4 @@ module Mongoid # :nodoc:
17
17
 
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -14,13 +14,13 @@ module Mongoid #:nodoc:
14
14
 
15
15
  attributes ||= {}
16
16
 
17
- attributes.merge!(:custom_fields_recipe => recipe)
17
+ attributes.merge!(custom_fields_recipe: recipe)
18
18
 
19
19
  # build the class with custom_fields for the first time
20
20
  type = metadata.klass.klass_with_custom_fields(recipe)
21
21
  end
22
-
23
22
  build_without_custom_fields(attributes, options, type)
23
+
24
24
  end
25
25
 
26
26
  alias_method_chain :build, :custom_fields
@@ -31,4 +31,4 @@ module Mongoid #:nodoc:
31
31
 
32
32
  end
33
33
  end
34
- end
34
+ end
@@ -6,7 +6,8 @@ module CustomFields
6
6
  include ::Mongoid::Timestamps
7
7
 
8
8
  ## types ##
9
- %w(default string text date boolean file select relationship_default belongs_to has_many many_to_many).each do |type|
9
+ %w(default string text email date boolean file select float integer money
10
+ relationship_default belongs_to has_many many_to_many).each do |type|
10
11
  include "CustomFields::Types::#{type.classify}::Field".constantize
11
12
  end
12
13
 
@@ -15,14 +16,15 @@ module CustomFields
15
16
  field :name
16
17
  field :type
17
18
  field :hint
18
- field :position, :type => Integer, :default => 0
19
- field :required, :type => Boolean, :default => false
20
- field :localized, :type => Boolean, :default => false
19
+ field :position, type: ::Integer, default: 0
20
+ field :required, type: ::Boolean, default: false
21
+ field :unique, type: ::Boolean, default: false
22
+ field :localized, type: ::Boolean, default: false
21
23
 
22
24
  ## validations ##
23
25
  validates_presence_of :label, :type
24
- validates_exclusion_of :name, :in => lambda { |f| CustomFields.options[:reserved_names].map(&:to_s) }
25
- validates_format_of :name, :with => /^[a-z]([A-Za-z0-9_]+)?$/
26
+ validates_exclusion_of :name, in: lambda { |f| CustomFields.options[:reserved_names].map(&:to_s) }
27
+ validates_format_of :name, with: /^[a-z]([A-Za-z0-9_]+)?$/
26
28
  validate :uniqueness_of_label_and_name
27
29
 
28
30
  ## callbacks ##
@@ -58,7 +60,11 @@ module CustomFields
58
60
  method_name = :"#{self.type}_to_recipe"
59
61
  custom_to_recipe = self.send(method_name) rescue {}
60
62
 
61
- { 'name' => self.name, 'type' => self.type, 'required' => self.required?, 'localized' => self.localized? }.merge(custom_to_recipe)
63
+ { 'name' => self.name,
64
+ 'type' => self.type,
65
+ 'required' => self.required?,
66
+ 'unique' => self.unique?,
67
+ 'localized' => self.localized? }.merge(custom_to_recipe)
62
68
  end
63
69
 
64
70
  def as_json(options = {})
@@ -94,4 +100,4 @@ module CustomFields
94
100
 
95
101
  end
96
102
 
97
- end
103
+ end
@@ -65,7 +65,8 @@ module CustomFields
65
65
  {
66
66
  'name' => "#{self.relations[name.to_s].class_name.demodulize}#{self._id}",
67
67
  'rules' => self.ordered_custom_fields(name).map(&:to_recipe),
68
- 'version' => self.custom_fields_version(name)
68
+ 'version' => self.custom_fields_version(name),
69
+ 'model_name' => self.relations[name.to_s].class_name.constantize.model_name
69
70
  }
70
71
  end
71
72
 
@@ -111,10 +112,18 @@ module CustomFields
111
112
 
112
113
  metadata.instance_variable_set(:@klass, self.klass_with_custom_fields(name))
113
114
  end
114
-
115
+ set_attribute_localization(name)
115
116
  # puts "new_metadata = #{self.send(name).metadata.klass.inspect} / #{self.send(name).metadata.object_id.inspect}" # DEBUG
116
117
  end
117
118
 
119
+ def set_attribute_localization(name)
120
+ klass_name = name.singularize.to_sym
121
+ self.send(:"#{name}_custom_fields").each do |cf|
122
+ I18n.backend.store_translations ::I18n.locale,
123
+ {mongoid: { attributes: {klass_name => {cf.name.to_sym => cf.label}}}}
124
+ end
125
+ end
126
+
118
127
  # Initializes the object tracking the modifications
119
128
  # of the custom fields
120
129
  #
@@ -145,7 +154,7 @@ module CustomFields
145
154
  # collect fields with a modified localized field
146
155
  fields.each do |field|
147
156
  if field.localized_changed? && field.persisted?
148
- self._custom_field_localize_diff[name] << { :field => field.name, :localized => field.localized? }
157
+ self._custom_field_localize_diff[name] << { field: field.name, localized: field.localized? }
149
158
  end
150
159
  end
151
160
  end
@@ -165,14 +174,14 @@ module CustomFields
165
174
 
166
175
  # puts "selector = #{selector.inspect}, memo = #{attributes.inspect}" # DEBUG
167
176
 
168
- collection.update selector, operations, :multi => true
177
+ collection.find(selector).update operations, multi: true
169
178
  end
170
179
 
171
180
  # If the localized attribute has been changed in at least one of the custom fields,
172
181
  # we have to upgrade all the records enhanced by custom_fields in order to make
173
182
  # the values consistent with the mongoid localize option.
174
183
  #
175
- # Ex: post.attributes[:name] = 'Hello world' => post.attributes[:name] = { :en => 'Hello world' }
184
+ # Ex: post.attributes[:name] = 'Hello world' => post.attributes[:name] = { en: 'Hello world' }
176
185
  #
177
186
  # @param [ String, Symbol ] name The name of the relation.
178
187
  #
@@ -198,7 +207,7 @@ module CustomFields
198
207
  next if updates.empty?
199
208
 
200
209
  collection = self.send(name).collection
201
- collection.update record.atomic_selector, { '$set' => updates }
210
+ collection.find(record.atomic_selector).update({ '$set' => updates })
202
211
  end
203
212
  end
204
213
 
@@ -228,13 +237,13 @@ module CustomFields
228
237
  # end
229
238
  #
230
239
  # class Employee
231
- # embedded_in :company, :inverse_of => :employees
240
+ # embedded_in :company, inverse_of: :employees
232
241
  # field :name, String
233
242
  # end
234
243
  #
235
- # company.employees_custom_fields.build :label => 'His/her position', :name => 'position', :kind => 'string'
244
+ # company.employees_custom_fields.build label: 'His/her position', name: 'position', kind: 'string'
236
245
  # company.save
237
- # company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
246
+ # company.employees.build name: 'Michael Scott', position: 'Regional manager'
238
247
  #
239
248
  def custom_fields_for(name)
240
249
  self.declare_embedded_in_definition_in_custom_field(name)
@@ -254,11 +263,11 @@ module CustomFields
254
263
  #
255
264
  def extend_for_custom_fields(name)
256
265
  class_eval do
257
- field :"#{name}_custom_fields_version", :type => Integer, :default => 0
266
+ field :"#{name}_custom_fields_version", type: ::Integer, default: 0
258
267
 
259
- embeds_many :"#{name}_custom_fields", :class_name => self.dynamic_custom_field_class_name(name) #, :cascade_callbacks => true # FIXME ?????
268
+ embeds_many :"#{name}_custom_fields", class_name: self.dynamic_custom_field_class_name(name) #, cascade_callbacks: true # FIXME ?????
260
269
 
261
- accepts_nested_attributes_for :"#{name}_custom_fields", :allow_destroy => true
270
+ accepts_nested_attributes_for :"#{name}_custom_fields", allow_destroy: true
262
271
  end
263
272
 
264
273
  class_eval <<-EOV
@@ -324,7 +333,7 @@ module CustomFields
324
333
 
325
334
  unless source.const_defined?(klass_name)
326
335
  (klass = Class.new(::CustomFields::Field)).class_eval <<-EOF
327
- embedded_in :#{self.name.demodulize.underscore}, :inverse_of => :#{name}_custom_fields, :class_name => '#{self.name}'
336
+ embedded_in :#{self.name.demodulize.underscore}, inverse_of: :#{name}_custom_fields, class_name: '#{self.name}'
328
337
  EOF
329
338
 
330
339
  source.const_set(klass_name, klass)
@@ -335,4 +344,4 @@ module CustomFields
335
344
 
336
345
  end
337
346
 
338
- end
347
+ end