custom_fields 1.0.0.beta.7 → 1.0.0.beta.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -55,7 +55,7 @@ module CustomFields
55
55
  class_eval <<-EOV
56
56
  embeds_one :#{collection_name}, :class_name => '::CustomFields::Metadata'
57
57
 
58
- def #{singular_name}
58
+ def safe_#{singular_name}
59
59
  self.#{collection_name} || self.build_#{collection_name}
60
60
  end
61
61
 
@@ -65,16 +65,20 @@ module CustomFields
65
65
  # common part
66
66
  class_eval <<-EOV
67
67
  field :#{singular_name}_custom_fields_counter, :type => Integer, :default => 0
68
+ field :#{singular_name}_custom_fields_version, :type => Integer, :default => 0
68
69
 
69
70
  embeds_many :#{singular_name}_custom_fields, :class_name => '#{dynamic_custom_field_class_name}'
70
71
 
71
- validates_associated :#{singular_name}_custom_fields
72
+ attr_accessor :invalidate_#{singular_name}_klass_flag
72
73
 
73
- after_validation do |record|
74
- if record.errors.empty?
75
- record.invalidate_#{singular_name}_klass
74
+ before_save do |record|
75
+ if record.invalidate_#{singular_name}_klass?
76
+ record.#{singular_name}_custom_fields_version ||= 0
77
+ record.#{singular_name}_custom_fields_version += 1
78
+ # puts "[parent/before_save] set #{singular_name}_custom_fields_version " + record.#{singular_name}_custom_fields_version.to_s # debug purpose
76
79
  end
77
80
  end
81
+
78
82
  after_destroy :invalidate_#{singular_name}_klass
79
83
 
80
84
  accepts_nested_attributes_for :#{singular_name}_custom_fields, :allow_destroy => true
@@ -88,13 +92,26 @@ module CustomFields
88
92
  metadata.klass.to_klass_with_custom_fields(self.ordered_#{singular_name}_custom_fields, self, metadata.name)
89
93
  end
90
94
 
95
+ def #{singular_name}_klass
96
+ metadata = self.relations['#{collection_name.to_s}']
97
+ metadata.klass.current_klass_with_custom_fields(self, metadata.name)
98
+ end
99
+
100
+ def #{singular_name}_klass_out_of_date?
101
+ self.#{singular_name}_klass.nil? || self.#{singular_name}_klass.version != self.#{singular_name}_custom_fields_version
102
+ end
103
+
91
104
  def invalidate_#{singular_name}_klass
92
105
  metadata = self.relations['#{collection_name.to_s}']
93
106
  metadata.klass.invalidate_proxy_class_with_custom_fields(self, metadata.name)
94
107
  end
108
+
109
+ def invalidate_#{singular_name}_klass?
110
+ self.invalidate_#{singular_name}_klass_flag == true
111
+ end
95
112
  EOV
96
113
 
97
- # mongoid tiny patch: for performance optimization (ie: we do want to invalidate klass every time we save a field)
114
+ # mongoid tiny patch: for performance optimization (ie: we do want to invalidate klass with custom fields every time we save a field)
98
115
  unless instance_methods.include?('write_attributes_with_custom_fields')
99
116
  class_eval do
100
117
  def write_attributes_with_custom_fields(attrs = nil)
@@ -34,7 +34,11 @@ module CustomFields
34
34
 
35
35
  ## callbacks ##
36
36
  before_validation :set_alias
37
- after_save :invalidate_klass
37
+ after_validation :set_target_klass_flag, :if => Proc.new { |f| f.changed? }
38
+
39
+ before_create :invalidate_target_klass
40
+ before_update :invalidate_target_klass
41
+ after_destroy :invalidate_target_klass
38
42
 
39
43
  ## methods ##
40
44
 
@@ -69,13 +73,7 @@ module CustomFields
69
73
  end
70
74
 
71
75
  def write_attributes_with_invalidation(attrs = nil)
72
- if self.association_name.to_s == '_metadata_custom_fields'
73
- target_name = 'metadata'
74
- else
75
- target_name = self.association_name.to_s.gsub('_custom_fields', '').pluralize
76
- end
77
-
78
- klass = self._parent.send(:"fetch_#{target_name.singularize}_klass")
76
+ klass = self._parent.send(:"fetch_#{singular_target_name}_klass")
79
77
 
80
78
  write_attributes_without_invalidation(attrs)
81
79
 
@@ -84,6 +82,14 @@ module CustomFields
84
82
 
85
83
  alias_method_chain :write_attributes, :invalidation
86
84
 
85
+ def singular_target_name
86
+ if self.association_name.to_s == '_metadata_custom_fields'
87
+ 'metadata'
88
+ else
89
+ self.association_name.to_s.gsub('_custom_fields', '').singularize
90
+ end
91
+ end
92
+
87
93
  def to_hash(more = {})
88
94
  self.fields.keys.inject({}) do |memo, meth|
89
95
  memo[meth] = self.send(meth.to_sym); memo
@@ -152,11 +158,20 @@ module CustomFields
152
158
 
153
159
  alias_method_chain :parentize, :custom_fields
154
160
 
155
- def invalidate_klass
156
- return if self._parent.instance_variable_get(:@_writing_attributes_with_custom_fields)
161
+ def invalidate_target_klass
162
+ # puts "[field/#{self.label}] invalidate_target_klass" # for debug purpose
163
+ if self._parent.instance_variable_get(:@_writing_attributes_with_custom_fields)
164
+ if self.destroyed? # force the parent to invalidate the related target class
165
+ self.set_target_klass_flag
166
+ end
167
+ else
168
+ self._parent.save
169
+ end
170
+ end
157
171
 
158
- target_name = self.association_name.to_s.gsub('_custom_fields', '')
159
- self._parent.send(:"invalidate_#{target_name}_klass")
172
+ def set_target_klass_flag
173
+ # puts "[field/set_target_klass_flag/#{self.label}] called" # debug purpose
174
+ self._parent.send(:"invalidate_#{self.singular_target_name}_klass_flag=", true)
160
175
  end
161
176
 
162
177
  end
@@ -24,8 +24,6 @@ module CustomFields
24
24
 
25
25
  alias_method_chain :parentize, :custom_fields
26
26
 
27
-
28
-
29
27
  end
30
28
 
31
29
  end
@@ -6,11 +6,16 @@ module CustomFields
6
6
  included do
7
7
 
8
8
  def self.to_klass_with_custom_fields(fields, parent, association_name)
9
- klass_name = self.klass_name_with_custom_fields(parent, association_name)
9
+ klass = self.current_klass_with_custom_fields(parent, association_name)
10
10
 
11
- klass = Object.const_defined?(klass_name) ? Object.const_get(klass_name): nil
11
+ # for debug purpose
12
+ # if klass.nil?
13
+ # puts "[#{association_name.to_s.gsub(/^_/, '').singularize} / #{parent.name rescue 'unknown'}] no klass found"
14
+ # else
15
+ # puts "[#{association_name.to_s.gsub(/^_/, '').singularize} / #{parent.name rescue 'unknown'}] klass nil ? #{klass.nil?} / current version ? #{klass.version.inspect} / parent ? #{self.custom_fields_version(parent, association_name)}" # for debug purpose
16
+ # end
12
17
 
13
- if klass && klass.built_at != parent.updated_at.try(:utc) # new version ?
18
+ if klass && klass.version != self.custom_fields_version(parent, association_name) # new version ?
14
19
  self.invalidate_proxy_class_with_custom_fields(parent, association_name)
15
20
  klass = nil
16
21
  end
@@ -18,13 +23,21 @@ module CustomFields
18
23
  if klass.nil?
19
24
  klass = self.build_proxy_class_with_custom_fields(fields, parent, association_name)
20
25
 
26
+ klass_name = self.klass_name_with_custom_fields(parent, association_name)
27
+
21
28
  Object.const_set(klass_name, klass)
22
29
  end
23
30
 
24
31
  klass
25
32
  end
26
33
 
34
+ def self.custom_fields_version(parent, association_name)
35
+ singular_name = association_name.to_s.gsub(/^_/, '').singularize
36
+ parent.send(:"#{singular_name}_custom_fields_version")
37
+ end
38
+
27
39
  def self.invalidate_proxy_class_with_custom_fields(parent, association_name)
40
+ # puts "-> invalidate_proxy_class_with_custom_fields !!!!!" # for debug purpose
28
41
  klass_name = self.klass_name_with_custom_fields(parent, association_name)
29
42
 
30
43
  if Object.const_defined?(klass_name)
@@ -32,14 +45,22 @@ module CustomFields
32
45
  end
33
46
  end
34
47
 
48
+ def self.current_klass_with_custom_fields(parent, association_name)
49
+ klass_name = self.klass_name_with_custom_fields(parent, association_name)
50
+
51
+ Object.const_defined?(klass_name) ? Object.const_get(klass_name): nil
52
+ end
53
+
35
54
  def self.klass_name_with_custom_fields(parent, association_name)
36
55
  "#{association_name.to_s.gsub(/^_/, '').singularize.camelize}#{parent.class.name.camelize}#{parent._id}"
37
56
  end
38
57
 
39
58
  def self.build_proxy_class_with_custom_fields(fields, parent, association_name)
59
+ # puts "BUILDING PROXY CLASS #{association_name} / parent version #{self.custom_fields_version(parent, association_name)}" # for debug purpose
60
+
40
61
  (klass = Class.new(self)).class_eval <<-EOF
41
62
 
42
- cattr_accessor :custom_fields, :_parent, :association_name, :built_at
63
+ cattr_accessor :custom_fields, :_parent, :association_name, :built_at, :version
43
64
 
44
65
  def self.model_name
45
66
  @_model_name ||= ActiveModel::Name.new(self.superclass)
@@ -90,7 +111,7 @@ module CustomFields
90
111
 
91
112
  [*fields].each { |field| klass.apply_custom_field(field) }
92
113
 
93
- klass.built_at = parent.updated_at.try(:utc)
114
+ klass.version = self.custom_fields_version(parent, association_name)
94
115
 
95
116
  klass
96
117
  end
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module CustomFields
3
- VERSION = "1.0.0.beta.7"
3
+ VERSION = "1.0.0.beta.8"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: custom_fields
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196365
4
+ hash: 62196371
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
10
  - beta
11
- - 7
12
- version: 1.0.0.beta.7
11
+ - 8
12
+ version: 1.0.0.beta.8
13
13
  platform: ruby
14
14
  authors:
15
15
  - Didier Lafforgue
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2011-03-18 00:00:00 +01:00
20
+ date: 2011-03-20 00:00:00 +01:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency