diff --git a/app/models/activity.rb b/app/models/activity.rb index 3accc495b..2d969e924 100644 --- a/app/models/activity.rb +++ b/app/models/activity.rb @@ -4,7 +4,7 @@ class Activity < ApplicationRecord VALID_ACTIONS = %w[hide block restore valuate email].freeze - validates :action, inclusion: { in: VALID_ACTIONS } + validates :action, inclusion: { in: ->(*) { VALID_ACTIONS }} scope :on_proposals, -> { where(actionable_type: "Proposal") } scope :on_debates, -> { where(actionable_type: "Debate") } diff --git a/app/models/budget.rb b/app/models/budget.rb index 1f7c7dc2b..cec58efe6 100644 --- a/app/models/budget.rb +++ b/app/models/budget.rb @@ -25,10 +25,10 @@ class Budget < ApplicationRecord validates_translation :name, presence: true validates_translation :main_link_url, presence: true, unless: -> { main_link_text.blank? } - validates :phase, inclusion: { in: Budget::Phase::PHASE_KINDS } + validates :phase, inclusion: { in: ->(*) { Budget::Phase::PHASE_KINDS }} validates :currency_symbol, presence: true validates :slug, presence: true, format: /\A[a-z0-9\-_]+\z/ - validates :voting_style, inclusion: { in: VOTING_STYLES } + validates :voting_style, inclusion: { in: ->(*) { VOTING_STYLES }} has_many :investments, dependent: :destroy has_many :ballots, dependent: :destroy diff --git a/app/models/budget/phase.rb b/app/models/budget/phase.rb index ae0c37634..28ae761d1 100644 --- a/app/models/budget/phase.rb +++ b/app/models/budget/phase.rb @@ -19,7 +19,7 @@ class Budget has_one :prev_phase, class_name: name, foreign_key: :next_phase_id, inverse_of: :next_phase validates_translation :name, presence: true - validates_translation :description, length: { maximum: DESCRIPTION_MAX_LENGTH } + validates_translation :description, length: { maximum: ->(*) { DESCRIPTION_MAX_LENGTH }} validates_translation :main_link_url, presence: true, unless: -> { main_link_text.blank? } validates :budget, presence: true validates :kind, presence: true, uniqueness: { scope: :budget }, inclusion: { in: ->(*) { PHASE_KINDS }} diff --git a/app/models/budget/reclassified_vote.rb b/app/models/budget/reclassified_vote.rb index ea73d27c1..958f6479a 100644 --- a/app/models/budget/reclassified_vote.rb +++ b/app/models/budget/reclassified_vote.rb @@ -7,6 +7,6 @@ class Budget validates :user, presence: true validates :investment, presence: true - validates :reason, inclusion: { in: REASONS, allow_nil: false } + validates :reason, inclusion: { in: ->(*) { REASONS }, allow_nil: false } end end diff --git a/app/models/comment.rb b/app/models/comment.rb index 443d2322d..e6f9a0af3 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -21,7 +21,7 @@ class Comment < ApplicationRecord validates_translation :body, presence: true validates :user, presence: true - validates :commentable_type, inclusion: { in: COMMENTABLE_TYPES } + validates :commentable_type, inclusion: { in: ->(*) { COMMENTABLE_TYPES }} validate :validate_body_length validate :comment_valuation, if: -> { valuation } diff --git a/app/models/legislation/draft_version.rb b/app/models/legislation/draft_version.rb index 9019d6cb8..c7576c421 100644 --- a/app/models/legislation/draft_version.rb +++ b/app/models/legislation/draft_version.rb @@ -17,7 +17,7 @@ class Legislation::DraftVersion < ApplicationRecord validates_translation :title, presence: true validates_translation :body, presence: true - validates :status, presence: true, inclusion: { in: VALID_STATUSES } + validates :status, presence: true, inclusion: { in: ->(*) { VALID_STATUSES }} scope :published, -> { where(status: "published").order("id DESC") } diff --git a/app/models/legislation/process.rb b/app/models/legislation/process.rb index 77240a13e..a0b28c3fd 100644 --- a/app/models/legislation/process.rb +++ b/app/models/legislation/process.rb @@ -55,8 +55,8 @@ class Legislation::Process < ApplicationRecord end validate :valid_date_ranges - validates :background_color, format: { allow_blank: true, with: CSS_HEX_COLOR } - validates :font_color, format: { allow_blank: true, with: CSS_HEX_COLOR } + validates :background_color, format: { allow_blank: true, with: ->(*) { CSS_HEX_COLOR }} + validates :font_color, format: { allow_blank: true, with: ->(*) { CSS_HEX_COLOR }} class << self; undef :open; end scope :open, -> { where("start_date <= ? and end_date >= ?", Date.current, Date.current) } diff --git a/app/models/poll/partial_result.rb b/app/models/poll/partial_result.rb index d8e9cc18b..eb11dd4e3 100644 --- a/app/models/poll/partial_result.rb +++ b/app/models/poll/partial_result.rb @@ -11,7 +11,7 @@ class Poll::PartialResult < ApplicationRecord validates :answer, presence: true validates :answer, inclusion: { in: ->(a) { a.question.possible_answers }}, unless: ->(a) { a.question.blank? } - validates :origin, inclusion: { in: VALID_ORIGINS } + validates :origin, inclusion: { in: ->(*) { VALID_ORIGINS }} scope :by_author, ->(author_id) { where(author_id: author_id) } scope :by_question, ->(question_id) { where(question_id: question_id) } diff --git a/app/models/poll/recount.rb b/app/models/poll/recount.rb index b5fb52bbf..578956692 100644 --- a/app/models/poll/recount.rb +++ b/app/models/poll/recount.rb @@ -6,7 +6,7 @@ class Poll::Recount < ApplicationRecord belongs_to :officer_assignment validates :author, presence: true - validates :origin, inclusion: { in: VALID_ORIGINS } + validates :origin, inclusion: { in: ->(*) { VALID_ORIGINS }} scope :web, -> { where(origin: "web") } scope :booth, -> { where(origin: "booth") } diff --git a/app/models/poll/voter.rb b/app/models/poll/voter.rb index 2ea150718..ab6e3a0a6 100644 --- a/app/models/poll/voter.rb +++ b/app/models/poll/voter.rb @@ -16,7 +16,7 @@ class Poll validates :document_number, presence: true, unless: :skip_user_verification? validates :user_id, uniqueness: { scope: [:poll_id], message: :has_voted } - validates :origin, inclusion: { in: VALID_ORIGINS } + validates :origin, inclusion: { in: ->(*) { VALID_ORIGINS }} before_validation :set_demographic_info, :set_document_info, :set_denormalized_booth_assignment_id diff --git a/app/models/progress_bar.rb b/app/models/progress_bar.rb index 3da9c072b..cf20c0d2e 100644 --- a/app/models/progress_bar.rb +++ b/app/models/progress_bar.rb @@ -16,7 +16,7 @@ class ProgressBar < ApplicationRecord scope: [:progressable_type, :progressable_id], conditions: -> { primary } } - validates :percentage, presence: true, inclusion: RANGE, numericality: { only_integer: true } + validates :percentage, presence: true, inclusion: { in: ->(*) { RANGE }}, numericality: { only_integer: true } validates_translation :title, presence: true, unless: :primary? end diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 3f1ff98e3..92bcc2aa1 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -51,7 +51,7 @@ class Proposal < ApplicationRecord validates :responsible_name, presence: true, unless: :skip_user_verification? validates :responsible_name, length: { in: 6..Proposal.responsible_name_max_length }, unless: :skip_user_verification? - validates :retired_reason, presence: true, inclusion: { in: RETIRE_OPTIONS }, unless: -> { retired_at.blank? } + validates :retired_reason, presence: true, inclusion: { in: ->(*) { RETIRE_OPTIONS }}, unless: -> { retired_at.blank? } validates :terms_of_service, acceptance: { allow_nil: false }, on: :create diff --git a/app/models/signature_sheet.rb b/app/models/signature_sheet.rb index c767c0bf1..713d6ef71 100644 --- a/app/models/signature_sheet.rb +++ b/app/models/signature_sheet.rb @@ -7,7 +7,7 @@ class SignatureSheet < ApplicationRecord has_many :signatures validates :author, presence: true - validates :signable_type, inclusion: { in: VALID_SIGNABLES } + validates :signable_type, inclusion: { in: ->(*) { VALID_SIGNABLES }} validates :required_fields_to_verify, presence: true validates :signable, presence: true validate :signable_found diff --git a/app/models/site_customization/content_block.rb b/app/models/site_customization/content_block.rb index a41580e36..744819956 100644 --- a/app/models/site_customization/content_block.rb +++ b/app/models/site_customization/content_block.rb @@ -2,7 +2,7 @@ class SiteCustomization::ContentBlock < ApplicationRecord VALID_BLOCKS = %w[top_links footer subnavigation_left subnavigation_right].freeze validates :locale, presence: true, inclusion: { in: I18n.available_locales.map(&:to_s) } - validates :name, presence: true, uniqueness: { scope: :locale }, inclusion: { in: VALID_BLOCKS } + validates :name, presence: true, uniqueness: { scope: :locale }, inclusion: { in: ->(*) { VALID_BLOCKS }} def self.block_for(name, locale) locale ||= I18n.default_locale diff --git a/app/models/site_customization/image.rb b/app/models/site_customization/image.rb index c9c41ed6a..185da4a25 100644 --- a/app/models/site_customization/image.rb +++ b/app/models/site_customization/image.rb @@ -13,7 +13,7 @@ class SiteCustomization::Image < ApplicationRecord has_attachment :image - validates :name, presence: true, uniqueness: true, inclusion: { in: VALID_IMAGES.keys } + validates :name, presence: true, uniqueness: true, inclusion: { in: ->(*) { VALID_IMAGES.keys }} validates :image, file_content_type: { allow: ["image/png", "image/jpeg"], if: -> { image.attached? }} validate :check_image diff --git a/app/models/site_customization/page.rb b/app/models/site_customization/page.rb index 2c2c84fd5..a5a1105d1 100644 --- a/app/models/site_customization/page.rb +++ b/app/models/site_customization/page.rb @@ -10,7 +10,7 @@ class SiteCustomization::Page < ApplicationRecord validates :slug, presence: true, uniqueness: { case_sensitive: false }, format: { with: /\A[0-9a-zA-Z\-_]*\Z/, message: :slug_format } - validates :status, presence: true, inclusion: { in: VALID_STATUSES } + validates :status, presence: true, inclusion: { in: ->(*) { VALID_STATUSES }} scope :published, -> { where(status: "published").sort_desc } scope :sort_asc, -> { order("id ASC") } diff --git a/spec/models/activity_spec.rb b/spec/models/activity_spec.rb index 16db70490..185d9ea84 100644 --- a/spec/models/activity_spec.rb +++ b/spec/models/activity_spec.rb @@ -17,6 +17,13 @@ describe Activity do expect(build(:activity, action: "dissapear")).not_to be_valid end + it "dynamically validates valid actions" do + stub_const("#{Activity}::VALID_ACTIONS", %w[custom]) + + expect(build(:activity, action: "custom")).to be_valid + expect(build(:activity, action: "hide")).not_to be_valid + end + describe "log" do it "creates an activity entry" do user = create(:user) diff --git a/spec/models/budget/phase_spec.rb b/spec/models/budget/phase_spec.rb index 58d70ca44..0833a2a62 100644 --- a/spec/models/budget/phase_spec.rb +++ b/spec/models/budget/phase_spec.rb @@ -28,6 +28,16 @@ describe Budget::Phase do end end + describe "description validations" do + it "dynamically validates the maximum length" do + stub_const("#{Budget::Phase}::DESCRIPTION_MAX_LENGTH", 3) + + informing_phase.description_en = "long" + + expect(informing_phase).not_to be_valid + end + end + describe "#dates_range_valid?" do it "is valid when start & end dates are different & consecutive" do informing_phase.assign_attributes(starts_at: Date.current, ends_at: Date.tomorrow) diff --git a/spec/models/budget/reclassified_vote_spec.rb b/spec/models/budget/reclassified_vote_spec.rb index 90f0e04f5..5b0b8d893 100644 --- a/spec/models/budget/reclassified_vote_spec.rb +++ b/spec/models/budget/reclassified_vote_spec.rb @@ -34,5 +34,15 @@ describe Budget::ReclassifiedVote do reclassified_vote.reason = "unfeasible" expect(reclassified_vote).to be_valid end + + it "dynamically validates the reasons" do + stub_const("#{Budget::ReclassifiedVote}::REASONS", %w[custom]) + + reclassified_vote.reason = "custom" + expect(reclassified_vote).to be_valid + + reclassified_vote.reason = "unfeasible" + expect(reclassified_vote).not_to be_valid + end end end diff --git a/spec/models/budget_spec.rb b/spec/models/budget_spec.rb index 41e827e31..f6d9818d5 100644 --- a/spec/models/budget_spec.rb +++ b/spec/models/budget_spec.rb @@ -148,6 +148,16 @@ describe Budget do expect(budget).not_to be_valid end + it "dynamically validates the phases" do + stub_const("#{Budget::Phase}::PHASE_KINDS", %w[accepting custom]) + + budget.phase = "custom" + expect(budget).to be_valid + + budget.phase = "reviewing" + expect(budget).not_to be_valid + end + it "produces auxiliary methods" do budget.phase = "accepting" expect(budget).to be_accepting @@ -444,6 +454,13 @@ describe Budget do it { expect(build(:budget, :approval)).to be_valid } it { expect(build(:budget, :knapsack)).to be_valid } it { expect(build(:budget, voting_style: "Oups!")).not_to be_valid } + + it "dynamically validates the voting styles" do + stub_const("#{Budget}::VOTING_STYLES", %w[custom]) + + expect(build(:budget, voting_style: "custom")).to be_valid + expect(build(:budget, voting_style: "knapsack")).not_to be_valid + end end context "Related supportive methods" do diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index f52b099d9..7123c9605 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -11,6 +11,13 @@ describe Comment do expect(comment).to be_valid end + it "dynamically validates the commentable types" do + stub_const("#{Comment}::COMMENTABLE_TYPES", %w[Debate]) + + expect(build(:comment, commentable: create(:debate))).to be_valid + expect(build(:comment, commentable: create(:proposal))).not_to be_valid + end + it "updates cache_counter in debate after hide and restore" do debate = create(:debate) comment = create(:comment, commentable: debate) diff --git a/spec/models/legislation/draft_version_spec.rb b/spec/models/legislation/draft_version_spec.rb index b0416d590..910a15f65 100644 --- a/spec/models/legislation/draft_version_spec.rb +++ b/spec/models/legislation/draft_version_spec.rb @@ -10,6 +10,16 @@ describe Legislation::DraftVersion do expect(legislation_draft_version).to be_valid end + it "dynamically validates the valid statuses" do + stub_const("#{Legislation::DraftVersion}::VALID_STATUSES", %w[custom]) + + legislation_draft_version.status = "custom" + expect(legislation_draft_version).to be_valid + + legislation_draft_version.status = "published" + expect(legislation_draft_version).not_to be_valid + end + it "renders the html from the markdown body field" do legislation_draft_version.body = body_markdown diff --git a/spec/models/legislation/process_spec.rb b/spec/models/legislation/process_spec.rb index 0d0519407..5f0e2999c 100644 --- a/spec/models/legislation/process_spec.rb +++ b/spec/models/legislation/process_spec.rb @@ -10,6 +10,13 @@ describe Legislation::Process do expect(process).to be_valid end + it "dynamically validates the color format" do + stub_const("#{Legislation::Process}::CSS_HEX_COLOR", /[G-H]{2}/) + + expect(build(:legislation_process, font_color: "GG", background_color: "GH")).to be_valid + expect(build(:legislation_process, font_color: "#ff0", background_color: "#00f")).not_to be_valid + end + it "assigns default values to new processes" do process = Legislation::Process.new diff --git a/spec/models/poll/partial_result_spec.rb b/spec/models/poll/partial_result_spec.rb index b5a045329..3e92379a2 100644 --- a/spec/models/poll/partial_result_spec.rb +++ b/spec/models/poll/partial_result_spec.rb @@ -14,6 +14,13 @@ describe Poll::PartialResult do expect(build(:poll_partial_result, question: question, answer: "Four")).not_to be_valid end + + it "dynamically validates the valid origins" do + stub_const("#{Poll::PartialResult}::VALID_ORIGINS", %w[custom]) + + expect(build(:poll_partial_result, origin: "custom")).to be_valid + expect(build(:poll_partial_result, origin: "web")).not_to be_valid + end end describe "logging changes" do diff --git a/spec/models/poll/recount_spec.rb b/spec/models/poll/recount_spec.rb index 11646edd8..4a8e741a4 100644 --- a/spec/models/poll/recount_spec.rb +++ b/spec/models/poll/recount_spec.rb @@ -1,6 +1,15 @@ require "rails_helper" describe Poll::Recount do + describe "validations" do + it "dynamically validates the valid origins" do + stub_const("#{Poll::Recount}::VALID_ORIGINS", %w[custom]) + + expect(build(:poll_recount, origin: "custom")).to be_valid + expect(build(:poll_recount, origin: "web")).not_to be_valid + end + end + describe "logging changes" do let(:author) { create(:user) } let(:officer_assignment) { create(:poll_officer_assignment) } diff --git a/spec/models/poll/voter_spec.rb b/spec/models/poll/voter_spec.rb index 9ed82be67..b30c7428e 100644 --- a/spec/models/poll/voter_spec.rb +++ b/spec/models/poll/voter_spec.rb @@ -117,6 +117,13 @@ describe Poll::Voter do voter.origin = "web" expect(voter).to be_valid end + + it "dynamically validates the valid origins" do + stub_const("#{Poll::Voter}::VALID_ORIGINS", %w[custom]) + + expect(build(:poll_voter, origin: "custom")).to be_valid + expect(build(:poll_voter, origin: "web")).not_to be_valid + end end context "assignments" do diff --git a/spec/models/progress_bar_spec.rb b/spec/models/progress_bar_spec.rb index f5ea05c8f..f0efbbcbd 100644 --- a/spec/models/progress_bar_spec.rb +++ b/spec/models/progress_bar_spec.rb @@ -64,6 +64,18 @@ describe ProgressBar do expect(progress_bar).to be_valid end + it "dynamically validates the percentage range" do + stub_const("#{ProgressBar}::RANGE", (-99..99)) + + progress_bar.percentage = -99 + + expect(progress_bar).to be_valid + + progress_bar.percentage = 100 + + expect(progress_bar).not_to be_valid + end + it "is not valid without a progressable" do progress_bar.progressable = nil diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 5e14c7688..469e986b2 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -171,6 +171,19 @@ describe Proposal do proposal.retired_reason = nil expect(proposal).not_to be_valid end + + it "dynamically validates the retired reason" do + stub_const("#{Proposal}::RETIRE_OPTIONS", %w[custom]) + + proposal.retired_at = Time.current + proposal.retired_explanation = "My custom reason" + + proposal.retired_reason = "custom" + expect(proposal).to be_valid + + proposal.retired_reason = "duplicated" + expect(proposal).not_to be_valid + end end describe "#editable?" do diff --git a/spec/models/signature_sheet_spec.rb b/spec/models/signature_sheet_spec.rb index c32e94b5c..9224b61a9 100644 --- a/spec/models/signature_sheet_spec.rb +++ b/spec/models/signature_sheet_spec.rb @@ -26,6 +26,16 @@ describe SignatureSheet do expect(signature_sheet).not_to be_valid end + it "dynamically validates the valid signables" do + stub_const("#{SignatureSheet}::VALID_SIGNABLES", %w[Comment]) + + signature_sheet.signable = create(:comment) + expect(signature_sheet).to be_valid + + signature_sheet.signable = create(:proposal) + expect(signature_sheet).not_to be_valid + end + it "is not valid without document numbers" do signature_sheet.required_fields_to_verify = nil expect(signature_sheet).not_to be_valid diff --git a/spec/models/site_customization/content_block_spec.rb b/spec/models/site_customization/content_block_spec.rb index 7cdc5b1b8..e5f1e1ec5 100644 --- a/spec/models/site_customization/content_block_spec.rb +++ b/spec/models/site_customization/content_block_spec.rb @@ -17,4 +17,14 @@ RSpec.describe SiteCustomization::ContentBlock, type: :model do valid_block = build(:site_customization_content_block, name: "top_links", locale: "es") expect(valid_block).to be_valid end + + it "dynamically validates the valid blocks" do + stub_const("#{SiteCustomization::ContentBlock}::VALID_BLOCKS", %w[custom]) + + block.name = "custom" + expect(block).to be_valid + + block.name = "top_links" + expect(block).not_to be_valid + end end diff --git a/spec/models/site_customization/image_spec.rb b/spec/models/site_customization/image_spec.rb index 076fc01d5..945046144 100644 --- a/spec/models/site_customization/image_spec.rb +++ b/spec/models/site_customization/image_spec.rb @@ -33,5 +33,15 @@ describe SiteCustomization::Image do expect(image).not_to be_valid end + + it "dynamically validates the valid images" do + stub_const("#{SiteCustomization::Image}::VALID_IMAGES", { "custom" => [223, 80] }) + + custom = build(:site_customization_image, name: "custom", image: fixture_file_upload("logo_header.png")) + expect(custom).to be_valid + + map = build(:site_customization_image, name: "map", image: fixture_file_upload("custom_map.jpg")) + expect(map).not_to be_valid + end end end diff --git a/spec/models/site_customization/page_spec.rb b/spec/models/site_customization/page_spec.rb index e2c4f4250..cc700a59f 100644 --- a/spec/models/site_customization/page_spec.rb +++ b/spec/models/site_customization/page_spec.rb @@ -13,4 +13,14 @@ RSpec.describe SiteCustomization::Page, type: :model do custom_page = build(:site_customization_page, slug: "as/as*la") expect(custom_page).to be_invalid end + + it "dynamically validates the valid statuses" do + stub_const("#{SiteCustomization::Page}::VALID_STATUSES", %w[custom]) + + custom_page.status = "custom" + expect(custom_page).to be_valid + + custom_page.status = "published" + expect(custom_page).not_to be_valid + end end