custom_fields 1.1.0.rc1 → 2.0.0.rc1

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 (41) hide show
  1. data/MIT-LICENSE +1 -1
  2. data/README.textile +14 -6
  3. data/config/locales/fr.yml +5 -1
  4. data/lib/custom_fields.rb +11 -37
  5. data/lib/custom_fields/extensions/carrierwave.rb +25 -0
  6. data/lib/custom_fields/extensions/mongoid/document.rb +12 -50
  7. data/lib/custom_fields/extensions/mongoid/factory.rb +20 -0
  8. data/lib/custom_fields/extensions/mongoid/fields.rb +29 -0
  9. data/lib/custom_fields/extensions/mongoid/fields/i18n.rb +53 -0
  10. data/lib/custom_fields/extensions/mongoid/fields/internal/localized.rb +84 -0
  11. data/lib/custom_fields/extensions/mongoid/relations/referenced/many.rb +29 -0
  12. data/lib/custom_fields/field.rb +44 -175
  13. data/lib/custom_fields/source.rb +333 -0
  14. data/lib/custom_fields/target.rb +90 -0
  15. data/lib/custom_fields/types/boolean.rb +26 -3
  16. data/lib/custom_fields/types/date.rb +36 -24
  17. data/lib/custom_fields/types/default.rb +44 -24
  18. data/lib/custom_fields/types/file.rb +35 -17
  19. data/lib/custom_fields/types/select.rb +184 -0
  20. data/lib/custom_fields/types/string.rb +25 -6
  21. data/lib/custom_fields/types/text.rb +35 -8
  22. data/lib/custom_fields/types_old/boolean.rb +13 -0
  23. data/lib/custom_fields/{types → types_old}/category.rb +0 -0
  24. data/lib/custom_fields/types_old/date.rb +49 -0
  25. data/lib/custom_fields/types_old/default.rb +44 -0
  26. data/lib/custom_fields/types_old/file.rb +27 -0
  27. data/lib/custom_fields/{types → types_old}/has_many.rb +0 -0
  28. data/lib/custom_fields/{types → types_old}/has_many/proxy_collection.rb +0 -0
  29. data/lib/custom_fields/{types → types_old}/has_many/reverse_lookup_proxy_collection.rb +0 -0
  30. data/lib/custom_fields/{types → types_old}/has_one.rb +0 -0
  31. data/lib/custom_fields/types_old/string.rb +13 -0
  32. data/lib/custom_fields/types_old/text.rb +15 -0
  33. data/lib/custom_fields/version.rb +1 -1
  34. metadata +115 -91
  35. data/lib/custom_fields/custom_fields_for.rb +0 -350
  36. data/lib/custom_fields/extensions/mongoid/relations/accessors.rb +0 -31
  37. data/lib/custom_fields/extensions/mongoid/relations/builders.rb +0 -30
  38. data/lib/custom_fields/proxy_class/base.rb +0 -112
  39. data/lib/custom_fields/proxy_class/builder.rb +0 -60
  40. data/lib/custom_fields/proxy_class/helper.rb +0 -57
  41. data/lib/custom_fields/self_metadata.rb +0 -30
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 [Didier Lafforgue]
1
+ Copyright (c) 2011 [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
@@ -1,7 +1,9 @@
1
+ "!https://secure.travis-ci.org/locomotivecms/custom_fields.png!":http://travis-ci.org/locomotivecms/custom_fields
2
+
1
3
  h1. CustomFields
2
4
 
3
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.
4
- Basically, its aim is to provide to editors a way to manage extra fields to a Mongoid document through for instance a web UI.
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.
5
7
 
6
8
  The main goals:
7
9
 
@@ -10,26 +12,30 @@ The main goals:
10
12
 
11
13
  h2. Requirements
12
14
 
13
- ActiveSupport 3.1.1, MongoDB 2.0 and Mongoid 2.3.2
15
+ ActiveSupport 3.1.3, MongoDB 2.0 and Mongoid 2.3.4
14
16
 
15
17
  h2. Examples
16
18
 
17
19
  h3. On a has_many relationship
18
20
 
19
21
  bc.. class Company
20
- embeds_many :employees
22
+ include CustomFields::Source
23
+
24
+ has_many :employees
21
25
 
22
26
  custom_fields_for :employees
23
27
  end
24
28
 
25
29
  class Employee
30
+ include CustomFields::Target
31
+
26
32
  field :name, String
27
33
 
28
- embedded_in :company, :inverse_of => :employees
34
+ belongs_to :company, :inverse_of => :employees
29
35
  end
30
36
 
31
37
  company = Company.new
32
- company.employees_custom_fields.build :label => 'His/her position', :_alias => 'position', :kind => 'string', :required => true
38
+ company.employees_custom_fields.build :label => 'His/her position', :name => 'position', :type => 'string', :required => true
33
39
 
34
40
  company.save
35
41
 
@@ -41,12 +47,14 @@ employee.position # returns a "not defined method" error
41
47
 
42
48
  h3. On the class itself
43
49
 
50
+ [IN PROGRESS]
51
+
44
52
  bc.. class Company
45
53
  custom_fields_for_itself
46
54
  end
47
55
 
48
56
  company = Company.new
49
- company.self_metadata_custom_fields.build :label => 'Shipping Address', :_alias => 'address', :kind => 'text'
57
+ company.self_metadata_custom_fields.build :label => 'Shipping Address', :name => 'address', :type => 'text'
50
58
 
51
59
  company.save
52
60
 
@@ -9,4 +9,8 @@ fr:
9
9
  file: Fichier
10
10
  text_formatting:
11
11
  none: Aucun
12
- html: HTML
12
+ html: HTML
13
+
14
+ errors:
15
+ messages:
16
+ blank: "doit être rempli(e)"
@@ -6,7 +6,7 @@ require 'carrierwave/mongoid'
6
6
  module CustomFields
7
7
 
8
8
  @@options = {
9
- :reserved_aliases => Mongoid.destructive_fields + %w(id _id send class)
9
+ :reserved_names => Mongoid.destructive_fields + %w(id _id send class)
10
10
  }
11
11
 
12
12
  def self.options=(options)
@@ -20,49 +20,23 @@ module CustomFields
20
20
  end
21
21
 
22
22
  require 'custom_fields/version'
23
- require 'custom_fields/extensions/active_support'
23
+ require 'custom_fields/extensions/carrierwave'
24
24
  require 'custom_fields/extensions/mongoid/document'
25
- require 'custom_fields/extensions/mongoid/relations/accessors'
26
- require 'custom_fields/extensions/mongoid/relations/builders'
25
+ require 'custom_fields/extensions/mongoid/factory'
26
+ require 'custom_fields/extensions/mongoid/relations/referenced/many'
27
+ require 'custom_fields/extensions/mongoid/fields.rb'
28
+ require 'custom_fields/extensions/mongoid/fields/i18n.rb'
29
+ require 'custom_fields/extensions/mongoid/fields/internal/localized.rb'
27
30
  require 'custom_fields/types/default'
28
31
  require 'custom_fields/types/string'
29
32
  require 'custom_fields/types/text'
30
- require 'custom_fields/types/category'
31
- require 'custom_fields/types/boolean'
32
33
  require 'custom_fields/types/date'
34
+ require 'custom_fields/types/boolean'
33
35
  require 'custom_fields/types/file'
34
- require 'custom_fields/types/has_one'
35
- require 'custom_fields/types/has_many/proxy_collection'
36
- require 'custom_fields/types/has_many/reverse_lookup_proxy_collection'
37
- require 'custom_fields/types/has_many'
38
- require 'custom_fields/proxy_class/base'
39
- require 'custom_fields/proxy_class/builder'
40
- require 'custom_fields/proxy_class/helper'
36
+ require 'custom_fields/types/select'
41
37
  require 'custom_fields/field'
42
- require 'custom_fields/self_metadata'
43
- require 'custom_fields/custom_fields_for'
44
-
45
- module Mongoid
46
- module CustomFields
47
- extend ActiveSupport::Concern
48
- included do
49
- extend ::CustomFields::ProxyClass::Helper
50
- include ::CustomFields::CustomFieldsFor
51
- end
52
- end
53
-
54
- module TargetCustomFields
55
- extend ActiveSupport::Concern
56
- included do
57
- extend ::CustomFields::ProxyClass::Helper
58
- extend ::CustomFields::ProxyClass::Builder
59
- end
60
- end
61
- end
62
-
63
- ActiveSupport::Inflector.inflections do |inflect|
64
- inflect.irregular 'metadata', 'metadata'
65
- end
38
+ require 'custom_fields/source'
39
+ require 'custom_fields/target'
66
40
 
67
41
  # Load all the translation files
68
42
  I18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', 'config', 'locales', '*.yml')]
@@ -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].deserialize(value)
16
+ else
17
+ nil
18
+ end
19
+ end
20
+ end
21
+
22
+ alias_method_chain :mount_uploader, :localization
23
+ end
24
+
25
+ end
@@ -1,59 +1,21 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
3
 
4
- # # This is the base module for all domain objects that need to be persisted to
5
- # # the database as documents.
6
- # module Document
7
- #
8
- # # Reloads the +Document+ attributes from the database. If the document has
9
- # # not been saved then an error will get raised if the configuration option
10
- # # was set.
11
- # #
12
- # # @example Reload the document.
13
- # # person.reload
14
- # #
15
- # # @raise [ Errors::DocumentNotFound ] If the document was deleted.
16
- # #
17
- # # @return [ Document ] The document, reloaded.
18
- # def reload_with_custom_fields
19
- # reload_without_custom_fields.tap do
20
- # instance_variable_names.each do |name|
21
- # if name =~ /_proxy_class$/
22
- # remove_instance_variable("#{name}")
23
- # end
24
- # end
25
- # end
26
- # end
27
- #
28
- # alias_method_chain :reload, :custom_fields
29
- #
30
- # end
4
+ module Document #:nodoc:
31
5
 
32
- # This is the base module for all domain objects that need to be persisted to
33
- # the database as documents.
34
- module Reloading
6
+ module ClassMethods #:nodoc:
35
7
 
36
- # Reloads the +Document+ attributes from the database. If the document has
37
- # not been saved then an error will get raised if the configuration option
38
- # was set.
39
- #
40
- # @example Reload the document.
41
- # person.reload
42
- #
43
- # @raise [ Errors::DocumentNotFound ] If the document was deleted.
44
- #
45
- # @return [ Document ] The document, reloaded.
46
- def reload_with_custom_fields
47
- reload_without_custom_fields.tap do
48
- instance_variable_names.each do |name|
49
- if name =~ /_proxy_class$/
50
- remove_instance_variable("#{name}")
51
- end
52
- end
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
53
15
  end
54
- end
55
16
 
56
- alias_method_chain :reload, :custom_fields
17
+ end
57
18
 
58
19
  end
59
- 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 = {})
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)
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,29 @@
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
+ defaults.delete_one(name)
22
+ add_field(name, fields[name].options.merge(:type => type, :localize => localize))
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,53 @@
1
+ module Mongoid #:nodoc
2
+
3
+ # This module defines behaviour for fields.
4
+ module Fields
5
+
6
+ class I18n
7
+
8
+ include Singleton
9
+
10
+ attr_accessor :locale, :fallbacks
11
+
12
+ def self.locale
13
+ self.instance.locale || ::I18n.locale
14
+ end
15
+
16
+ def self.locale=(value)
17
+ self.instance.locale = value.to_sym rescue nil
18
+ end
19
+
20
+ def self.fallbacks
21
+ if ::I18n.respond_to?(:fallbacks)
22
+ ::I18n.fallbacks
23
+ elsif !self.instance.fallbacks.blank?
24
+ self.instance.fallbacks
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ def self.fallbacks_for(locale, fallbacks)
31
+ self.instance.fallbacks ||= {}
32
+ self.instance.fallbacks[locale.to_sym] = fallbacks
33
+ end
34
+
35
+ def self.fallbacks?
36
+ ::I18n.respond_to?(:fallbacks) || !self.instance.fallbacks.blank?
37
+ end
38
+
39
+ def self.with_locale(new_locale = nil)
40
+ if tmp_locale
41
+ current_locale = self.locale
42
+ self.locale = new_locale
43
+ end
44
+ yield
45
+ ensure
46
+ self.locale = current_locale if new_locale
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Fields #:nodoc:
4
+ module Internal #:nodoc:
5
+
6
+ # Defines the behaviour for localized string fields.
7
+ class Localized
8
+
9
+ attr_accessor :original_field_type
10
+
11
+ class << self
12
+
13
+ # Instantiate 2 field types:
14
+ # - a wrapper in charge of dealing with the translations
15
+ # - the original field type to help to serialize / deserialize types
16
+ #
17
+ # @param [ Hash ] options The field options.
18
+ #
19
+ # @option options [ Class ] :type The class of the field.
20
+ # @option options [ Object ] :default The default value for the field.
21
+ # @option options [ String ] :label The field's label.
22
+ #
23
+ def instantiate_with_localize(name, options = {})
24
+ instantiate_without_localize(name, options).tap do |field|
25
+ field.original_field_type = Mappings.for(options[:type], options[:identity]).instantiate(name, options)
26
+ end
27
+ end
28
+
29
+ alias_method_chain :instantiate, :localize
30
+
31
+ end
32
+
33
+ # Deserialize the object based on the current locale. Will look in the
34
+ # hash for the current locale.
35
+ #
36
+ # @example Get the deserialized value.
37
+ # field.deserialize({ "en" => "testing" })
38
+ #
39
+ # @param [ Hash ] object The hash of translations.
40
+ #
41
+ # @return [ String ] The value for the current locale.
42
+ #
43
+ # @since 2.3.0
44
+ def deserialize(object)
45
+ return nil if object.nil?
46
+
47
+ # puts "deserializing...#{locale.inspect} / #{object.inspect}" # DEBUG
48
+
49
+ value = if I18n.fallbacks?
50
+ object[I18n.fallbacks[locale.to_sym].map(&:to_s).find { |loc| !object[loc].nil? }]
51
+ else
52
+ object[locale.to_s]
53
+ end
54
+
55
+ self.original_field_type.deserialize(value)
56
+ end
57
+
58
+ # Convert the provided string into a hash for the locale.
59
+ #
60
+ # @example Serialize the value.
61
+ # field.serialize("testing")
62
+ #
63
+ # @param [ String ] object The string to convert.
64
+ #
65
+ # @return [ Hash ] The locale with string translation.
66
+ #
67
+ # @since 2.3.0
68
+ def serialize(object)
69
+ # puts "serializing...#{locale} / #{object.inspect} / #{options.inspect}" # DEBUG
70
+
71
+ value = self.original_field_type.serialize(object)
72
+ { locale.to_s => value }
73
+ end
74
+
75
+ protected
76
+
77
+ def locale
78
+ I18n.locale
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,29 @@
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.merge!(:custom_fields_recipe => recipe)
16
+
17
+ # build the class with custom_fields for the first time
18
+ type = metadata.klass.klass_with_custom_fields(recipe)
19
+ end
20
+
21
+ build_without_custom_fields(attributes, options, type)
22
+ end
23
+
24
+ alias_method_chain :build, :custom_fields
25
+ end
26
+
27
+ end
28
+ end
29
+ end