flexi_model 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.
- 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
|