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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 309a3ca9a168664f17e363a3a273237d14e0665e
4
- data.tar.gz: bbb3b343f7f4bbb322effb26855f1b842eee1d85
3
+ metadata.gz: 05064a476fcba8652d4ea0a5069c89fa351e1e86
4
+ data.tar.gz: 23c2c0ba4ddf69b51f7df13ba4a3779413b82772
5
5
  SHA512:
6
- metadata.gz: a252ea2459830ca898a149deb1d71c43ebcdd91965b6107c6c26f37cc8cd864a1254b400d722a6468aa60a3cb24c7c4bbf86a88a75ef5c7c73c39a61b27843fe
7
- data.tar.gz: 4a8511ccf1d8c491aec26fdcb14a94091bc4e49387e41d15377728f26c9a768781d33e23fdbd14f50b09e99904126605828a573d91306959a1ec747b34ecd992
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 = ['Text Entry', 'Multiple Choice', 'Date', 'DateTime', 'Boolean', 'List']
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
- scope :text_entry_fields, -> { all.where(field_type: ['String', 'Fixnum', 'Float'], allowed_values: nil) }
28
- scope :multiple_choice_fields, -> { all.where.not(allowed_values: nil) }
29
- scope :date_fields, -> { all.where(field_type: 'Date', allowed_values: nil) }
30
- scope :date_time_fields, -> { all.where(field_type: 'DateTime', allowed_values: nil) }
31
- scope :boolean_fields, -> { all.where(field_type: 'Boolean', allowed_values: nil) }
32
- scope :list_fields, -> { all.where(field_type: 'Array') }
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("#{form_field.delete(' ').underscore}_fields")
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.delete_if { |k, v| v == [] }
71
+ end
46
72
  end
47
73
 
48
74
  ##
49
- # Returns the deserialized version of allowed_values
75
+ # Returns the deserialized version of field_options
50
76
  #
51
77
  # @return [Array]
52
78
  #
53
79
  def options
54
- allowed_values.nil? ? nil : deserialize('Array', allowed_values)
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 allowed_values are of the correct type
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 type_of_allowed_values
66
- return if allowed_values.nil?
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 there is an allowed_values_error
135
+ # Adds error if the default passed is not the correct type
72
136
  #
73
137
  # @return [Nil]
74
138
  #
75
- def allowed_values_error
76
- errors.add(:allowed_values, 'Value in options is not the correct type')
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 :check_allowed_values
10
+ validate :check_field_options
11
11
  validate :check_fieldable_type
12
12
 
13
- belongs_to :field, dependent: :destroy
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 allowed_values
93
- @allowed_values ||= field.options
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 check_allowed_values
142
- return unless allowed_values
143
- value_not_allowed_error unless allowed_values.include?(value)
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, index: { name: 'index_values_on_fieldable_type_and_fieldable_id' }
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 :allowed_values
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
@@ -34,8 +34,6 @@ module CustomFielder
34
34
  end
35
35
  end
36
36
 
37
- field << (f.check_box(:active) + ' Active')
38
-
39
37
  safe_join(field)
40
38
  end
41
39
  end
@@ -1,3 +1,3 @@
1
1
  module CustomFielder
2
- VERSION = "0.6.5"
2
+ VERSION = "0.7.0"
3
3
  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.6.5
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-02 00:00:00.000000000 Z
11
+ date: 2016-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails