custom_fielder 0.6.5 → 0.7.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.
- checksums.yaml +4 -4
- data/app/helpers/custom_fielder/deserialization_helper.rb +5 -0
- data/app/helpers/custom_fielder/type_checking_helper.rb +8 -0
- data/app/models/custom_fielder/field.rb +90 -26
- data/app/models/custom_fielder/value.rb +9 -37
- data/db/migrate/20160525133243_create_custom_fielder_values.rb +3 -2
- data/db/migrate/20160525133922_create_custom_fielder_fields.rb +2 -1
- data/lib/custom_fielder/custom_fieldable.rb +83 -1
- data/lib/custom_fielder/form_for_helpers.rb +0 -2
- data/lib/custom_fielder/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05064a476fcba8652d4ea0a5069c89fa351e1e86
|
4
|
+
data.tar.gz: 23c2c0ba4ddf69b51f7df13ba4a3779413b82772
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38a908cd70cd6021fb227ed68d2a05b460d20a5c024377fc0e894f2647a0e6fb844f7d2e91a2b997fc71cf678bf08cf9fb67de4deebe18189bc31e33b645eba5
|
7
|
+
data.tar.gz: fa544cdc7d5bc6da3c475d01340fd931dea95300c8bf386fada02c8d725001c0a5b27b3eeb05068e09737dd25f3f0c2c3a2ffbf5aad7e7e3d755197704dac0fb
|
@@ -4,6 +4,11 @@ module CustomFielder
|
|
4
4
|
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF']
|
5
5
|
|
6
6
|
##
|
7
|
+
# Runs the the deserialization function for the passed type
|
8
|
+
#
|
9
|
+
# @param type [String] the type to deserialize to
|
10
|
+
# @param value [String] the value to be deserialized
|
11
|
+
#
|
7
12
|
# @return [Array|Integer|Float|Date|DateTime|Boolean|String]
|
8
13
|
#
|
9
14
|
def deserialize(type, value)
|
@@ -5,6 +5,11 @@ module CustomFielder
|
|
5
5
|
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF']
|
6
6
|
|
7
7
|
##
|
8
|
+
# Runs the the type checking function for the passed type
|
9
|
+
#
|
10
|
+
# @param type [String] the type to be checked
|
11
|
+
# @param value [String] the value to be type checked
|
12
|
+
#
|
8
13
|
# @return [Boolean]
|
9
14
|
#
|
10
15
|
def is_correct_type?(type, value)
|
@@ -43,6 +48,9 @@ module CustomFielder
|
|
43
48
|
# @return [Boolean]
|
44
49
|
#
|
45
50
|
def is_date_time?(value)
|
51
|
+
value =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/ or
|
52
|
+
value =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/ or
|
53
|
+
value =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}$/ or
|
46
54
|
value =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}-\d{2}:\d{2}$/
|
47
55
|
end
|
48
56
|
|
@@ -13,23 +13,49 @@ module CustomFielder
|
|
13
13
|
'List' => 'Array'
|
14
14
|
}
|
15
15
|
|
16
|
-
FORM_FIELD_TYPES =
|
16
|
+
FORM_FIELD_TYPES = {
|
17
|
+
'Text - Entry' => :text_entry_fields,
|
18
|
+
'Text - Multiple Choice' => :text_choice_fields,
|
19
|
+
'Integer - Entry' => :int_entry_fields,
|
20
|
+
'Integer - Multiple Choice' => :int_choice_fields,
|
21
|
+
'Decimal - Entry' => :float_entry_fields,
|
22
|
+
'Decimal - Multiple Choice' => :float_choice_fields,
|
23
|
+
'Date - Entry' => :date_entry_fields,
|
24
|
+
'Date - Multiple Choice' => :date_choice_fields,
|
25
|
+
'Date & Time - Entry' => :datetime_entry_fields,
|
26
|
+
'Date & Time - Multiple Choice' => :datetime_choice_fields,
|
27
|
+
'True/False' => :boolean_fields
|
28
|
+
}
|
29
|
+
|
30
|
+
validate :default_type
|
31
|
+
validate :field_options_types
|
32
|
+
validate :field_options_unique
|
33
|
+
|
34
|
+
validates :name, presence: true,
|
35
|
+
uniqueness: {
|
36
|
+
scope: [:fieldable_type],
|
37
|
+
message: "Field name already exists"
|
38
|
+
}
|
39
|
+
validates :field_type, presence: true,
|
40
|
+
inclusion: { in: %w[Array Fixnum Float Date DateTime Boolean String] }
|
41
|
+
validates :fieldable_type, presence: true
|
42
|
+
|
17
43
|
|
18
|
-
has_many :values
|
19
44
|
|
20
|
-
validates :name, presence: true
|
21
|
-
validates :field_type, presence: true,
|
22
|
-
inclusion: { in: %w[Array Fixnum Float Date DateTime Boolean String] }
|
23
|
-
validates :fieldable_type, presence: true
|
24
|
-
validates :allow_blank, inclusion: { in: [true, false] }
|
25
|
-
validate :type_of_allowed_values
|
26
45
|
|
27
|
-
|
28
|
-
|
29
|
-
scope :
|
30
|
-
scope :
|
31
|
-
scope :
|
32
|
-
scope :
|
46
|
+
has_many :values, dependent: :destroy
|
47
|
+
|
48
|
+
scope :text_entry_fields, -> { all.where(field_type: 'String', field_options: nil) }
|
49
|
+
scope :text_choice_fields, -> { all.where(field_type: 'String').where.not(field_options: nil) }
|
50
|
+
scope :int_entry_fields, -> { all.where(field_type: 'Fixnum', field_options: nil) }
|
51
|
+
scope :int_choice_fields, -> { all.where(field_type: 'Fixnum').where.not(field_options: nil) }
|
52
|
+
scope :float_entry_fields, -> { all.where(field_type: 'Float', field_options: nil) }
|
53
|
+
scope :float_choice_fields, -> { all.where(field_type: 'Float').where.not(field_options: nil) }
|
54
|
+
scope :date_entry_fields, -> { all.where(field_type: 'Date', field_options: nil) }
|
55
|
+
scope :date_choice_fields, -> { all.where(field_type: 'Date').where.not(field_options:nil) }
|
56
|
+
scope :datetime_entry_fields, -> { all.where(field_type: 'DateTime', field_options: nil) }
|
57
|
+
scope :datetime_choice_fields, -> { all.where(field_type: 'DateTime').where.not(field_options:nil) }
|
58
|
+
scope :boolean_fields, -> { all.where(field_type: 'Boolean') }
|
33
59
|
|
34
60
|
##
|
35
61
|
# Creates a hash of form field types mapped to array of field, field id pairs
|
@@ -39,41 +65,79 @@ module CustomFielder
|
|
39
65
|
#
|
40
66
|
def self.all_fields_hashed_for_opt_group
|
41
67
|
FORM_FIELD_TYPES.inject(Hash.new) do |hash, form_field|
|
42
|
-
fields = send(
|
43
|
-
hash[form_field] = fields.map { |field| [field.name, field.id] }
|
68
|
+
fields = send(form_field.last)
|
69
|
+
hash[form_field.first] = fields.map { |field| [field.name, field.id] } unless fields.empty?
|
44
70
|
hash
|
45
|
-
end
|
71
|
+
end
|
46
72
|
end
|
47
73
|
|
48
74
|
##
|
49
|
-
# Returns the deserialized version of
|
75
|
+
# Returns the deserialized version of field_options
|
50
76
|
#
|
51
77
|
# @return [Array]
|
52
78
|
#
|
53
79
|
def options
|
54
|
-
|
80
|
+
field_options.nil? ? nil : deserialize('Array', field_options)
|
55
81
|
end
|
56
82
|
|
57
83
|
|
58
84
|
private
|
59
85
|
|
60
86
|
##
|
61
|
-
# Checks to make sure all values in
|
87
|
+
# Checks to make sure all values in field_options are of the correct type
|
88
|
+
#
|
89
|
+
# @return [Nil]
|
90
|
+
#
|
91
|
+
def field_options_types
|
92
|
+
return if field_options.nil?
|
93
|
+
options.each { |v| (field_options_type_error; return) unless v.class.to_s == field_type }
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Checks to make sure all values in field_options are unique
|
98
|
+
#
|
99
|
+
# @return [Nil]
|
100
|
+
#
|
101
|
+
def field_options_unique
|
102
|
+
return if field_options.nil?
|
103
|
+
field_options_unique_error unless options.uniq.count == options.count
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Checks that the default value is of the correct type
|
108
|
+
#
|
109
|
+
# @return [Nil]
|
110
|
+
#
|
111
|
+
def default_type
|
112
|
+
return if default.nil?
|
113
|
+
default_type_error unless is_correct_type?(field_type, default)
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Adds error if there is an field_options_error
|
118
|
+
#
|
119
|
+
# @return [Nil]
|
120
|
+
#
|
121
|
+
def field_options_type_error
|
122
|
+
errors.add(:field_options, 'Value in options is not the correct type')
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Adds error if values in field_options aren't unique
|
62
127
|
#
|
63
128
|
# @return [Nil]
|
64
129
|
#
|
65
|
-
def
|
66
|
-
|
67
|
-
options.each { |v| allowed_values_error unless v.class.to_s == field_type }
|
130
|
+
def field_options_unique_error
|
131
|
+
errors.add(:field_options, 'Values in field options must be unique')
|
68
132
|
end
|
69
133
|
|
70
134
|
##
|
71
|
-
# Adds error if
|
135
|
+
# Adds error if the default passed is not the correct type
|
72
136
|
#
|
73
137
|
# @return [Nil]
|
74
138
|
#
|
75
|
-
def
|
76
|
-
errors.add(:
|
139
|
+
def default_type_error
|
140
|
+
errors.add(:default, 'Default value is not the correct type')
|
77
141
|
end
|
78
142
|
|
79
143
|
end
|
@@ -7,15 +7,12 @@ module CustomFielder
|
|
7
7
|
|
8
8
|
validate :check_type
|
9
9
|
validate :check_allow_blank
|
10
|
-
validate :
|
10
|
+
validate :check_field_options
|
11
11
|
validate :check_fieldable_type
|
12
12
|
|
13
|
-
belongs_to :field
|
13
|
+
belongs_to :field
|
14
14
|
belongs_to :fieldable, polymorphic: true
|
15
15
|
|
16
|
-
scope :active, -> { where(active: true) }
|
17
|
-
scope :inactive, -> { where(active: false) }
|
18
|
-
|
19
16
|
scope :values_with_field, -> (field) { where(field: field) }
|
20
17
|
scope :values_with_class, -> (klass) { where(fieldable_type: klass) }
|
21
18
|
|
@@ -29,32 +26,6 @@ module CustomFielder
|
|
29
26
|
alias_method :raw_value, :value
|
30
27
|
def value; deserialize_value; end;
|
31
28
|
|
32
|
-
class << self
|
33
|
-
##
|
34
|
-
# Activates all CustomFields that belong to passed field attributes
|
35
|
-
#
|
36
|
-
# @param field_attrs [CustomFielder::Field]
|
37
|
-
#
|
38
|
-
# @return [Nil]
|
39
|
-
#
|
40
|
-
def activate_field_for_all(field)
|
41
|
-
values = all.where(field: field)
|
42
|
-
values.each { |value| value.active = true; value.save }
|
43
|
-
end
|
44
|
-
|
45
|
-
##
|
46
|
-
# Deactivates all CustomFields that belong to passed field attributes
|
47
|
-
#
|
48
|
-
# @param field_attrs [CustomFielder::Field]
|
49
|
-
#
|
50
|
-
# @return [Nil]
|
51
|
-
#
|
52
|
-
def deactivate_field_for_all(field)
|
53
|
-
values = all.where(field: field)
|
54
|
-
values.each { |value| value.active = false; value.save }
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
29
|
private
|
59
30
|
|
60
31
|
##
|
@@ -89,8 +60,8 @@ module CustomFielder
|
|
89
60
|
#
|
90
61
|
# @return [Array]
|
91
62
|
#
|
92
|
-
def
|
93
|
-
@
|
63
|
+
def field_options
|
64
|
+
@field_options ||= field.options
|
94
65
|
end
|
95
66
|
|
96
67
|
##
|
@@ -112,11 +83,12 @@ module CustomFielder
|
|
112
83
|
end
|
113
84
|
|
114
85
|
##
|
115
|
-
# Sets the value to the default if value is blank
|
86
|
+
# Sets the value to the default if value is blank and allow blank is false
|
116
87
|
#
|
117
88
|
# @return [Nil]
|
118
89
|
#
|
119
90
|
def set_default
|
91
|
+
return if allow_blank
|
120
92
|
update_attribute(:value, default) if default? and raw_value_blank?
|
121
93
|
end
|
122
94
|
|
@@ -138,9 +110,9 @@ module CustomFielder
|
|
138
110
|
##
|
139
111
|
# @return [Nil] Adds error if invalid
|
140
112
|
#
|
141
|
-
def
|
142
|
-
return unless
|
143
|
-
value_not_allowed_error unless
|
113
|
+
def check_field_options
|
114
|
+
return unless field_options
|
115
|
+
value_not_allowed_error unless field_options.include?(value)
|
144
116
|
end
|
145
117
|
|
146
118
|
##
|
@@ -1,13 +1,14 @@
|
|
1
1
|
class CreateCustomFielderValues < ActiveRecord::Migration
|
2
2
|
def change
|
3
3
|
create_table :custom_fielder_values do |t|
|
4
|
-
t.references :fieldable, polymorphic: true, null: false
|
4
|
+
t.references :fieldable, polymorphic: true, null: false
|
5
5
|
t.integer :field_id, null: false, index: true
|
6
|
-
t.boolean :active, null: false, default: true
|
7
6
|
t.string :value
|
8
7
|
t.text :note
|
9
8
|
|
10
9
|
t.timestamps null: false
|
11
10
|
end
|
11
|
+
|
12
|
+
add_index :custom_fielder_values, [:fieldable_type, :fieldable_id, :field_id], unique: true, name: 'index_values_on_fieldable_type_and_fieldable_id_and_field_id'
|
12
13
|
end
|
13
14
|
end
|
@@ -5,8 +5,9 @@ class CreateCustomFielderFields < ActiveRecord::Migration
|
|
5
5
|
t.string :field_type, null: false
|
6
6
|
t.string :fieldable_type, null: false
|
7
7
|
t.string :default
|
8
|
+
t.boolean :active, null: false, default: true
|
8
9
|
t.boolean :allow_blank, null: false, default: false
|
9
|
-
t.string :
|
10
|
+
t.string :field_options
|
10
11
|
t.text :note
|
11
12
|
|
12
13
|
t.timestamps null: false
|
@@ -20,6 +20,76 @@ module CustomFielder
|
|
20
20
|
alias_method :custom_fields, :custom_fielder_fields
|
21
21
|
alias_method :custom_field_values, :custom_fielder_values
|
22
22
|
|
23
|
+
##
|
24
|
+
# Returns all the objects on the model that have the passed
|
25
|
+
# value, defined on the field with the passed field_id
|
26
|
+
#
|
27
|
+
# @return [ActiveRecord::Relation]
|
28
|
+
#
|
29
|
+
def self.find_objects_with_custom_values_where(value:, field_id:)
|
30
|
+
joins(:custom_fielder_values).
|
31
|
+
where(custom_fielder_values: {
|
32
|
+
value: value,
|
33
|
+
field_id: field_id
|
34
|
+
})
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Provides a list of columns to be included in an
|
39
|
+
# object search. This is to be able to dynamically
|
40
|
+
# create tables no matter the object
|
41
|
+
#
|
42
|
+
# @note this method should be overridden
|
43
|
+
#
|
44
|
+
# @return [Array]
|
45
|
+
#
|
46
|
+
def self.custom_fielder_columns
|
47
|
+
[:id]
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Provides a uniform means of accessing data no matter
|
52
|
+
# the object, this can be overridden to suit your
|
53
|
+
# needs
|
54
|
+
#
|
55
|
+
# @note this method can be overridden more specific
|
56
|
+
# @note object selection
|
57
|
+
#
|
58
|
+
# @return [ActiveRecord::Relation]
|
59
|
+
#
|
60
|
+
def self.custom_fielder_search
|
61
|
+
all
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Provides an array of hashes of objects and Custom Field values (if they exist)
|
66
|
+
# using custom_fielder_search as the means of generating
|
67
|
+
# the sub query to find objects and then using this query
|
68
|
+
# to join the values with the objects if they exist (in one transaction)
|
69
|
+
#
|
70
|
+
# @param field [CustomFielder::Field] field to search for values on
|
71
|
+
#
|
72
|
+
# @return [Array<Hash>]
|
73
|
+
#
|
74
|
+
def self.custom_fielder_objects(field)
|
75
|
+
columns = custom_fielder_columns
|
76
|
+
sub_query = custom_fielder_search.select(columns).to_sql
|
77
|
+
columns.map! { |column| "objects.#{column} as #{column}" }
|
78
|
+
|
79
|
+
query = <<-SQL
|
80
|
+
SELECT #{columns.join(', ')}, cfv.id AS value_id, cfv.value AS value
|
81
|
+
FROM (#{sub_query}) objects
|
82
|
+
LEFT OUTER JOIN custom_fielder_values cfv
|
83
|
+
ON objects.id = cfv.fieldable_id
|
84
|
+
AND cfv.field_id = #{field.id}
|
85
|
+
SQL
|
86
|
+
|
87
|
+
objects = ActiveRecord::Base.connection.execute(query)
|
88
|
+
objects = objects.values.map { |values| Hash[objects.fields.zip(values)] } if objects.class == PG::Result
|
89
|
+
|
90
|
+
return objects
|
91
|
+
end
|
92
|
+
|
23
93
|
##
|
24
94
|
# Returns a hash where the keys are the field names
|
25
95
|
# and the values are the field values
|
@@ -32,7 +102,19 @@ module CustomFielder
|
|
32
102
|
h[field_name] = field_value.value; h
|
33
103
|
end
|
34
104
|
end
|
35
|
-
end
|
36
105
|
|
106
|
+
##
|
107
|
+
# Provides a shorter method call to retrieve a custom fields
|
108
|
+
# value given the field. Returns the value or nil if the value
|
109
|
+
# does not exist
|
110
|
+
#
|
111
|
+
# @return [String|Nil]
|
112
|
+
#
|
113
|
+
def value_for_custom_field(field)
|
114
|
+
value = self.custom_fielder_values.find_by(field_id: field.id)
|
115
|
+
value.nil? ? nil : value.value
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
37
119
|
end
|
38
120
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: custom_fielder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Hurst
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|