custom_fields 1.1.0.rc1 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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