Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion lib/simple_form/helpers/validators.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,46 @@ def valid_validator?(validator)
end

def conditional_validators?(validator)
validator.options.include?(:if) || validator.options.include?(:unless)
if_condition = validator.options[:if]
unless_condition = validator.options[:unless]

return false if if_condition.nil? && unless_condition.nil?

conditional = false

if if_condition
conditions = Array(if_condition)
conditional = conditions.any? { |c| !resolve_if_condition(c) }
end

if !conditional && unless_condition
conditions = Array(unless_condition)
conditional = conditions.any? { |c| resolve_if_condition(c) }
end

conditional
# If evaluating the condition fails (e.g., the condition references a method
# the object doesn't have, or a callable with unexpected arity), fall back to
# treating the validator as conditional and skipping it.
rescue NoMethodError, ArgumentError
true
end

def resolve_if_condition(condition)
case condition
when Symbol
object.send(condition)
else
if condition.respond_to?(:call)
if condition.is_a?(Proc) && condition.arity == 0
condition.call
else
condition.call(object)
end
else
condition
end
end
end

def action_validator_match?(validator)
Expand Down
16 changes: 14 additions & 2 deletions test/inputs/required_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,32 @@ class RequiredTest < ActionView::TestCase
end

# VALIDATORS :if :unless
test 'builder input does not be required when ActiveModel::Validations is included and if option is present' do
test 'builder input is required when if condition is present and evaluates to true' do
with_form_for @validating_user, :age
assert_select 'input.required[required]#validating_user_age'
end

test 'builder input is not required when if condition is present and evaluates to false' do
@validating_user.name = nil
with_form_for @validating_user, :age
assert_no_select 'input.required'
assert_no_select 'input[required]'
assert_select 'input.optional#validating_user_age'
end

test 'builder input does not be required when ActiveModel::Validations is included and unless option is present' do
test 'builder input is not required when unless condition is present and evaluates to true' do
with_form_for @validating_user, :amount
assert_no_select 'input.required'
assert_no_select 'input[required]'
assert_select 'input.optional#validating_user_amount'
end

test 'builder input is required when unless condition is present and evaluates to false' do
@validating_user.age = nil
with_form_for @validating_user, :amount
assert_select 'input.required[required]#validating_user_amount'
end

# VALIDATORS :on
test 'builder input is required when validation is on create and is not persisted' do
@validating_user.new_record!
Expand Down