2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
# File 'lib/metadata/acts_as_metadata.rb', line 2
def acts_as_metadata(options={})
if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
scope = "#{options[:scope]}_id".to_sym
else
scope = nil
end
MetadataType.class_variable_set("@@metadata_scope", scope)
class_variable_set("@@metadata_scope", scope)
class_eval do
serialize :metadata_cache
has_many :metadata, :as => :model, :dependent => :destroy, :class_name => "Metadata::Metadata"
before_create :create_accessors_and_save_metadata
before_update :create_accessors_and_save_metadata
validate :metadata_constraints
def metadata_constraints
metadata_types.each do |type_name|
type = MetadataType.type(type_name, metadata_scope)
value = get_metadata(type.tag)
values = type.values.map {|v| v.is_a?(Array) ? v[1].to_s : v.to_s } rescue []
if value.is_a? Array
errors.add(type.tag, I18n.t('acts_as_metadata.errors.blank')) if type.mandatory && (value.blank? || value.map(&:blank?).reduce(:&))
value.each_with_index do |v, i|
errors.add("#{type.tag}_#{i}", I18n.t('acts_as_metadata.errors.format')) if values.blank? && type.format.present? && v.present? && v.to_s !~ Regexp.new("^#{type.format}$")
errors.add("#{type.tag}_#{i}", I18n.t('acts_as_metadata.errors.values')) if values.present? && v.present? && !values.include?(v)
end
else
errors.add(type.tag, I18n.t('acts_as_metadata.errors.blank')) if type.mandatory && value.blank?
errors.add(type.tag, I18n.t('acts_as_metadata.errors.format')) if values.blank? && type.format.present? && value.present? && value.to_s !~ Regexp.new("^#{type.format}$")
errors.add(type.tag, I18n.t('acts_as_metadata.errors.values')) if values.present? && value.present? && !values.include?(value.to_s)
end
end unless @skip_metadata_validation
end
def skip_metadata_validation!
@skip_metadata_validation = true
end
def mass_assignment_authorizer(role = :default)
super + metadata_types
end
def initialize(args=nil, options = {})
scope = self.class.class_variable_get('@@metadata_scope') ? args[self.class.class_variable_get('@@metadata_scope')] : nil rescue nil
types = MetadataType.model_types(model_name, scope)
types.each do |type|
create_accessor type
end
super
end
def update_attributes(attributes)
create_accessors
super
end
def create_accessors
metadata_types.each do |type|
create_accessor type
end
end
def create_accessor type
class_eval "attr_accessor :#{type}"
class_eval "def #{type}; get_metadata('#{type}'); end"
class_eval "def #{type}=(value); set_metadata('#{type}', value); end"
end
def create_accessors_and_save_metadata
create_accessors
save_metadata
end
def method_missing(meth, *args, &block)
begin
super
rescue NoMethodError
name = meth.to_s
if name =~ /^(.+)=$/
name = name[0..-2]
if metadata_types.include?(name)
set_metadata(name, args.first)
else
raise
end
else
if metadata_types.include?(name)
get_metadata(name)
else
raise
end
end
end
end
def metadata_scope
self.class.class_variable_get('@@metadata_scope') ? self.send(self.class.class_variable_get('@@metadata_scope')) : nil
end
def model_name
self.class.name.underscore.to_sym
end
def metadata_types
MetadataType.model_types(model_name, metadata_scope)
end
def self.metadata_types(scope=nil)
MetadataType.model_types(self.name.underscore.to_sym, scope)
end
def get_metadata(name)
load_metadata unless metadata_cache.is_a?(Hash)
metadata_cache[name].nil? ? MetadataType.type(name, metadata_scope).default : metadata_cache[name]
end
def set_metadata(name, value)
type = MetadataType.type(name, metadata_scope)
raise NoMethodError if type.nil?
load_metadata unless metadata_cache.is_a?(Hash)
self.metadata_cache[name] = type.type_cast(value) || type.type_cast(type.default)
self.metadata_cache[name] = [self.metadata_cache[name]].compact if type.multiple && !self.metadata_cache[name].is_a?(Array)
self.metadata_cache[name] = self.metadata_cache[name].first if !type.multiple && self.metadata_cache[name].is_a?(Array)
end
def save_metadata
Metadata::Metadata.delete_all(:model_type => self.class.name, :model_id => self.id) unless self.id.blank?
self.metadata_types.each do |type_name|
value = self.get_metadata(type_name)
if value.is_a? Array
value.each {|v| self.metadata.build(:metadata_type => type_name, :value => v) unless v.nil? }
else
self.metadata.build(:metadata_type => type_name, :value => value) unless value.nil?
end
end
end
def load_metadata
hash = {}
metadata.each do |m|
if hash[m.metadata_type].nil?
hash[m.metadata_type] = m.value
elsif hash[m.metadata_type].is_a? Array
hash[m.metadata_type] << m.value
else
hash[m.metadata_type] = [hash[m.metadata_type], m.value]
end
end
self.metadata_cache = {}
metadata_types.each {|type_name| set_metadata type_name, hash[type_name] }
end
end
end
|