custom_fielder 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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