phlexi-form 0.2.0 → 0.3.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/Appraisals +4 -9
- data/README.md +117 -316
- data/TODO +4 -0
- data/config.ru +0 -3
- data/gemfiles/default.gemfile.lock +22 -2
- data/gemfiles/rails_7.gemfile +8 -0
- data/gemfiles/rails_7.gemfile.lock +282 -0
- data/lib/phlexi/form/base.rb +65 -56
- data/lib/phlexi/form/components/base.rb +14 -8
- data/lib/phlexi/form/components/checkbox.rb +5 -0
- data/lib/phlexi/form/components/collection_checkboxes.rb +28 -14
- data/lib/phlexi/form/components/collection_radio_buttons.rb +19 -13
- data/lib/phlexi/form/components/concerns/extracts_input.rb +53 -0
- data/lib/phlexi/form/components/concerns/handles_array_input.rb +21 -0
- data/lib/phlexi/form/components/concerns/handles_input.rb +23 -0
- data/lib/phlexi/form/components/concerns/has_options.rb +6 -2
- data/lib/phlexi/form/components/concerns/submits_form.rb +47 -0
- data/lib/phlexi/form/components/error.rb +1 -1
- data/lib/phlexi/form/components/file_input.rb +33 -0
- data/lib/phlexi/form/components/hint.rb +1 -1
- data/lib/phlexi/form/components/input.rb +38 -36
- data/lib/phlexi/form/components/input_array.rb +45 -0
- data/lib/phlexi/form/components/label.rb +2 -1
- data/lib/phlexi/form/components/radio_button.rb +11 -1
- data/lib/phlexi/form/components/select.rb +21 -8
- data/lib/phlexi/form/components/submit_button.rb +41 -0
- data/lib/phlexi/form/components/textarea.rb +2 -3
- data/lib/phlexi/form/field_options/associations.rb +21 -0
- data/lib/phlexi/form/field_options/autofocus.rb +1 -1
- data/lib/phlexi/form/field_options/collection.rb +26 -9
- data/lib/phlexi/form/field_options/errors.rb +17 -3
- data/lib/phlexi/form/field_options/hints.rb +5 -1
- data/lib/phlexi/form/field_options/{type.rb → inferred_types.rb} +21 -17
- data/lib/phlexi/form/field_options/multiple.rb +2 -0
- data/lib/phlexi/form/field_options/required.rb +1 -1
- data/lib/phlexi/form/field_options/themes.rb +207 -0
- data/lib/phlexi/form/field_options/validators.rb +2 -2
- data/lib/phlexi/form/option_mapper.rb +2 -2
- data/lib/phlexi/form/structure/dom.rb +21 -16
- data/lib/phlexi/form/structure/field_builder.rb +165 -121
- data/lib/phlexi/form/structure/field_collection.rb +20 -6
- data/lib/phlexi/form/structure/namespace.rb +48 -31
- data/lib/phlexi/form/structure/namespace_collection.rb +20 -20
- data/lib/phlexi/form/structure/node.rb +13 -3
- data/lib/phlexi/form/version.rb +1 -1
- data/lib/phlexi/form.rb +4 -1
- metadata +32 -7
- data/CODE_OF_CONDUCT.md +0 -84
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
module Concerns
|
7
|
+
module HandlesArrayInput
|
8
|
+
protected
|
9
|
+
|
10
|
+
def normalize_input(input_value)
|
11
|
+
normalize_array_input(input_value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def normalize_array_input(input_value)
|
15
|
+
Array(input_value).map { |nested_input_value| normalize_simple_input(nested_input_value) }.compact
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
module Concerns
|
7
|
+
module HandlesInput
|
8
|
+
include Phlexi::Form::Components::Concerns::ExtractsInput
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def build_attributes
|
13
|
+
super
|
14
|
+
|
15
|
+
# only overwrite id if it was set in Base
|
16
|
+
attributes[:id] = field.dom.id if attributes[:id] == "#{field.dom.id}_#{component_name}"
|
17
|
+
attributes[:name] = field.dom.name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -19,13 +19,17 @@ module Phlexi
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def selected?(option)
|
22
|
-
if
|
22
|
+
if attributes[:multiple]
|
23
23
|
@options_list ||= Array(field.value)
|
24
24
|
@options_list.any? { |item| item.to_s == option.to_s }
|
25
25
|
else
|
26
|
-
field.
|
26
|
+
field.value.to_s == option.to_s
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
def normalize_simple_input(input_value)
|
31
|
+
([super] & option_mapper.values)[0]
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
module Concerns
|
7
|
+
module SubmitsForm
|
8
|
+
include Phlexi::Form::Components::Concerns::ExtractsInput
|
9
|
+
|
10
|
+
def extract_input(params)
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def submit_type_value
|
17
|
+
if field.object.respond_to?(:persisted?)
|
18
|
+
field.object.persisted? ? :update : :create
|
19
|
+
else
|
20
|
+
:submit
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def submit_type_label
|
25
|
+
@submit_type_label ||= begin
|
26
|
+
key = submit_type_value
|
27
|
+
|
28
|
+
model_object = field.dom.lineage.first.key.to_s
|
29
|
+
model_name_human = if field.object.respond_to?(:model_name)
|
30
|
+
field.object.model_name.human
|
31
|
+
else
|
32
|
+
model_object.humanize
|
33
|
+
end
|
34
|
+
|
35
|
+
defaults = []
|
36
|
+
defaults << :"helpers.submit.#{model_object}.#{key}"
|
37
|
+
defaults << :"helpers.submit.#{key}"
|
38
|
+
defaults << "#{key.to_s.humanize} #{model_name_human}"
|
39
|
+
|
40
|
+
I18n.t(defaults.shift, model: model_name_human, default: defaults)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
class FileInput < Input
|
7
|
+
def view_template
|
8
|
+
input(type: :hidden, name: attributes[:name], value: "", autocomplete: "off", hidden: true) if include_hidden?
|
9
|
+
input(**attributes)
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def build_input_attributes
|
15
|
+
attributes[:type] = :file
|
16
|
+
super
|
17
|
+
# ensure we are always setting it to false
|
18
|
+
attributes[:value] = false
|
19
|
+
end
|
20
|
+
|
21
|
+
def include_hidden?
|
22
|
+
return false if @include_hidden == false
|
23
|
+
|
24
|
+
attributes[:multiple]
|
25
|
+
end
|
26
|
+
|
27
|
+
def normalize_input(input_value)
|
28
|
+
input_value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -4,6 +4,8 @@ module Phlexi
|
|
4
4
|
module Form
|
5
5
|
module Components
|
6
6
|
class Input < Base
|
7
|
+
include Concerns::HandlesInput
|
8
|
+
|
7
9
|
def view_template
|
8
10
|
input(**attributes)
|
9
11
|
end
|
@@ -13,63 +15,63 @@ module Phlexi
|
|
13
15
|
def build_attributes
|
14
16
|
super
|
15
17
|
|
16
|
-
# only overwrite id if it was set in Base
|
17
|
-
attributes[:id] = field.dom.id if attributes[:id] == "#{field.dom.id}_#{component_name}"
|
18
|
-
attributes[:name] = field.dom.name
|
19
18
|
attributes[:value] = field.dom.value
|
20
19
|
|
21
20
|
build_input_attributes
|
22
21
|
end
|
23
22
|
|
24
23
|
def build_input_attributes
|
25
|
-
attributes
|
26
|
-
attributes
|
24
|
+
attributes.fetch(:type) { attributes[:type] = field.inferred_input_component_subtype }
|
25
|
+
attributes.fetch(:disabled) { attributes[:disabled] = field.disabled? }
|
27
26
|
|
28
27
|
case attributes[:type]
|
29
28
|
when :text, :password, :email, :tel, :url, :search
|
30
|
-
attributes
|
31
|
-
attributes
|
32
|
-
attributes
|
33
|
-
attributes
|
34
|
-
attributes
|
35
|
-
attributes
|
36
|
-
attributes
|
29
|
+
attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
|
30
|
+
attributes.fetch(:placeholder) { attributes[:placeholder] = field.placeholder }
|
31
|
+
attributes.fetch(:minlength) { attributes[:minlength] = field.minlength }
|
32
|
+
attributes.fetch(:maxlength) { attributes[:maxlength] = field.maxlength }
|
33
|
+
attributes.fetch(:readonly) { attributes[:readonly] = field.readonly? }
|
34
|
+
attributes.fetch(:required) { attributes[:required] = field.required? }
|
35
|
+
attributes.fetch(:pattern) { attributes[:pattern] = field.pattern }
|
37
36
|
when :number
|
38
|
-
attributes
|
39
|
-
attributes
|
40
|
-
attributes
|
41
|
-
attributes
|
42
|
-
attributes
|
43
|
-
attributes
|
44
|
-
attributes
|
37
|
+
attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
|
38
|
+
attributes.fetch(:placeholder) { attributes[:placeholder] = field.placeholder }
|
39
|
+
attributes.fetch(:readonly) { attributes[:readonly] = field.readonly? }
|
40
|
+
attributes.fetch(:required) { attributes[:required] = field.required? }
|
41
|
+
attributes.fetch(:min) { attributes[:min] = field.min }
|
42
|
+
attributes.fetch(:max) { attributes[:max] = field.max }
|
43
|
+
attributes.fetch(:step) { attributes[:step] = field.step }
|
45
44
|
when :checkbox, :radio
|
46
|
-
attributes
|
47
|
-
attributes
|
45
|
+
attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
|
46
|
+
attributes.fetch(:required) { attributes[:required] = field.required? }
|
48
47
|
when :file
|
49
|
-
attributes
|
50
|
-
attributes
|
51
|
-
attributes
|
52
|
-
attributes[:accept] = attributes.fetch(:accept, field.accept)
|
48
|
+
attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
|
49
|
+
attributes.fetch(:required) { attributes[:required] = field.required? }
|
50
|
+
attributes.fetch(:multiple) { attributes[:multiple] = field.multiple? }
|
53
51
|
when :date, :time, :datetime_local
|
54
|
-
attributes
|
55
|
-
attributes
|
56
|
-
attributes
|
57
|
-
attributes
|
58
|
-
attributes
|
52
|
+
attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
|
53
|
+
attributes.fetch(:readonly) { attributes[:readonly] = field.readonly? }
|
54
|
+
attributes.fetch(:required) { attributes[:required] = field.required? }
|
55
|
+
attributes.fetch(:min) { attributes[:min] = field.min }
|
56
|
+
attributes.fetch(:max) { attributes[:max] = field.max }
|
59
57
|
when :color
|
60
|
-
attributes
|
58
|
+
attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
|
61
59
|
when :range
|
62
|
-
attributes
|
63
|
-
attributes
|
64
|
-
attributes
|
65
|
-
attributes
|
60
|
+
attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
|
61
|
+
attributes.fetch(:min) { attributes[:min] = field.min }
|
62
|
+
attributes.fetch(:max) { attributes[:max] = field.max }
|
63
|
+
attributes.fetch(:step) { attributes[:step] = field.step }
|
64
|
+
when :hidden
|
65
|
+
attributes[:class] = false
|
66
|
+
attributes[:hidden] = true
|
67
|
+
attributes[:autocomplete] = "off"
|
66
68
|
else
|
67
69
|
# Handle any unrecognized input types
|
68
70
|
# Rails.logger.warn("Unhandled input type: #{attributes[:type]}")
|
69
71
|
end
|
70
72
|
|
71
73
|
if (attributes[:type] == :file) ? attributes[:multiple] : attributes.delete(:multiple)
|
72
|
-
attributes[:name] = "#{attributes[:name].sub(/\[]$/, "")}[]"
|
74
|
+
attributes[:name] = "#{attributes[:name].sub(/\[\]$/, "")}[]"
|
73
75
|
end
|
74
76
|
end
|
75
77
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
class InputArray < Base
|
7
|
+
include Concerns::HandlesInput
|
8
|
+
include Concerns::HandlesArrayInput
|
9
|
+
|
10
|
+
def view_template
|
11
|
+
div(**attributes.slice(:id, :class)) do
|
12
|
+
field.repeated(values.length) do |builder|
|
13
|
+
render builder.hidden_field_tag if builder.index == 0
|
14
|
+
|
15
|
+
field = builder.field(
|
16
|
+
label: builder.key,
|
17
|
+
# we expect key to be an integer string starting from "1"
|
18
|
+
value: values[builder.index]
|
19
|
+
)
|
20
|
+
if block_given?
|
21
|
+
yield field
|
22
|
+
else
|
23
|
+
render field.input_tag
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def build_attributes
|
32
|
+
super
|
33
|
+
|
34
|
+
attributes[:multiple] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def values
|
40
|
+
@values ||= Array(field.value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -8,6 +8,11 @@ module Phlexi
|
|
8
8
|
input(**attributes, value: @checked_value)
|
9
9
|
end
|
10
10
|
|
11
|
+
def extract_input(...)
|
12
|
+
# when a radio is not submitted, nothing is returned
|
13
|
+
super.compact
|
14
|
+
end
|
15
|
+
|
11
16
|
protected
|
12
17
|
|
13
18
|
def build_input_attributes
|
@@ -17,7 +22,7 @@ module Phlexi
|
|
17
22
|
@checked_value = (attributes.key?(:checked_value) ? attributes.delete(:checked_value) : "1").to_s
|
18
23
|
|
19
24
|
# this is a hack to workaround the fact that radio cannot be indexed/multiple
|
20
|
-
attributes[:name] = attributes[:name].sub(/\[]$/, "")
|
25
|
+
attributes[:name] = attributes[:name].sub(/\[\]$/, "")
|
21
26
|
attributes[:value] = @checked_value
|
22
27
|
attributes[:checked] = attributes.fetch(:checked) { checked? }
|
23
28
|
end
|
@@ -25,6 +30,11 @@ module Phlexi
|
|
25
30
|
def checked?
|
26
31
|
field.dom.value == @checked_value
|
27
32
|
end
|
33
|
+
|
34
|
+
def normalize_input(...)
|
35
|
+
input_value = super
|
36
|
+
(input_value == @checked_value) ? input_value : nil
|
37
|
+
end
|
28
38
|
end
|
29
39
|
end
|
30
40
|
end
|
@@ -4,11 +4,14 @@ module Phlexi
|
|
4
4
|
module Form
|
5
5
|
module Components
|
6
6
|
class Select < Base
|
7
|
+
include Concerns::HandlesInput
|
8
|
+
include Concerns::HandlesArrayInput
|
7
9
|
include Concerns::HasOptions
|
8
10
|
|
9
|
-
def view_template
|
11
|
+
def view_template
|
12
|
+
input(type: :hidden, name: attributes[:name], value: "", autocomplete: "off", hidden: true) if include_hidden?
|
10
13
|
select(**attributes) do
|
11
|
-
blank_option { blank_option_text }
|
14
|
+
blank_option { blank_option_text } if include_blank?
|
12
15
|
options
|
13
16
|
end
|
14
17
|
end
|
@@ -28,14 +31,12 @@ module Phlexi
|
|
28
31
|
def build_attributes
|
29
32
|
super
|
30
33
|
|
31
|
-
attributes[:id] = field.dom.id
|
32
|
-
attributes[:name] = field.dom.name
|
33
|
-
|
34
34
|
build_select_attributes
|
35
35
|
end
|
36
36
|
|
37
37
|
def build_select_attributes
|
38
|
-
@
|
38
|
+
@include_blank = attributes.delete(:include_blank)
|
39
|
+
@include_hidden = attributes.delete(:include_hidden)
|
39
40
|
|
40
41
|
attributes[:autofocus] = attributes.fetch(:autofocus, field.focused?)
|
41
42
|
attributes[:required] = attributes.fetch(:required, field.required?)
|
@@ -48,8 +49,20 @@ module Phlexi
|
|
48
49
|
field.placeholder
|
49
50
|
end
|
50
51
|
|
51
|
-
def
|
52
|
-
@
|
52
|
+
def include_blank?
|
53
|
+
return true if @include_blank == true
|
54
|
+
|
55
|
+
@include_blank != false && !attributes[:multiple]
|
56
|
+
end
|
57
|
+
|
58
|
+
def include_hidden?
|
59
|
+
return false if @include_hidden == false
|
60
|
+
|
61
|
+
attributes[:multiple]
|
62
|
+
end
|
63
|
+
|
64
|
+
def normalize_input(input_value)
|
65
|
+
attributes[:multiple] ? normalize_array_input(input_value) : normalize_simple_input(input_value)
|
53
66
|
end
|
54
67
|
end
|
55
68
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
class SubmitButton < Base
|
7
|
+
include Concerns::SubmitsForm
|
8
|
+
|
9
|
+
def view_template(&content)
|
10
|
+
content ||= proc { submit_type_label }
|
11
|
+
button(**attributes, &content)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def build_attributes
|
17
|
+
root_key = field.dom.lineage.first.respond_to?(:dom_id) ? field.dom.lineage.first.dom_id : field.dom.lineage.first.key
|
18
|
+
attributes.fetch(:id) { attributes[:id] = "#{root_key}_submit_button" }
|
19
|
+
attributes[:class] = tokens(
|
20
|
+
component_name,
|
21
|
+
submit_type_value,
|
22
|
+
attributes[:class]
|
23
|
+
)
|
24
|
+
|
25
|
+
build_button_attributes
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_button_attributes
|
29
|
+
formmethod = attributes[:formmethod]
|
30
|
+
if formmethod.present? && !/post|get/i.match?(formmethod) && !attributes.key?(:name) && !attributes.key?(:value)
|
31
|
+
attributes.merge! formmethod: :post, name: "_method", value: formmethod
|
32
|
+
end
|
33
|
+
|
34
|
+
attributes.fetch(:name) { attributes[:name] = "commit" }
|
35
|
+
attributes.fetch(:value) { attributes[:value] = submit_type_label }
|
36
|
+
attributes.fetch(:type) { attributes[:type] = :submit }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -4,6 +4,8 @@ module Phlexi
|
|
4
4
|
module Form
|
5
5
|
module Components
|
6
6
|
class Textarea < Base
|
7
|
+
include Concerns::HandlesInput
|
8
|
+
|
7
9
|
def view_template
|
8
10
|
textarea(**attributes) { field.dom.value }
|
9
11
|
end
|
@@ -13,9 +15,6 @@ module Phlexi
|
|
13
15
|
def build_attributes
|
14
16
|
super
|
15
17
|
|
16
|
-
attributes[:id] = field.dom.id
|
17
|
-
attributes[:name] = field.dom.name
|
18
|
-
|
19
18
|
build_textarea_attributes
|
20
19
|
end
|
21
20
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module FieldOptions
|
6
|
+
module Associations
|
7
|
+
protected
|
8
|
+
|
9
|
+
def association_reflection
|
10
|
+
@association_reflection ||= find_association_reflection
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_association_reflection
|
14
|
+
if object.class.respond_to?(:reflect_on_association)
|
15
|
+
object.class.reflect_on_association(key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -16,20 +16,37 @@ module Phlexi
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def infer_collection
|
19
|
-
|
20
|
-
inclusion_validator = find_inclusion_validator
|
21
|
-
collection_value_from(inclusion_validator)
|
22
|
-
end
|
19
|
+
collection_value_from_association || collection_value_from_validator
|
23
20
|
end
|
24
21
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
22
|
+
def collection_value_from_association
|
23
|
+
return unless association_reflection
|
24
|
+
|
25
|
+
relation = association_reflection.klass.all
|
26
|
+
|
27
|
+
if association_reflection.respond_to?(:scope) && association_reflection.scope
|
28
|
+
relation = if association_reflection.scope.parameters.any?
|
29
|
+
association_reflection.klass.instance_exec(object, &association_reflection.scope)
|
30
|
+
else
|
31
|
+
association_reflection.klass.instance_exec(&association_reflection.scope)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
order = association_reflection.options[:order]
|
35
|
+
conditions = association_reflection.options[:conditions]
|
36
|
+
conditions = object.instance_exec(&conditions) if conditions.respond_to?(:call)
|
37
|
+
|
38
|
+
relation = relation.where(conditions) if relation.respond_to?(:where) && conditions.present?
|
39
|
+
relation = relation.order(order) if relation.respond_to?(:order)
|
28
40
|
end
|
41
|
+
|
42
|
+
relation
|
29
43
|
end
|
30
44
|
|
31
|
-
def
|
32
|
-
|
45
|
+
def collection_value_from_validator
|
46
|
+
return unless has_validators?
|
47
|
+
|
48
|
+
inclusion_validator = find_validator(:inclusion)
|
49
|
+
inclusion_validator.options[:in] || inclusion_validator.options[:within] if inclusion_validator
|
33
50
|
end
|
34
51
|
end
|
35
52
|
end
|
@@ -21,10 +21,14 @@ module Phlexi
|
|
21
21
|
object_with_errors? || !object && has_custom_error?
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def can_show_errors?
|
25
25
|
options[:error] != false
|
26
26
|
end
|
27
27
|
|
28
|
+
def show_errors?
|
29
|
+
can_show_errors? && has_errors?
|
30
|
+
end
|
31
|
+
|
28
32
|
def valid?
|
29
33
|
!has_errors? && has_value?
|
30
34
|
end
|
@@ -66,16 +70,26 @@ module Phlexi
|
|
66
70
|
end
|
67
71
|
|
68
72
|
def errors_on_association
|
69
|
-
|
73
|
+
association_reflection ? object.errors[association_reflection.name] : []
|
70
74
|
end
|
71
75
|
|
72
76
|
def full_errors_on_association
|
73
|
-
|
77
|
+
association_reflection ? object.errors.full_messages_for(association_reflection.name) : []
|
74
78
|
end
|
75
79
|
|
76
80
|
def has_custom_error?
|
77
81
|
options[:error].is_a?(String)
|
78
82
|
end
|
83
|
+
|
84
|
+
# Determines if the associated object is in a valid state
|
85
|
+
#
|
86
|
+
# An object is considered valid if it is persisted and has no errors.
|
87
|
+
#
|
88
|
+
# @return [Boolean] true if the object is persisted and has no errors, false otherwise
|
89
|
+
def object_valid?
|
90
|
+
object.respond_to?(:persisted?) && object.persisted? &&
|
91
|
+
object.respond_to?(:errors) && !object.errors.empty?
|
92
|
+
end
|
79
93
|
end
|
80
94
|
end
|
81
95
|
end
|