diff --git a/app/models/concerns/questionable.rb b/app/models/concerns/questionable.rb new file mode 100644 index 000000000..12d8ce399 --- /dev/null +++ b/app/models/concerns/questionable.rb @@ -0,0 +1,12 @@ +module Questionable + extend ActiveSupport::Concern + + included do + has_one :votation_type, as: :questionable, dependent: :destroy + delegate :max_votes, :multiple?, :vote_type, to: :votation_type, allow_nil: true + end + + def unique? + votation_type.nil? || votation_type.unique? + end +end diff --git a/app/models/poll/question.rb b/app/models/poll/question.rb index 6f489c8d8..6be7aecc9 100644 --- a/app/models/poll/question.rb +++ b/app/models/poll/question.rb @@ -1,6 +1,7 @@ class Poll::Question < ApplicationRecord include Measurable include Searchable + include Questionable acts_as_paranoid column: :hidden_at include ActsAsParanoidAliases diff --git a/app/models/votation_type.rb b/app/models/votation_type.rb new file mode 100644 index 000000000..00fca0ecf --- /dev/null +++ b/app/models/votation_type.rb @@ -0,0 +1,17 @@ +class VotationType < ApplicationRecord + belongs_to :questionable, polymorphic: true + + QUESTIONABLE_TYPES = %w[Poll::Question].freeze + + enum vote_type: %w[unique multiple] + + validates :questionable, presence: true + validates :questionable_type, inclusion: { in: ->(*) { QUESTIONABLE_TYPES }} + validates :max_votes, presence: true, if: :max_votes_required? + + private + + def max_votes_required? + multiple? + end +end diff --git a/db/migrate/20220323233643_add_votation_types.rb b/db/migrate/20220323233643_add_votation_types.rb new file mode 100644 index 000000000..beca11ef6 --- /dev/null +++ b/db/migrate/20220323233643_add_votation_types.rb @@ -0,0 +1,12 @@ +class AddVotationTypes < ActiveRecord::Migration[5.2] + def change + create_table :votation_types do |t| + t.integer :questionable_id + t.string :questionable_type + t.integer :vote_type + t.integer :max_votes + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index cb93e1c07..20c37835e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1698,6 +1698,15 @@ ActiveRecord::Schema.define(version: 2022_09_15_154808) do t.index ["user_id"], name: "index_visits_on_user_id" end + create_table "votation_types", force: :cascade do |t| + t.integer "questionable_id" + t.string "questionable_type" + t.integer "vote_type" + t.integer "max_votes" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "votes", id: :serial, force: :cascade do |t| t.string "votable_type" t.integer "votable_id" diff --git a/spec/factories/votation_type.rb b/spec/factories/votation_type.rb new file mode 100644 index 000000000..dfee71b8d --- /dev/null +++ b/spec/factories/votation_type.rb @@ -0,0 +1,14 @@ +FactoryBot.define do + factory :votation_type do + factory :votation_type_unique do + vote_type { "unique" } + end + + factory :votation_type_multiple do + vote_type { "multiple" } + max_votes { 3 } + end + + association :questionable, factory: :poll_question + end +end diff --git a/spec/models/votation_type_spec.rb b/spec/models/votation_type_spec.rb new file mode 100644 index 000000000..4c947ddd6 --- /dev/null +++ b/spec/models/votation_type_spec.rb @@ -0,0 +1,35 @@ +require "rails_helper" + +describe VotationType do + let(:vote_types) { %i[votation_type_unique votation_type_multiple] } + let(:votation_type) { build(vote_types.sample) } + + it "is valid" do + expect(votation_type).to be_valid + end + + it "is not valid without questionable" do + votation_type.questionable = nil + + expect(votation_type).not_to be_valid + end + + it "is not valid when questionable_type is not allowed" do + votation_type.questionable_type = Poll::Answer + + expect(votation_type).not_to be_valid + expect(votation_type.errors[:questionable_type]).to include "is not included in the list" + end + + it "is not valid when max_votes is undefined for multiple votation_type" do + votation_type.max_votes = nil + votation_type.vote_type = "unique" + + expect(votation_type).to be_valid + + votation_type.vote_type = "multiple" + + expect(votation_type).not_to be_valid + expect(votation_type.errors[:max_votes]).to include "can't be blank" + end +end