has_dynamic_columns 0.1.1 → 0.2.0

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.
@@ -0,0 +1,12 @@
1
+ module HasDynamicColumns
2
+ module ActiveRecord
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+
6
+ end
7
+
8
+ module ClassMethods
9
+ include HasDynamicColumns::ActiveRecordRelation
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,231 @@
1
+ module HasDynamicColumns
2
+ module ActiveRecord
3
+ module QueryMethods
4
+ def self.included(base)
5
+
6
+ base.class_eval do
7
+ alias_method_chain :where, :dynamic_columns
8
+ alias_method_chain :build_arel, :dynamic_columns
9
+ end
10
+
11
+ base.instance_eval do
12
+ def has_dynamic_column_values=a
13
+ end
14
+ def has_dynamic_column_values
15
+ end
16
+ end
17
+ end
18
+
19
+ # When arel starts building - filter
20
+ def build_arel_with_dynamic_columns
21
+ #arel = Arel::SelectManager.new(table.engine, table)
22
+
23
+ # Calculate any dynamic scope that was passed
24
+ self.has_dynamic_columns_values.each { |dynamic_scope|
25
+ field_scope = dynamic_scope[:scope]
26
+ field_scope_id = (!field_scope.nil?) ? field_scope.id : nil
27
+ field_scope_type = (!field_scope.nil?) ? field_scope.class.name.constantize.to_s : nil
28
+
29
+ # TODO - make this work on compound arel queries like: table[:last_name].eq("Paterson").or(table[:first_name].eq("John"))
30
+ #collapsed = collapse_wheres(arel, dynamic_scope[:where])
31
+
32
+ dynamic_scope[:where].each_with_index { |rel, index|
33
+ case rel
34
+ when String
35
+ next
36
+ else
37
+ dynamic_type = rel.left.relation.engine.to_s
38
+ col_name = rel.left.name
39
+ value = rel.right
40
+ end
41
+
42
+ column_table = HasDynamicColumns::DynamicColumn.arel_table.alias("dynamic_where_#{index}_#{col_name}")
43
+ column_datum_table = HasDynamicColumns::DynamicColumnDatum.arel_table.alias("dynamic_where_data_#{index}_#{col_name}")
44
+
45
+ # Join on the column with the key
46
+ on_query = column_table[:key].eq(col_name)
47
+ on_query = on_query.and(
48
+ column_table[:field_scope_type].eq(field_scope_type)
49
+ ) unless field_scope_type.nil?
50
+
51
+ on_query = on_query.and(
52
+ column_table[:field_scope_id].eq(field_scope_id)
53
+ ) unless field_scope_id.nil?
54
+
55
+ column_table_join_on = column_table
56
+ .create_on(
57
+ on_query
58
+ )
59
+
60
+ column_table_join = table.create_join(column_table, column_table_join_on)
61
+ self.joins_values += [column_table_join]
62
+
63
+ arel_node = case rel
64
+ when Arel::Nodes::Equality
65
+ column_datum_table[:value].eq(value)
66
+ else
67
+ column_datum_table[:value].matches(value)
68
+ end
69
+
70
+ # Join on all the data with the provided key
71
+ column_table_datum_join_on = column_datum_table
72
+ .create_on(
73
+ column_datum_table[:owner_id].eq(table[:id]).and(
74
+ column_datum_table[:owner_type].eq(dynamic_type)
75
+ ).and(
76
+ column_datum_table[:dynamic_column_id].eq(column_table[:id])
77
+ ).and(
78
+ arel_node
79
+ )
80
+ )
81
+
82
+ column_table_datum_join = table.create_join(column_datum_table, column_table_datum_join_on)
83
+ self.joins_values += [column_table_datum_join]
84
+ }
85
+ }
86
+
87
+ build_arel_without_dynamic_columns
88
+ end
89
+
90
+ # lifted from
91
+ # http://erniemiller.org/2013/10/07/activerecord-where-not-sane-true/
92
+ module WhereChainCompatibility
93
+ #include ::ActiveRecord::QueryMethods
94
+ #define_method :build_where,
95
+ # ::ActiveRecord::QueryMethods.instance_method(:build_where)
96
+
97
+ # Extends where to chain a has_dynamic_columns method
98
+ # This builds all the joins needed to search the has_dynamic_columns_data tables
99
+ def has_dynamic_columns(opts = :chain, *rest)
100
+ # Map
101
+ dynamic_columns_value = {
102
+ :scope => nil,
103
+ :where => @scope.send(:build_where, opts, rest)
104
+ }
105
+ @scope.has_dynamic_columns_values = dynamic_columns_value
106
+
107
+ chain = ::ActiveRecord::QueryMethods::WhereChain.new(@scope)
108
+ chain.instance_eval do
109
+ # Make outer scope variable accessible
110
+ @dynamic_columns_value = dynamic_columns_value
111
+
112
+ # Extends where to chain with a has_scope method
113
+ # This scopes the where from above
114
+ def with_scope(opt)
115
+ @dynamic_columns_value[:scope] = opt
116
+
117
+ @scope
118
+ end
119
+ def without_scope
120
+ @scope
121
+ end
122
+ end
123
+
124
+ chain
125
+ end
126
+ end
127
+
128
+ def where_with_dynamic_columns(opts = :chain, *rest)
129
+ if opts == :chain
130
+ scope = spawn
131
+ chain = ::ActiveRecord::QueryMethods::WhereChain.new(scope)
132
+ chain.send(:extend, WhereChainCompatibility)
133
+ else
134
+ where_without_dynamic_columns(opts, rest)
135
+ end
136
+ end
137
+ =begin
138
+ def where_with_dynamic_columns(opts = :chain, *rest)
139
+ puts "--------------------------------------"
140
+ puts "Calling where_with_dynamic_columns"
141
+ puts opts.inspect
142
+ puts rest.inspect
143
+
144
+ if opts == :chain
145
+ scope = spawn
146
+ scope.extend(WhereChainCompatibility)
147
+ chain = ::ActiveRecord::QueryMethods::WhereChain.new(scope)
148
+ chain.instance_eval do
149
+ # Provide search on dynamic columns
150
+ def dynamic(opts, *rest)
151
+ options = rest.extract_options!
152
+ field_scope = opts.respond_to?(:class) && opts.class.respond_to?(:ancestors) && (opts.class.ancestors.include?(::ActiveRecord::Base)) ? opts : nil
153
+
154
+ # Field scope passed to the where clause
155
+ if !field_scope.nil?
156
+ opts = options
157
+ rest = []
158
+ end
159
+
160
+ field_scope_id = (!field_scope.nil?) ? field_scope.id : nil
161
+ field_scope_type = (!field_scope.nil?) ? field_scope.class.name.constantize.to_s : nil
162
+
163
+ # Join dynamic_column table
164
+ # This filter by scope if field_scope is passed
165
+ @scope.joins_values += @scope.send(:build_where, opts, rest).map do |rel|
166
+ dynamic_type = rel.left.relation.engine.to_s
167
+
168
+ col_name = rel.left.name
169
+ value = rel.right
170
+
171
+ table = dynamic_type.constantize.arel_table
172
+ column_table = ::HasDynamicColumns::DynamicColumn.arel_table.alias("dynamic_where_#{col_name}")
173
+
174
+ on_query = column_table[:key].eq(col_name)
175
+ if !field_scope_type.nil?
176
+ on_query = on_query.and(
177
+ column_table[:field_scope_type].eq(field_scope_type)
178
+ )
179
+ end
180
+ if !field_scope_id.nil?
181
+ on_query = on_query.and(
182
+ column_table[:field_scope_id].eq(field_scope_id)
183
+ )
184
+ end
185
+
186
+ column_table_join_on = column_table.create_on(on_query)
187
+ table.create_join(column_table, column_table_join_on)
188
+ end unless field_scope.nil?
189
+
190
+ # Join dynamic_column_data table
191
+ # This filters on data irrigardless of scope
192
+ join_value = @scope.send(:build_where, opts, rest).map do |rel|
193
+ dynamic_type = rel.left.relation.engine.to_s
194
+
195
+ col_name = rel.left.name
196
+ value = rel.right
197
+
198
+ table = dynamic_type.constantize.arel_table
199
+ column_table = ::HasDynamicColumns::DynamicColumn.arel_table.alias("dynamic_where_#{col_name}")
200
+ column_datum_table = ::HasDynamicColumns::DynamicColumnDatum.arel_table.alias("dynamic_where_data_#{col_name}")
201
+
202
+ # Join on all the data with the provided key
203
+ column_table_datum_join_on = column_datum_table
204
+ .create_on(
205
+ column_datum_table[:owner_id].eq(table[:id]).and(
206
+ column_datum_table[:owner_type].eq(dynamic_type)
207
+ ).and(
208
+ column_datum_table[:dynamic_column_id].eq(column_table[:id])
209
+ ).and(
210
+ column_datum_table[:value].matches("%"+value+"%")
211
+ )
212
+ )
213
+
214
+ table.create_join(column_datum_table, column_table_datum_join_on)
215
+ end
216
+ @scope.joins_values += join_value
217
+
218
+ @scope
219
+ end
220
+ end
221
+
222
+ chain
223
+ else
224
+ # Default where
225
+ where_without_dynamic_columns(opts, rest)
226
+ end
227
+ end
228
+ =end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,21 @@
1
+ module HasDynamicColumns
2
+ module ActiveRecord
3
+ module Relation
4
+ def self.included(base)
5
+ base.class_eval do
6
+ def has_dynamic_columns_values
7
+ @values[:has_dynamic_columns_values] || []
8
+ end
9
+ def has_dynamic_columns_values=values
10
+ raise ImmutableRelation if @loaded
11
+ @values[:has_dynamic_columns_values] ||= []
12
+ @values[:has_dynamic_columns_values] << values
13
+ end
14
+ end
15
+
16
+ base.instance_eval do
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,105 @@
1
+ module HasDynamicColumns
2
+ module ActiveRecordRelation
3
+ def self.included(base)
4
+ base.class_eval do
5
+ end
6
+
7
+ base.instance_eval do
8
+ end
9
+ end
10
+
11
+ # lifted from
12
+ # http://erniemiller.org/2013/10/07/activerecord-where-not-sane-true/
13
+ module WhereChainCompatibility
14
+ module_function
15
+ include ::ActiveRecord::QueryMethods
16
+ define_method :build_where,
17
+ ::ActiveRecord::QueryMethods.instance_method(:build_where)
18
+ end
19
+
20
+ def where(opts = :chain, *rest)
21
+ if opts == :chain
22
+ scope = spawn
23
+ scope.extend(WhereChainCompatibility)
24
+ chain = ::ActiveRecord::QueryMethods::WhereChain.new(scope)
25
+ chain.instance_eval do
26
+ # Provide search on dynamic columns
27
+ def dynamic(opts, *rest)
28
+ options = rest.extract_options!
29
+ field_scope = opts.respond_to?(:class) && opts.class.respond_to?(:ancestors) && (opts.class.ancestors.include?(::ActiveRecord::Base)) ? opts : nil
30
+
31
+ # Field scope passed to the where clause
32
+ if !field_scope.nil?
33
+ opts = options
34
+ rest = []
35
+ end
36
+
37
+ field_scope_id = (!field_scope.nil?) ? field_scope.id : nil
38
+ field_scope_type = (!field_scope.nil?) ? field_scope.class.name.constantize.to_s : nil
39
+
40
+ # Join dynamic_column table
41
+ # This filter by scope if field_scope is passed
42
+ @scope.joins_values += @scope.send(:build_where, opts, rest).map do |rel|
43
+ dynamic_type = rel.left.relation.engine.to_s
44
+
45
+ col_name = rel.left.name
46
+ value = rel.right
47
+
48
+ table = dynamic_type.constantize.arel_table
49
+ column_table = ::HasDynamicColumns::DynamicColumn.arel_table.alias("dynamic_where_#{col_name}")
50
+
51
+ on_query = column_table[:key].eq(col_name)
52
+ if !field_scope_type.nil?
53
+ on_query = on_query.and(
54
+ column_table[:field_scope_type].eq(field_scope_type)
55
+ )
56
+ end
57
+ if !field_scope_id.nil?
58
+ on_query = on_query.and(
59
+ column_table[:field_scope_id].eq(field_scope_id)
60
+ )
61
+ end
62
+
63
+ column_table_join_on = column_table.create_on(on_query)
64
+ table.create_join(column_table, column_table_join_on)
65
+ end unless field_scope.nil?
66
+
67
+ # Join dynamic_column_data table
68
+ # This filters on data irrigardless of scope
69
+ join_value = @scope.send(:build_where, opts, rest).map do |rel|
70
+ dynamic_type = rel.left.relation.engine.to_s
71
+
72
+ col_name = rel.left.name
73
+ value = rel.right
74
+
75
+ table = dynamic_type.constantize.arel_table
76
+ column_table = ::HasDynamicColumns::DynamicColumn.arel_table.alias("dynamic_where_#{col_name}")
77
+ column_datum_table = ::HasDynamicColumns::DynamicColumnDatum.arel_table.alias("dynamic_where_data_#{col_name}")
78
+
79
+ # Join on all the data with the provided key
80
+ column_table_datum_join_on = column_datum_table
81
+ .create_on(
82
+ column_datum_table[:owner_id].eq(table[:id]).and(
83
+ column_datum_table[:owner_type].eq(dynamic_type)
84
+ ).and(
85
+ column_datum_table[:dynamic_column_id].eq(column_table[:id])
86
+ ).and(
87
+ column_datum_table[:value].matches("%"+value+"%")
88
+ )
89
+ )
90
+
91
+ table.create_join(column_datum_table, column_table_datum_join_on)
92
+ end
93
+ @scope.joins_values += join_value
94
+
95
+ @scope
96
+ end
97
+ end
98
+
99
+ chain
100
+ else
101
+ super
102
+ end
103
+ end
104
+ end
105
+ end
@@ -1,5 +1,5 @@
1
1
  module HasDynamicColumns
2
- class DynamicColumn < ActiveRecord::Base
2
+ class DynamicColumn < ::ActiveRecord::Base
3
3
  has_many :dynamic_column_options, :class_name => "HasDynamicColumns::DynamicColumnOption"
4
4
  has_many :dynamic_column_validations, :class_name => "HasDynamicColumns::DynamicColumnValidation"
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module HasDynamicColumns
2
- class DynamicColumnDatum < ActiveRecord::Base
2
+ class DynamicColumnDatum < ::ActiveRecord::Base
3
3
  belongs_to :dynamic_column, :class_name => "HasDynamicColumns::DynamicColumn"
4
4
  belongs_to :dynamic_column_option, :class_name => "HasDynamicColumns::DynamicColumnOption"
5
5
  belongs_to :owner, :polymorphic => true
@@ -1,5 +1,5 @@
1
1
  module HasDynamicColumns
2
- class DynamicColumnOption < ActiveRecord::Base
2
+ class DynamicColumnOption < ::ActiveRecord::Base
3
3
  belongs_to :dynamic_column, :class_name => "HasDynamicColumns::DynamicColumn"
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module HasDynamicColumns
2
- class DynamicColumnValidation < ActiveRecord::Base
2
+ class DynamicColumnValidation < ::ActiveRecord::Base
3
3
  belongs_to :dynamic_column, :class_name => "HasDynamicColumns::DynamicColumn"
4
4
 
5
5
  def is_valid?(str)
@@ -0,0 +1,10 @@
1
+ require "has_dynamic_columns/model/class_methods"
2
+ require "has_dynamic_columns/model/instance_methods"
3
+
4
+ module HasDynamicColumns
5
+ module Model
6
+ def self.included(base)
7
+ base.send :extend, ClassMethods
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,294 @@
1
+ module HasDynamicColumns
2
+ module Model
3
+ module ClassMethods
4
+ def has_dynamic_columns(*args)
5
+ options = args.extract_options!
6
+ configuration = {
7
+ :as => "dynamic_columns",
8
+ :field_scope => nil,
9
+ }
10
+ configuration.update(options) if options.is_a?(Hash)
11
+
12
+ class_eval <<-EOV
13
+ alias_method :as_json_before_#{configuration[:as]}, :as_json
14
+
15
+ # Store all our configurations for usage later
16
+ @@has_dynamic_columns_configurations ||= []
17
+ @@has_dynamic_columns_configurations << #{configuration}
18
+
19
+ include ::HasDynamicColumns::Model::InstanceMethods
20
+
21
+ has_many :activerecord_dynamic_columns,
22
+ class_name: "HasDynamicColumns::DynamicColumn",
23
+ as: :field_scope
24
+ has_many :activerecord_dynamic_column_data,
25
+ class_name: "HasDynamicColumns::DynamicColumnDatum",
26
+ as: :owner,
27
+ autosave: true
28
+
29
+ # only add to attr_accessible
30
+ # if the class has some mass_assignment_protection
31
+ if defined?(accessible_attributes) and !accessible_attributes.blank?
32
+ #attr_accessible :#{configuration[:column]}
33
+ end
34
+
35
+ validate do |field_scope|
36
+ field_scope = self.get_#{configuration[:as]}_field_scope
37
+
38
+ if field_scope
39
+ # has_many association
40
+ if field_scope.respond_to?(:select) && field_scope.respond_to?(:collect)
41
+
42
+ # belongs_to association
43
+ else
44
+ # All the fields defined on the parent model
45
+ dynamic_columns = field_scope.send("activerecord_dynamic_columns")
46
+
47
+ self.send("activerecord_dynamic_column_data").each { |dynamic_column_datum|
48
+ # Collect all validation errors
49
+ validation_errors = []
50
+
51
+ if dynamic_column_datum.dynamic_column_option_id == -1
52
+ validation_errors << "invalid_option"
53
+ end
54
+
55
+ # Find the dynamic_column defined for this datum
56
+ dynamic_column = nil
57
+ dynamic_columns.each { |i|
58
+ if i == dynamic_column_datum.dynamic_column
59
+ dynamic_column = i
60
+ break
61
+ end
62
+ }
63
+ # We have a dynamic_column - validate
64
+ if dynamic_column
65
+ dynamic_column.dynamic_column_validations.each { |validation|
66
+ if !validation.is_valid?(dynamic_column_datum.value.to_s)
67
+ validation_errors << validation.error
68
+ end
69
+ }
70
+ else
71
+ # No field found - this is probably bad - should we throw an error?
72
+ validation_errors << "not_found"
73
+ end
74
+
75
+ # If any errors exist - add them
76
+ if validation_errors.length > 0
77
+ if dynamic_column.nil?
78
+ # TODO - fix from the has_many - need to fix validations
79
+ #errors.add(:dynamic_columns, { "unknown" => validation_errors })
80
+ else
81
+ errors.add(:dynamic_columns, { dynamic_column.key.to_s => validation_errors })
82
+ end
83
+ end
84
+ }
85
+ end
86
+ end
87
+ end
88
+
89
+ public
90
+ # Order by dynamic columns
91
+ def self.dynamic_order(field_scope, key, direction = :asc)
92
+ table = self.name.constantize.arel_table
93
+ column_table = HasDynamicColumns::DynamicColumn.arel_table.alias("dynamic_order_"+key.to_s)
94
+ column_datum_table = HasDynamicColumns::DynamicColumnDatum.arel_table.alias("dynamic_order_data_"+key.to_s)
95
+
96
+ field_scope_id = (!field_scope.nil?) ? field_scope.id : nil
97
+ field_scope_type = (!field_scope.nil?) ? field_scope.class.name.constantize.to_s : nil
98
+ dynamic_type = self.name.constantize.to_s
99
+
100
+ # Join on the column with the key
101
+ on_query = column_table[:key].eq(key)
102
+ if !field_scope_type.nil?
103
+ on_query = on_query.and(
104
+ column_table[:field_scope_type].eq(field_scope_type)
105
+ )
106
+ end
107
+ if !field_scope_id.nil?
108
+ on_query = on_query.and(
109
+ column_table[:field_scope_id].eq(field_scope_id)
110
+ )
111
+ end
112
+
113
+ column_table_join_on = column_table
114
+ .create_on(
115
+ on_query
116
+ )
117
+
118
+ column_table_join = table.create_join(column_table, column_table_join_on)
119
+ query = joins(column_table_join)
120
+
121
+ # Join on all the data with the provided key
122
+ column_table_datum_join_on = column_datum_table
123
+ .create_on(
124
+ column_datum_table[:owner_id].eq(table[:id]).and(
125
+ column_datum_table[:owner_type].eq(dynamic_type)
126
+ ).and(
127
+ column_datum_table[:dynamic_column_id].eq(column_table[:id])
128
+ )
129
+ )
130
+
131
+ column_table_datum_join = table.create_join(column_datum_table, column_table_datum_join_on)
132
+ query = query.joins(column_table_datum_join)
133
+
134
+ # Order
135
+ query = query.order(column_datum_table[:value].send(direction))
136
+
137
+ # Group required - we have many rows
138
+ query = query.group(table[:id])
139
+
140
+ query
141
+ end
142
+
143
+ # Find by dynamic columns
144
+ def self.dynamic_where(*args)
145
+ field_scope = args[0].is_a?(Hash) ? nil : args[0]
146
+ options = args.extract_options!
147
+
148
+ field_scope_id = (!field_scope.nil?) ? field_scope.id : nil
149
+ field_scope_type = (!field_scope.nil?) ? field_scope.class.name.constantize.to_s : nil
150
+ dynamic_type = self.name.constantize.to_s
151
+
152
+ table = self.name.constantize.arel_table
153
+ query = nil
154
+
155
+ # Need to join on each of the keys we are performing where on
156
+ options.each { |key, value|
157
+ # Don't bother with empty values
158
+ next if value.to_s.empty?
159
+
160
+ column_table = HasDynamicColumns::DynamicColumn.arel_table.alias("dynamic_where_"+key.to_s)
161
+ column_datum_table = HasDynamicColumns::DynamicColumnDatum.arel_table.alias("dynamic_where_data_"+key.to_s)
162
+
163
+ # Join on the column with the key
164
+ on_query = column_table[:key].eq(key)
165
+ if !field_scope_type.nil?
166
+ on_query = on_query.and(
167
+ column_table[:field_scope_type].eq(field_scope_type)
168
+ )
169
+ end
170
+ if !field_scope_id.nil?
171
+ on_query = on_query.and(
172
+ column_table[:field_scope_id].eq(field_scope_id)
173
+ )
174
+ end
175
+
176
+ column_table_join_on = column_table
177
+ .create_on(
178
+ on_query
179
+ )
180
+
181
+ column_table_join = table.create_join(column_table, column_table_join_on)
182
+ query = (query.nil?)? joins(column_table_join) : query.joins(column_table_join)
183
+
184
+ # Join on all the data with the provided key
185
+ column_table_datum_join_on = column_datum_table
186
+ .create_on(
187
+ column_datum_table[:owner_id].eq(table[:id]).and(
188
+ column_datum_table[:owner_type].eq(dynamic_type)
189
+ ).and(
190
+ column_datum_table[:dynamic_column_id].eq(column_table[:id])
191
+ ).and(
192
+ column_datum_table[:value].matches("%"+value+"%")
193
+ )
194
+ )
195
+
196
+ column_table_datum_join = table.create_join(column_datum_table, column_table_datum_join_on)
197
+ query = query.joins(column_table_datum_join)
198
+ }
199
+ # Group required - we have many rows
200
+ query = (query.nil?)? group(table[:id]) : query.group(table[:id])
201
+
202
+ query
203
+ end
204
+
205
+ def as_json(*args)
206
+ json = super(*args)
207
+ options = args.extract_options!
208
+
209
+ @@has_dynamic_columns_configurations.each { |config|
210
+ if !options[:root].nil?
211
+ json[options[:root]][config[:as].to_s] = self.send(config[:as].to_s)
212
+ else
213
+ json[config[:as].to_s] = self.send(config[:as].to_s)
214
+ end
215
+ }
216
+
217
+ json
218
+ end
219
+
220
+ # Setter for dynamic field data
221
+ def #{configuration[:as]}=data
222
+ data.each_pair { |key, value|
223
+ # We dont play well with this key
224
+ if !self.storable_#{configuration[:as].to_s.singularize}_key?(key)
225
+ raise NoMethodError
226
+ end
227
+ dynamic_column = self.#{configuration[:as].to_s.singularize}_key_to_dynamic_column(key)
228
+
229
+ # We already have this key in database
230
+ if existing = self.activerecord_dynamic_column_data.select { |i| i.dynamic_column == dynamic_column }.first
231
+ existing.value = value
232
+ else
233
+ self.activerecord_dynamic_column_data.build(:dynamic_column => dynamic_column, :value => value)
234
+ end
235
+ }
236
+ end
237
+
238
+ def #{configuration[:as]}
239
+ h = {}
240
+ self.field_scope_#{configuration[:as]}.each { |i|
241
+ h[i.key] = nil
242
+ }
243
+
244
+ self.activerecord_dynamic_column_data.each { |i|
245
+ h[i.dynamic_column.key] = i.value unless !i.dynamic_column || !h.has_key?(i.dynamic_column.key)
246
+ }
247
+
248
+ h
249
+ end
250
+
251
+ def #{configuration[:as].to_s.singularize}_keys
252
+ self.field_scope_#{configuration[:as]}.collect { |i| i.key }
253
+ end
254
+
255
+ def field_scope_#{configuration[:as]}
256
+ # has_many relationship
257
+ if self.get_#{configuration[:as]}_field_scope.respond_to?(:select) && self.get_#{configuration[:as]}_field_scope.respond_to?(:collect)
258
+ self.get_#{configuration[:as]}_field_scope.collect { |i|
259
+ i.send("activerecord_dynamic_columns")
260
+ }.flatten.select { |i|
261
+ i.dynamic_type.to_s.empty? || i.dynamic_type.to_s == self.class.to_s
262
+ }
263
+ # belongs_to relationship
264
+ else
265
+ self.get_#{configuration[:as]}_field_scope.send("activerecord_dynamic_columns").select { |i|
266
+ # Only get things with no dynamic type defined or dynamic types defined as this class
267
+ i.dynamic_type.to_s.empty? || i.dynamic_type.to_s == self.class.to_s
268
+ }
269
+ end
270
+ end
271
+
272
+ protected
273
+ def get_#{configuration[:as]}_field_scope
274
+ #{configuration[:field_scope]}
275
+ end
276
+
277
+ # Whether this is storable
278
+ def storable_#{configuration[:as].to_s.singularize}_key?(key)
279
+ self.#{configuration[:as].to_s.singularize}_keys.include?(key.to_s)
280
+ end
281
+
282
+ # Figures out which dynamic_column has which key
283
+ def #{configuration[:as].to_s.singularize}_key_to_dynamic_column(key)
284
+ found = nil
285
+ if record = self.send('field_scope_#{configuration[:as]}').select { |i| i.key == key.to_s }.first
286
+ found = record
287
+ end
288
+ found
289
+ end
290
+ EOV
291
+ end
292
+ end
293
+ end
294
+ end