flexi_model 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +122 -0
- data/lib/discover.rb +11 -0
- data/lib/flexi_model/ar_models/collection.rb +15 -0
- data/lib/flexi_model/ar_models/field.rb +36 -0
- data/lib/flexi_model/ar_models/record.rb +31 -0
- data/lib/flexi_model/ar_models/value.rb +52 -0
- data/lib/flexi_model/ar_models.rb +10 -0
- data/lib/flexi_model/ar_persistence.rb +318 -0
- data/lib/flexi_model/ar_queryable.rb +239 -0
- data/lib/flexi_model/association.rb +303 -0
- data/lib/flexi_model/attachment_field.rb +20 -0
- data/lib/flexi_model/callbacks.rb +41 -0
- data/lib/flexi_model/fields.rb +290 -0
- data/lib/flexi_model/filter.rb +61 -0
- data/lib/flexi_model/stub_persistence.rb +24 -0
- data/lib/flexi_model/validations.rb +37 -0
- data/lib/flexi_model.rb +38 -0
- data/lib/generators/flexi_model/install/install_generator.rb +20 -0
- data/lib/generators/flexi_model/install/templates/create_flexi_model_collections.rb +18 -0
- data/lib/generators/flexi_model/install/templates/create_flexi_model_collections_fields.rb +11 -0
- data/lib/generators/flexi_model/install/templates/create_flexi_model_fields.rb +20 -0
- data/lib/generators/flexi_model/install/templates/create_flexi_model_records.rb +12 -0
- data/lib/generators/flexi_model/install/templates/create_flexi_model_values.rb +17 -0
- metadata +92 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module ArQueryable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
RECORD = FlexiModel::ArPersistence::RECORD
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Return count of items from the model
|
9
|
+
def count
|
10
|
+
_build_criteria.count
|
11
|
+
end
|
12
|
+
|
13
|
+
# Alias to :count
|
14
|
+
def length;
|
15
|
+
self.count
|
16
|
+
end
|
17
|
+
|
18
|
+
# Find a record instance by id
|
19
|
+
# Returns model instance
|
20
|
+
def find(id_or_ids)
|
21
|
+
records = RECORD.includes(:values).where(id: id_or_ids)
|
22
|
+
|
23
|
+
if records.present?
|
24
|
+
if id_or_ids.is_a?(Array)
|
25
|
+
records.map { |_record| initialize_with_record(_record) }
|
26
|
+
else
|
27
|
+
initialize_with_record(records.first)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Load all records from the model
|
35
|
+
def all
|
36
|
+
_build_criteria
|
37
|
+
end
|
38
|
+
|
39
|
+
# Load first record from the model
|
40
|
+
def first
|
41
|
+
_build_criteria.first
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load last record from the model
|
45
|
+
def last
|
46
|
+
_build_criteria.last
|
47
|
+
end
|
48
|
+
|
49
|
+
# Apply conditions using hash map
|
50
|
+
def where(conditions = {})
|
51
|
+
_build_criteria.where(conditions)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def _build_criteria
|
56
|
+
Criteria.new(RECORD, self, self.get_flexi_namespace)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def count;
|
62
|
+
Criteria.new(RECORD, self, self.get_flexi_namespace).count
|
63
|
+
end
|
64
|
+
|
65
|
+
def length;
|
66
|
+
self.class.count
|
67
|
+
end
|
68
|
+
|
69
|
+
class Criteria
|
70
|
+
include Enumerable
|
71
|
+
|
72
|
+
attr_accessor :offset, :limit, :conditions, :host, :orders, :joins,
|
73
|
+
:groups, :select_field
|
74
|
+
attr_reader :target_model
|
75
|
+
|
76
|
+
protected :"joins=", :joins, :"orders=", :orders, :"groups=", :groups
|
77
|
+
|
78
|
+
def initialize(host, target_model, namespace)
|
79
|
+
@conditions = {namespace: namespace}
|
80
|
+
@joins = []
|
81
|
+
@orders = {}
|
82
|
+
@groups = []
|
83
|
+
@target_model = target_model
|
84
|
+
@select_object = nil
|
85
|
+
|
86
|
+
# By default Max 100 items will be retrieved
|
87
|
+
@limit = 100
|
88
|
+
@offset = 0
|
89
|
+
@host = host
|
90
|
+
@members = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def where(hash)
|
94
|
+
self._convert_query(hash)
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
def offset(num)
|
99
|
+
self.offset = num
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
def get_offset
|
104
|
+
@offset
|
105
|
+
end
|
106
|
+
|
107
|
+
def limit(num)
|
108
|
+
self.limit = num
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_limit
|
113
|
+
@limit
|
114
|
+
end
|
115
|
+
|
116
|
+
def select_field(field)
|
117
|
+
self.select_field = field
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
def destroy_all
|
122
|
+
_perform_query.destroy_all
|
123
|
+
end
|
124
|
+
|
125
|
+
DEFAULT_SORTABLE_FIELDS = [:created_at, :updated_at]
|
126
|
+
|
127
|
+
# Order query by the given field and order type
|
128
|
+
#
|
129
|
+
# key - field name in symbol or string
|
130
|
+
# order_type - order type :asc or :desc
|
131
|
+
# :asc - stands for ascending order
|
132
|
+
# :desc - stands for descending order
|
133
|
+
# Returns self instance
|
134
|
+
def order(key, order_type)
|
135
|
+
if DEFAULT_SORTABLE_FIELDS.include?(key.to_sym)
|
136
|
+
self.orders[key.to_sym] = order_type
|
137
|
+
else
|
138
|
+
field = _find_field(key)
|
139
|
+
_join_table :values
|
140
|
+
column = "`#{FlexiModel::ArModels::Value.table_name}`.`#{field.value_column}`"
|
141
|
+
self.orders[column] = order_type
|
142
|
+
self.groups << "`#{FlexiModel::ArModels::Record.table_name}`.`id`"
|
143
|
+
end
|
144
|
+
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def each(&block)
|
149
|
+
_members.each {|m| block.call _convert_to_model(m) }
|
150
|
+
end
|
151
|
+
|
152
|
+
def last
|
153
|
+
@target_model.initialize_with_record(_members.last)
|
154
|
+
end
|
155
|
+
|
156
|
+
def to_sql
|
157
|
+
self._perform_query.to_sql
|
158
|
+
end
|
159
|
+
|
160
|
+
protected
|
161
|
+
def _convert_query(hash = {})
|
162
|
+
hash.each do |k, v|
|
163
|
+
case k.to_sym
|
164
|
+
|
165
|
+
when :namespace
|
166
|
+
self.conditions[:namespace] = v
|
167
|
+
|
168
|
+
when :id
|
169
|
+
self.conditions[:id] = v
|
170
|
+
|
171
|
+
else
|
172
|
+
_join_table :values
|
173
|
+
|
174
|
+
# Find associated field
|
175
|
+
field = _find_field(k)
|
176
|
+
self.conditions["#{FlexiModel::ArModels::Value.table_name}.field_id"] = field.id
|
177
|
+
self.conditions["#{FlexiModel::ArModels::Value.table_name}.#{field.value_column.to_s}"] = v
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def _join_table(model)
|
183
|
+
unless @joins.include?(model)
|
184
|
+
@joins.push(model)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def _find_field(k)
|
189
|
+
field = (@empty_inst ||= @target_model.new)
|
190
|
+
.get_flexi_fields_map[k.to_sym]
|
191
|
+
raise "Invalid field - #{k}" unless field
|
192
|
+
|
193
|
+
field
|
194
|
+
end
|
195
|
+
|
196
|
+
def _convert_to_model(r)
|
197
|
+
_inst = @target_model.initialize_with_record(r)
|
198
|
+
if @select_field.present?
|
199
|
+
_inst.send(@select_field.to_sym)
|
200
|
+
else
|
201
|
+
_inst
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def _singular_field(class_name)
|
206
|
+
class_name.name.split('::').last.underscore
|
207
|
+
end
|
208
|
+
|
209
|
+
def _members
|
210
|
+
@members ||= _perform_query
|
211
|
+
end
|
212
|
+
|
213
|
+
def _perform_query
|
214
|
+
# Prepare conditions
|
215
|
+
_host = self.host
|
216
|
+
.where(self.conditions)
|
217
|
+
.limit(self.get_limit)
|
218
|
+
.offset(self.get_offset)
|
219
|
+
|
220
|
+
# Join tables
|
221
|
+
if self.joins.present?
|
222
|
+
_host = _host.joins(@joins)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Add orders
|
226
|
+
self.orders.each do |k, v|
|
227
|
+
_host = _host.order("#{k} #{v.to_sym == :desc ? 'DESC' : 'ASC'}")
|
228
|
+
end
|
229
|
+
|
230
|
+
# Add groups
|
231
|
+
if self.groups.present?
|
232
|
+
_host = _host.group(self.groups)
|
233
|
+
end
|
234
|
+
|
235
|
+
_host
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,303 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module Association
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_eval <<-ATTRS, __FILE__, __LINE__ + 1
|
7
|
+
cattr_accessor :associations
|
8
|
+
@@associations = {}
|
9
|
+
|
10
|
+
cattr_accessor :associated_classes
|
11
|
+
@@associated_classes = {}
|
12
|
+
ATTRS
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
# Create relationship between two flexi model based on primary key
|
18
|
+
def belongs_to(model_name, options = { })
|
19
|
+
_id_field = options[:foreign_key] || "#{model_name.to_s}_id"
|
20
|
+
_target_model = (options[:class_name] || model_name).to_s.classify
|
21
|
+
|
22
|
+
self.flexi_field _id_field.to_sym, :integer
|
23
|
+
|
24
|
+
# Generate dynamic finder method
|
25
|
+
_build_belongs_to_accessors model_name, _target_model, _id_field
|
26
|
+
|
27
|
+
self.associated_classes["#{model_name.to_s.singularize}_id".to_sym] =
|
28
|
+
_target_model.to_sym
|
29
|
+
|
30
|
+
(self.associations[:belongs_to] ||= []) << model_name
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create one to many relationship among the flexi models
|
34
|
+
#
|
35
|
+
# Options
|
36
|
+
# - :class_name - Target model class name
|
37
|
+
def has_many(model_name, options = { })
|
38
|
+
_class_name = (options[:class_name] ||
|
39
|
+
model_name.to_s.singularize.classify).to_sym
|
40
|
+
|
41
|
+
_build_has_many_accessors _class_name, model_name
|
42
|
+
|
43
|
+
self.associated_classes["#{model_name.to_s.singularize}_id".to_sym] =
|
44
|
+
_class_name.to_sym
|
45
|
+
(self.associations[:has_many] ||= []) << model_name
|
46
|
+
end
|
47
|
+
|
48
|
+
# Create many to many relationship between two flexi models based
|
49
|
+
# on foreign key
|
50
|
+
#
|
51
|
+
# Options
|
52
|
+
# - joining_class - You can define your joining class name or
|
53
|
+
# you can leave it to us to generate on the fly.
|
54
|
+
#
|
55
|
+
def has_and_belongs_to_many(method_name, options = { })
|
56
|
+
# Get joining class name (dev can specify over :joining_class option)
|
57
|
+
_self_ref, _class_name = _build_joining_class_name(method_name)
|
58
|
+
_joining_class_name = (options[:joining_class] || _class_name).to_sym
|
59
|
+
|
60
|
+
# Build field name
|
61
|
+
_fields = [_build_field_name(self.name), _build_field_name(method_name)]
|
62
|
+
|
63
|
+
# Eval dynamic joining class
|
64
|
+
_joining_class = _build_joining_class(
|
65
|
+
_joining_class_name, _fields, _self_ref)
|
66
|
+
|
67
|
+
# Create setter for setting all <target> records
|
68
|
+
_build_habtm_class_accessors(
|
69
|
+
_joining_class_name, method_name, _fields, _self_ref)
|
70
|
+
|
71
|
+
self.associated_classes["#{method_name.to_s.singularize}_id".to_sym] =
|
72
|
+
_joining_class.name.to_sym
|
73
|
+
(self.associations[:has_and_belongs_to_many] ||= []) << method_name
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return list of fields excluding relationship's foreign key for
|
77
|
+
def flexi_fields_except_fk
|
78
|
+
_field_names = self.associations.values.flatten.map { |_v| :"#{_v.to_s.singularize}_id" }
|
79
|
+
if none_flexi_fields.present?
|
80
|
+
none_flexi_fields.each do |field|
|
81
|
+
['file_name', 'content_type', 'file_size', 'updated_at'].each do |_suffix|
|
82
|
+
_field_names << :"#{field.name.to_s}_#{_suffix}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
self.flexi_fields.select { |_f| !_field_names.include?(_f.name.to_sym) }
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
def _build_belongs_to_accessors(model_name, target_model, id_field)
|
91
|
+
self.class_eval <<-ACCESSORS, __FILE__, __LINE__ + 1
|
92
|
+
# Return object instance
|
93
|
+
def #{model_name.to_s}
|
94
|
+
@#{model_name.to_s} ||= self.class.parent::#{target_model}.find(self.#{id_field})
|
95
|
+
end
|
96
|
+
|
97
|
+
def #{model_name.to_s}_type
|
98
|
+
:#{target_model.classify}
|
99
|
+
end
|
100
|
+
|
101
|
+
# Set object instance
|
102
|
+
def #{model_name.to_s}=(inst)
|
103
|
+
inst.save if inst.new_record?
|
104
|
+
self.#{id_field} = inst._id
|
105
|
+
@#{model_name.to_s} = inst
|
106
|
+
end
|
107
|
+
ACCESSORS
|
108
|
+
end
|
109
|
+
|
110
|
+
def _build_habtm_class_accessors(_class_name, method_name, _fields, self_ref)
|
111
|
+
_column_name = if self_ref
|
112
|
+
"first_id"
|
113
|
+
else
|
114
|
+
"#{_fields.first}_id"
|
115
|
+
end
|
116
|
+
|
117
|
+
self.class_eval <<-ACCESSORS, __FILE__, __LINE__ + 1
|
118
|
+
def #{method_name}_changed?; @#{method_name}_changed end
|
119
|
+
|
120
|
+
def #{method_name}
|
121
|
+
@#{method_name} ||= #{_class_name}.
|
122
|
+
#{self_ref ?
|
123
|
+
"where(:first_id => self._id).select_field(:second)" :
|
124
|
+
"where(#{_column_name}: self._id).select_field(:#{_fields.last})"}
|
125
|
+
end
|
126
|
+
|
127
|
+
def #{method_name.to_s.singularize}_ids=(ids)
|
128
|
+
@#{method_name.to_s.singularize}_ids = ids
|
129
|
+
self.#{method_name}= self.class.send(
|
130
|
+
:_find_class, :#{method_name.to_s.classify}).
|
131
|
+
where(id: ids).to_a
|
132
|
+
end
|
133
|
+
|
134
|
+
def #{method_name.to_s.singularize}_ids
|
135
|
+
@#{method_name.to_s.singularize}_ids ||= #{method_name}.to_a.compact.map(&:_id)
|
136
|
+
end
|
137
|
+
|
138
|
+
def #{method_name}=(an_array)
|
139
|
+
@#{method_name} = an_array
|
140
|
+
@#{method_name}_changed = true
|
141
|
+
end
|
142
|
+
|
143
|
+
after_save :_#{method_name}_after_save
|
144
|
+
after_update :_#{method_name}_after_update
|
145
|
+
|
146
|
+
def _#{method_name}_after_save
|
147
|
+
return if @#{method_name}.nil?
|
148
|
+
_create_#{method_name}_mappings!
|
149
|
+
end
|
150
|
+
|
151
|
+
def _#{method_name}_after_update
|
152
|
+
return if @#{method_name}.nil?
|
153
|
+
_update_#{method_name}_mappings!
|
154
|
+
end
|
155
|
+
|
156
|
+
def _update_#{method_name}_mappings!
|
157
|
+
_destroy_#{method_name}_mappings!
|
158
|
+
_create_#{method_name}_mappings!
|
159
|
+
end
|
160
|
+
|
161
|
+
def _destroy_#{method_name}_mappings!
|
162
|
+
#{_class_name}.where(#{_column_name}: self._id).destroy_all
|
163
|
+
end
|
164
|
+
|
165
|
+
def _create_#{method_name}_mappings!
|
166
|
+
@#{method_name}.each do |_target_inst|
|
167
|
+
_target_inst.save if _target_inst.new_record?
|
168
|
+
_map = #{_class_name}.create(
|
169
|
+
#{ self_ref ?
|
170
|
+
"first: self, second: _target_inst" :
|
171
|
+
"#{_fields.first}: self, #{_fields.last}: _target_inst"
|
172
|
+
}
|
173
|
+
)
|
174
|
+
|
175
|
+
raise _map.errors.inspect if _map.errors.present?
|
176
|
+
end
|
177
|
+
end
|
178
|
+
ACCESSORS
|
179
|
+
end
|
180
|
+
|
181
|
+
def _build_field_name(name)
|
182
|
+
name.to_s.split("::").last.underscore.singularize
|
183
|
+
end
|
184
|
+
|
185
|
+
def _build_joining_class(class_name, fields, self_ref)
|
186
|
+
_cls = self.send(:_find_class, class_name.to_s.split('::').last.to_sym)
|
187
|
+
_cls if _cls.present?
|
188
|
+
|
189
|
+
_relationships = ''
|
190
|
+
|
191
|
+
if self_ref
|
192
|
+
_relationships << <<-CODE
|
193
|
+
belongs_to :first, :class_name => :#{fields.first}
|
194
|
+
belongs_to :second, :class_name => :#{fields.last}
|
195
|
+
validates_presence_of :first_id, :second_id
|
196
|
+
CODE
|
197
|
+
else
|
198
|
+
_relationships << <<-CODE
|
199
|
+
belongs_to :#{fields.first}
|
200
|
+
belongs_to :#{fields.last}
|
201
|
+
validates_presence_of :#{fields.first}, :#{fields.last}
|
202
|
+
CODE
|
203
|
+
end
|
204
|
+
|
205
|
+
self.class_eval <<-CLASS, __FILE__, __LINE__ + 1
|
206
|
+
class #{class_name}
|
207
|
+
include FlexiModel
|
208
|
+
set_flexi_visible false
|
209
|
+
|
210
|
+
#{_relationships}
|
211
|
+
end
|
212
|
+
|
213
|
+
#{class_name}
|
214
|
+
CLASS
|
215
|
+
end
|
216
|
+
|
217
|
+
def _build_joining_class_name(model_name)
|
218
|
+
_parts = self.name.to_s.split("::")
|
219
|
+
_name = _parts.last
|
220
|
+
_self_ref = false
|
221
|
+
|
222
|
+
_name_parts = [model_name.to_s.pluralize.downcase,
|
223
|
+
_name.pluralize.downcase]
|
224
|
+
|
225
|
+
_class_name = if _name_parts.uniq.count == 2
|
226
|
+
_name_parts.sort.join('_').classify
|
227
|
+
else
|
228
|
+
_self_ref = true
|
229
|
+
_name_parts.join('_').classify
|
230
|
+
end
|
231
|
+
|
232
|
+
[_self_ref, if _parts.length > 1
|
233
|
+
"#{_parts[0..(_parts.length - 2)].join('::')}::#{_class_name}"
|
234
|
+
else
|
235
|
+
_class_name
|
236
|
+
end]
|
237
|
+
end
|
238
|
+
|
239
|
+
def _build_has_many_accessors(_class_name, _method)
|
240
|
+
_field_name = "#{self.name.underscore.split('/').last}_id"
|
241
|
+
|
242
|
+
self.class_eval <<-ACCESSORS, __FILE__, __LINE__ + 1
|
243
|
+
def #{_method}
|
244
|
+
@#{_method} ||= self.class.send(:_find_class, :#{_class_name}).where(#{_field_name}: self._id)
|
245
|
+
end
|
246
|
+
|
247
|
+
def #{_method}=(items)
|
248
|
+
@#{_method} = items
|
249
|
+
end
|
250
|
+
|
251
|
+
after_save :_#{_method}_after_save
|
252
|
+
|
253
|
+
def _#{_method}_after_save
|
254
|
+
return unless @#{_method}.present?
|
255
|
+
@#{_method}.each do |_item|
|
256
|
+
_item.update_attribute(#{_field_name}: self._id)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
ACCESSORS
|
261
|
+
end
|
262
|
+
|
263
|
+
def _find_class(_constant)
|
264
|
+
if self.parent && self.parent.constants.include?(_constant)
|
265
|
+
self.parent.const_get(_constant)
|
266
|
+
elsif self.class.parent.constants.include?(_constant)
|
267
|
+
self.class.parent.const_get(_constant)
|
268
|
+
elsif self.class.constants.include?(_constant)
|
269
|
+
self.class.const_get(_constant)
|
270
|
+
else
|
271
|
+
nil
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def _find_or_generate_joining_class(_class_name, _fields)
|
276
|
+
_class = _find_class _class_name
|
277
|
+
if _class.nil?
|
278
|
+
_generate_mapping_class _class_name, _fields.first, _fields.last
|
279
|
+
else
|
280
|
+
_class
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def _generate_mapping_class(name, _field_1, _field_2)
|
285
|
+
self.class_eval <<-CLASS, __FILE__, __LINE__ + 1
|
286
|
+
class #{name.to_s}
|
287
|
+
include FlexiModel
|
288
|
+
|
289
|
+
set_flexi_visible false
|
290
|
+
|
291
|
+
flexi_field :#{_field_1}_id, :integer
|
292
|
+
flexi_field :#{_field_2}_id, :integer
|
293
|
+
|
294
|
+
belongs_to :#{_field_1}
|
295
|
+
belongs_to :#{_field_2}
|
296
|
+
end
|
297
|
+
|
298
|
+
#{name.to_s}
|
299
|
+
CLASS
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module AttachmentField
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
# Set filed definition which is used as attachment accessor.
|
8
|
+
#
|
9
|
+
# Ie. Paperclip exposes < attachment name > method over the host class.
|
10
|
+
# Using this method we can hint admin panel that we have a field which
|
11
|
+
# accepts file
|
12
|
+
def attachment_field(name, options = { })
|
13
|
+
options[:accessors] = false
|
14
|
+
flexi_field name, :attachment, options
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :_attachment, :attachment_field
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module Callbacks
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extend ActiveModel::Callbacks
|
7
|
+
include ActiveModel::Validations::Callbacks
|
8
|
+
|
9
|
+
# Set callbacks
|
10
|
+
define_model_callbacks :save, :create, :update, :destroy, :initialize
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(*)
|
15
|
+
run_callbacks(:initialize) { super }
|
16
|
+
end
|
17
|
+
|
18
|
+
def save
|
19
|
+
run_callbacks(:save) { super }
|
20
|
+
end
|
21
|
+
|
22
|
+
def create
|
23
|
+
run_callbacks(:create) { super }
|
24
|
+
end
|
25
|
+
|
26
|
+
def update(*)
|
27
|
+
run_callbacks(:update) { super }
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_attributes(*)
|
31
|
+
run_callbacks(:update) { super }
|
32
|
+
end
|
33
|
+
|
34
|
+
def update_attribute(*)
|
35
|
+
run_callbacks(:update) { super }
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy
|
39
|
+
run_callbacks(:destroy) { super }
|
40
|
+
end
|
41
|
+
end
|