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
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
flexi-model
|
2
|
+
===========
|
3
|
+
|
4
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/we4tech/flexi-model)
|
5
|
+
|
6
|
+
Build flexible database model with dynamic fields (right now based on ActiveRecord soon it will work with mongoid too)
|
7
|
+
|
8
|
+
How to do ?
|
9
|
+
===========
|
10
|
+
|
11
|
+
Define your first model.
|
12
|
+
---------
|
13
|
+
```ruby
|
14
|
+
class User
|
15
|
+
include FlexiModel
|
16
|
+
_string :name, :email
|
17
|
+
_text :bio
|
18
|
+
validates_presence_of :name, :email
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
Create your new record.
|
23
|
+
------------
|
24
|
+
```ruby
|
25
|
+
User.create name: 'hasan', email: 'hasan@welltreat.us', bio: 'Ruby developer'
|
26
|
+
#=> #<User:...>
|
27
|
+
```
|
28
|
+
|
29
|
+
Find record by id.
|
30
|
+
-----------
|
31
|
+
```ruby
|
32
|
+
User.find(1)
|
33
|
+
```
|
34
|
+
|
35
|
+
Find records by name
|
36
|
+
--------
|
37
|
+
```ruby
|
38
|
+
User.where(name: 'hasan')
|
39
|
+
#=> #<...::Criteria...> # Instance of criteria object
|
40
|
+
```
|
41
|
+
|
42
|
+
Define belongs to and has many relationship
|
43
|
+
---------
|
44
|
+
```ruby
|
45
|
+
class Blog
|
46
|
+
include FlexiModel
|
47
|
+
_string :title
|
48
|
+
_text :content
|
49
|
+
belongs_to :user
|
50
|
+
end
|
51
|
+
|
52
|
+
class User
|
53
|
+
include FlexiModel
|
54
|
+
_string :name
|
55
|
+
has_many :blogs
|
56
|
+
end
|
57
|
+
|
58
|
+
# Create records
|
59
|
+
user = User.create(name: 'nafi')
|
60
|
+
Blog.create(title: 'Hello world', content: 'Hello content', user: user)
|
61
|
+
|
62
|
+
# Find all related blogs
|
63
|
+
user.blogs
|
64
|
+
|
65
|
+
# Find parent record
|
66
|
+
user.blogs.first.user
|
67
|
+
```
|
68
|
+
|
69
|
+
Define has and belongs to many relationships
|
70
|
+
-----------
|
71
|
+
```ruby
|
72
|
+
class User
|
73
|
+
inlude FlexiModel
|
74
|
+
_string :name
|
75
|
+
has_and_belongs_to_many :roles
|
76
|
+
end
|
77
|
+
|
78
|
+
class Role
|
79
|
+
include FlexiModel
|
80
|
+
_string :name
|
81
|
+
has_and_belongs_to_many :users
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create user with roles
|
85
|
+
User.create(name: 'khan', roles: [Role.create(name: 'admin'), Role.create(name: 'moderator')])
|
86
|
+
|
87
|
+
# Find user roles
|
88
|
+
user = User.where(name: 'khan').first
|
89
|
+
user.roles
|
90
|
+
```
|
91
|
+
|
92
|
+
Update attribute
|
93
|
+
---------
|
94
|
+
```ruby
|
95
|
+
user = User.where(...)
|
96
|
+
user.update_attribute :name, 'raju'
|
97
|
+
```
|
98
|
+
|
99
|
+
Update attributes
|
100
|
+
-----------
|
101
|
+
```ruby
|
102
|
+
user = User.where(...)
|
103
|
+
user.update_attributes name: 'raju', email: 'hola@hola.com'
|
104
|
+
```
|
105
|
+
|
106
|
+
Destroy record
|
107
|
+
-------
|
108
|
+
```ruby
|
109
|
+
user.destroy
|
110
|
+
User.where(...conditions...).destroy_all
|
111
|
+
```
|
112
|
+
|
113
|
+
Observers
|
114
|
+
--------
|
115
|
+
* Before, After and Around Create
|
116
|
+
* Before, After and Around Update
|
117
|
+
* Before, After and Around Destroy
|
118
|
+
|
119
|
+
TODOS
|
120
|
+
=====
|
121
|
+
|
122
|
+
* Write documentation
|
data/lib/discover.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Include plugins
|
2
|
+
require 'autotest/fsevent'
|
3
|
+
require 'autotest/growl'
|
4
|
+
|
5
|
+
Autotest.add_discovery { "rspec2" }
|
6
|
+
|
7
|
+
# Skip some paths
|
8
|
+
Autotest.add_hook :initialize do |autotest|
|
9
|
+
%w{.idea .git .DS_Store ._* vendor}.each { |exception| autotest.add_exception(exception) }
|
10
|
+
false
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module ArModels
|
3
|
+
class Collection < ActiveRecord::Base
|
4
|
+
self.table_name = 'flexi_model_collections'
|
5
|
+
|
6
|
+
validates_presence_of :name
|
7
|
+
validates_uniqueness_of :name, :scope => :partition_id, :if => :partition_id
|
8
|
+
has_and_belongs_to_many :fields, :join_table => 'flexi_model_collections_fields'
|
9
|
+
has_many :records, :dependent => :destroy
|
10
|
+
|
11
|
+
attr_accessible :namespace, :name, :partition_id,
|
12
|
+
:singular_label, :plural_label, :fields
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module ArModels
|
3
|
+
class Field < ActiveRecord::Base
|
4
|
+
self.table_name = 'flexi_model_fields'
|
5
|
+
attr_accessible :name, :singular_label,:plural_label, :namespace,
|
6
|
+
:partition_id, :field_type, :default_value
|
7
|
+
|
8
|
+
COLUMNS_MAP = {
|
9
|
+
boolean: :bool_value,
|
10
|
+
integer: :int_value,
|
11
|
+
decimal: :dec_value,
|
12
|
+
float: :dec_value,
|
13
|
+
string: :str_value,
|
14
|
+
email: :str_value,
|
15
|
+
phone: :str_value,
|
16
|
+
location: :str_value,
|
17
|
+
address: :txt_value,
|
18
|
+
text: :txt_value,
|
19
|
+
multiple: :txt_value,
|
20
|
+
datetime: :dt_value,
|
21
|
+
date: :dt_value,
|
22
|
+
time: :dt_value
|
23
|
+
}
|
24
|
+
|
25
|
+
has_and_belongs_to_many :collections, :join_table => 'flexi_model_collections_fields'
|
26
|
+
has_many :values, :dependent => :destroy
|
27
|
+
|
28
|
+
validates_presence_of :name, :field_type
|
29
|
+
validates_uniqueness_of :name, :scope => [:namespace, :partition_id, :field_type]
|
30
|
+
|
31
|
+
def value_column
|
32
|
+
FlexiModel::ArModels::Field::COLUMNS_MAP[self.field_type.to_sym]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module ArModels
|
3
|
+
class Record < ActiveRecord::Base
|
4
|
+
self.table_name = 'flexi_model_records'
|
5
|
+
|
6
|
+
attr_accessible :collection_id, :namespace, :values, :values_attributes,
|
7
|
+
:collection
|
8
|
+
|
9
|
+
belongs_to :collection
|
10
|
+
has_many :values, :dependent => :destroy
|
11
|
+
has_many :fields, :through => :values
|
12
|
+
|
13
|
+
scope :by_namespace, lambda { |n| where(namespace: n) }
|
14
|
+
scope :recent, order('created_at DESC')
|
15
|
+
|
16
|
+
accepts_nested_attributes_for :values
|
17
|
+
|
18
|
+
def value_of(field_name)
|
19
|
+
values.select{|v| v.field.present? }.
|
20
|
+
select{|v| v.field.name.downcase == field_name.to_s.downcase}.first
|
21
|
+
end
|
22
|
+
|
23
|
+
def title
|
24
|
+
_value = value_of(:name) || value_of(:title)
|
25
|
+
return _value.value if _value.present?
|
26
|
+
|
27
|
+
self.collection.singular_label
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module ArModels
|
3
|
+
class Value < ActiveRecord::Base
|
4
|
+
self.table_name = 'flexi_model_values'
|
5
|
+
|
6
|
+
attr_accessible :record_id, :field_id, :bool_value, :int_value,
|
7
|
+
:dec_value, :str_value, :txt_value, :dt_value, :field,
|
8
|
+
:value
|
9
|
+
|
10
|
+
belongs_to :record
|
11
|
+
belongs_to :field
|
12
|
+
|
13
|
+
# Set value based on field type.
|
14
|
+
# ie. if it is `string` type it will store value in str_value
|
15
|
+
#
|
16
|
+
# List of field value mappings -
|
17
|
+
# Boolean 'bool_value'
|
18
|
+
# Integer 'int_value'
|
19
|
+
# Decimal 'dec_value'
|
20
|
+
# String 'str_value'
|
21
|
+
# Text 'txt_value'
|
22
|
+
# Datetime 'dt_value'
|
23
|
+
def value=(val)
|
24
|
+
self.send :"#{_mapped_value_column}=", val
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get value from corresponding column based on field type
|
28
|
+
def value
|
29
|
+
self.send :"#{_mapped_value_column}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def column_for_attribute(name)
|
33
|
+
if :value == name.to_sym
|
34
|
+
self.class.columns_hash[self.field.value_column.to_s]
|
35
|
+
else
|
36
|
+
self.class.columns_hash[name.to_s]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def _mapped_value_column
|
42
|
+
raise 'No field is set' if field.nil?
|
43
|
+
|
44
|
+
value_col =
|
45
|
+
FlexiModel::ArModels::Field::COLUMNS_MAP[field.field_type.to_sym]
|
46
|
+
raise "Unknown field type - #{field.field_type}" if value_col.nil?
|
47
|
+
|
48
|
+
value_col
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,318 @@
|
|
1
|
+
module FlexiModel
|
2
|
+
module ArPersistence
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
RECORD = FlexiModel::ArModels::Record
|
6
|
+
COLLECTION = FlexiModel::ArModels::Collection
|
7
|
+
FIELD = FlexiModel::ArModels::Field
|
8
|
+
VALUE = FlexiModel::ArModels::Value
|
9
|
+
|
10
|
+
included do
|
11
|
+
class_eval <<-RUBY
|
12
|
+
@@_flexi_collection = nil
|
13
|
+
cattr_accessor :_flexi_collection
|
14
|
+
|
15
|
+
@@_flexi_metadata = { }
|
16
|
+
cattr_accessor :_flexi_metadata
|
17
|
+
|
18
|
+
@@_flexi_fields_map = nil
|
19
|
+
cattr_accessor :_flexi_fields_map
|
20
|
+
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
# Set collection label
|
26
|
+
#
|
27
|
+
# singular - Set singular name for the collection
|
28
|
+
# plural - Set plural name for the collection
|
29
|
+
def set_flexi_label(singular, plural)
|
30
|
+
_flexi_metadata[:label_singular] = singular
|
31
|
+
_flexi_metadata[:label_plural] = plural
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return singular and plural collection label
|
35
|
+
# If not defined it will take class name as collection name
|
36
|
+
#
|
37
|
+
# Returns array of singular and plural labels
|
38
|
+
def get_flexi_label
|
39
|
+
labels = [_flexi_metadata[:label_singular],
|
40
|
+
_flexi_metadata[:label_plural]].compact
|
41
|
+
|
42
|
+
if labels.empty?
|
43
|
+
_f_name = _friendly_name(self.name)
|
44
|
+
[_f_name.singularize, _f_name.pluralize]
|
45
|
+
else
|
46
|
+
labels
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return collection name based on parametrized class name
|
51
|
+
def flexi_collection_name
|
52
|
+
self.name.parameterize
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_flexi_namespace
|
56
|
+
self.flexi_collection_name.parameterize
|
57
|
+
end
|
58
|
+
|
59
|
+
# Initialize new instance and set data from record
|
60
|
+
def initialize_with_record(record)
|
61
|
+
inst = self.new
|
62
|
+
inst.send(:_record=, record)
|
63
|
+
inst.send(:_id=, record.id)
|
64
|
+
inst
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return by default plural label
|
68
|
+
def flexi_label(singular = false)
|
69
|
+
if singular
|
70
|
+
self._flexi_collection.singular_label
|
71
|
+
else
|
72
|
+
self._flexi_collection.plural_label
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def flexi_collection;
|
77
|
+
_flexi_collection
|
78
|
+
end
|
79
|
+
|
80
|
+
delegate :id, :to => :_flexi_collection
|
81
|
+
|
82
|
+
def destroy_all;
|
83
|
+
RECORD.by_namespace(self.get_flexi_namespace).each do |record|
|
84
|
+
inst = initialize_with_record(record)
|
85
|
+
inst.destroy
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete_all;
|
90
|
+
RECORD.by_namespace(self.get_flexi_namespace).delete_all
|
91
|
+
end
|
92
|
+
|
93
|
+
# Create does exactly as `save`, but it initiates `:create` callbacks
|
94
|
+
def create(attributes = { })
|
95
|
+
inst = self.new(attributes)
|
96
|
+
inst.save
|
97
|
+
|
98
|
+
inst
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
def _friendly_name(long_name)
|
103
|
+
long_name.to_s.split("::").last
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize(*)
|
108
|
+
super
|
109
|
+
_find_or_update_or_build_collection!
|
110
|
+
end
|
111
|
+
|
112
|
+
# Ensure object with same _id returns true on equality check
|
113
|
+
def ==(another_instance)
|
114
|
+
self._id && self._id == another_instance._id
|
115
|
+
end
|
116
|
+
|
117
|
+
# Return true if record is not saved
|
118
|
+
def new_record?
|
119
|
+
!_id.present?
|
120
|
+
end
|
121
|
+
|
122
|
+
# Store record in persistent storage
|
123
|
+
def save
|
124
|
+
create_or_update
|
125
|
+
_id.present?
|
126
|
+
end
|
127
|
+
|
128
|
+
# Update stored attributes by give hash
|
129
|
+
def update_attributes(_params)
|
130
|
+
assign_attributes _params
|
131
|
+
save
|
132
|
+
end
|
133
|
+
|
134
|
+
# Update single attribute by key and value
|
135
|
+
def update_attribute(key, value)
|
136
|
+
self.update_attributes(key => value)
|
137
|
+
end
|
138
|
+
|
139
|
+
def destroy
|
140
|
+
if _id.present?
|
141
|
+
RECORD.delete(self._id)
|
142
|
+
else
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Reload object instance
|
148
|
+
def reload
|
149
|
+
self.class.find(self._id)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Forcefully load all attributes
|
153
|
+
def load_attributes!
|
154
|
+
self.flexi_fields.map { |f| self.send(f.name.to_sym) }
|
155
|
+
end
|
156
|
+
|
157
|
+
# Return existing or create new collection set
|
158
|
+
def get_flexi_collection
|
159
|
+
_find_or_update_or_build_collection!
|
160
|
+
|
161
|
+
self._flexi_collection
|
162
|
+
end
|
163
|
+
|
164
|
+
# Return flexi fields in name and field object map
|
165
|
+
def get_flexi_fields_map
|
166
|
+
self._flexi_fields_map ||=
|
167
|
+
Hash[get_flexi_collection.fields.
|
168
|
+
map { |_field| [_field.name.to_sym, _field] }]
|
169
|
+
end
|
170
|
+
|
171
|
+
delegate :created_at, :updated_at, :to => :_get_record, :prefix => :flexi
|
172
|
+
|
173
|
+
private
|
174
|
+
def create_or_update
|
175
|
+
_id.nil? ? create : update
|
176
|
+
end
|
177
|
+
|
178
|
+
def create(*)
|
179
|
+
# Initialize AR record and store
|
180
|
+
record = _get_record
|
181
|
+
record.save
|
182
|
+
|
183
|
+
# Set Id and errors to the parent host object
|
184
|
+
self._id = record.id
|
185
|
+
@errors = record.errors
|
186
|
+
|
187
|
+
record
|
188
|
+
end
|
189
|
+
|
190
|
+
def update(*)
|
191
|
+
record = _get_record
|
192
|
+
record.values.destroy_all
|
193
|
+
record.update_attributes(values: _get_values)
|
194
|
+
record
|
195
|
+
end
|
196
|
+
|
197
|
+
def _get_record
|
198
|
+
_load_record_instance!
|
199
|
+
self._record
|
200
|
+
end
|
201
|
+
|
202
|
+
def _load_record_instance!
|
203
|
+
self._record ||= _record_load_or_initialize
|
204
|
+
end
|
205
|
+
|
206
|
+
def _record_load_or_initialize
|
207
|
+
collection = _find_or_update_or_build_collection!
|
208
|
+
|
209
|
+
if self._id.nil?
|
210
|
+
RECORD.new(
|
211
|
+
namespace: self.class.get_flexi_namespace,
|
212
|
+
collection: collection,
|
213
|
+
values: self.send(:_get_values)
|
214
|
+
)
|
215
|
+
else
|
216
|
+
RECORD.find(self._id)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Return `Value` object based on flexi attributes
|
221
|
+
def _get_values
|
222
|
+
_fields_map = get_flexi_fields_map
|
223
|
+
|
224
|
+
@attributes.map do |k, v|
|
225
|
+
field = _fields_map[k]
|
226
|
+
raise "Field - #{k} not defined" if field.nil?
|
227
|
+
VALUE.new(:field => field, value: self.send(:"#{k}"))
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# Find existing collection object
|
232
|
+
# If not found create new collection
|
233
|
+
# If found but schema is back dated
|
234
|
+
# update schema
|
235
|
+
def _find_or_update_or_build_collection!
|
236
|
+
return _flexi_collection if _flexi_collection.present?
|
237
|
+
|
238
|
+
# Find existing collection
|
239
|
+
self._flexi_collection = COLLECTION.where(
|
240
|
+
namespace: self.class.get_flexi_namespace,
|
241
|
+
name: self.class.flexi_collection_name,
|
242
|
+
partition_id: self.class.flexi_partition_id
|
243
|
+
).first
|
244
|
+
|
245
|
+
# Update if schema changed
|
246
|
+
if self._flexi_collection
|
247
|
+
_update_schema
|
248
|
+
else
|
249
|
+
_build_collection
|
250
|
+
end
|
251
|
+
|
252
|
+
self._flexi_collection
|
253
|
+
end
|
254
|
+
|
255
|
+
# Check whether update is back dated
|
256
|
+
# This update is verified through comparing stored collection
|
257
|
+
# and new definition
|
258
|
+
def _update_schema
|
259
|
+
singular_label, plural_label = self.class.get_flexi_label
|
260
|
+
existing = self._flexi_collection
|
261
|
+
|
262
|
+
# Check labels
|
263
|
+
if existing.singular_label != singular_label
|
264
|
+
existing.update_attribute :singular_label, singular_label
|
265
|
+
end
|
266
|
+
|
267
|
+
if existing.plural_label != plural_label
|
268
|
+
existing.update_attribute :plural_label, plural_label
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
# Check fields
|
273
|
+
fields = _build_fields
|
274
|
+
if _fields_changed? fields, existing
|
275
|
+
# TODO: Dangerous need to fix it up
|
276
|
+
existing.fields.destroy_all
|
277
|
+
existing.update_attribute :fields, fields
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def _fields_changed?(fields, existing)
|
282
|
+
added_or_removed = existing.fields.length != fields.length
|
283
|
+
name_changed = existing.fields.map(&:name).sort != fields.map(&:name).sort
|
284
|
+
type_changed = existing.fields.map(&:field_type).sort != fields.map(&:field_type).sort
|
285
|
+
|
286
|
+
added_or_removed || name_changed || type_changed
|
287
|
+
end
|
288
|
+
|
289
|
+
def _build_collection
|
290
|
+
singular_label, plural_label = self.class.get_flexi_label
|
291
|
+
|
292
|
+
self._flexi_collection = COLLECTION.create(
|
293
|
+
namespace: self.class.get_flexi_namespace,
|
294
|
+
name: self.class.flexi_collection_name,
|
295
|
+
partition_id: self.class.flexi_partition_id,
|
296
|
+
singular_label: singular_label,
|
297
|
+
plural_label: plural_label,
|
298
|
+
|
299
|
+
fields: _build_fields
|
300
|
+
)
|
301
|
+
end
|
302
|
+
|
303
|
+
def _build_fields
|
304
|
+
self.flexi_fields.map do |field|
|
305
|
+
params = {
|
306
|
+
namespace: self.class.get_flexi_namespace,
|
307
|
+
name: field.name.to_s,
|
308
|
+
partition_id: self.class.flexi_partition_id,
|
309
|
+
field_type: field.type,
|
310
|
+
singular_label: field.singular,
|
311
|
+
plural_label: field.plural
|
312
|
+
}
|
313
|
+
|
314
|
+
FIELD.send(:"find_or_create_by_#{params.keys.map(&:to_s).join('_and_')}", params)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|