Skip to content

Commit 8f85e16

Browse files
committed
[TAC061] Improve the length validation on the proposal body
1 parent e8e8c25 commit 8f85e16

3 files changed

Lines changed: 42 additions & 3 deletions

File tree

decidim-core/lib/decidim/form_builder.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,9 +597,16 @@ def string_or_symbol?(obj)
597597
# Returns an Integer or Nil.
598598
def length_for_attribute(attribute, type)
599599
length_validator = find_validator(attribute, ActiveModel::Validations::LengthValidator)
600-
return unless length_validator
600+
return length_validator.options[type] if length_validator
601601

602-
length_validator.options[type]
602+
length_validator = find_validator(attribute, ProposalLengthValidator)
603+
if length_validator
604+
length = length_validator.options[type]
605+
return length.call(object) if length.respond_to?(:call)
606+
return length
607+
end
608+
609+
nil
603610
end
604611

605612
# Private: Finds a validator.

decidim-proposals/app/forms/decidim/proposals/proposal_wizard_create_step_form.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ class ProposalWizardCreateStepForm < Decidim::Form
1313

1414
validates :title, :body, presence: true, etiquette: true
1515
validates :title, length: { in: 15..150 }
16-
validates :body, length: { minimum: 15 }
16+
validates :body, proposal_length: {
17+
minimum: 15,
18+
maximum: ->(record) { record.component.settings.proposal_length }
19+
}
1720

1821
validate :proposal_length
1922
validate :body_is_not_bare_template
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# frozen_string_literal: true
2+
3+
# This validator takes care of ensuring the validated attributes are long enough
4+
# and not too long. The difference to the Rails length validator is that this
5+
# allows the minimum and maximum values to be lambdas allowing us to fetch the
6+
# maximum length dynamically for each proposals component.
7+
class ProposalLengthValidator < ActiveModel::EachValidator
8+
def validate_each(record, attribute, value)
9+
return if value.blank?
10+
11+
validate_length(record, attribute, value)
12+
end
13+
14+
private
15+
16+
def validate_length(record, attribute, value)
17+
min = options[:minimum] || nil
18+
min = min.call(record) if min.respond_to?(:call)
19+
if min && min > 0 && value.length < min
20+
record.errors.add(attribute, options[:message] || :too_short)
21+
end
22+
23+
max = options[:maximum] || nil
24+
max = max.call(record) if max.respond_to?(:call)
25+
if max && max > 0 && value.length > max
26+
record.errors.add(attribute, options[:message] || :too_long)
27+
end
28+
end
29+
end

0 commit comments

Comments
 (0)