diff --git a/app/models/budget.rb b/app/models/budget.rb index 8d65d63e3..f11c378ff 100644 --- a/app/models/budget.rb +++ b/app/models/budget.rb @@ -2,6 +2,7 @@ class Budget < ApplicationRecord include Measurable include Sluggable + include StatsVersionable translates :name, touch: true include Globalizable diff --git a/app/models/budget/stats.rb b/app/models/budget/stats.rb index 783536920..766e6ef77 100644 --- a/app/models/budget/stats.rb +++ b/app/models/budget/stats.rb @@ -178,6 +178,6 @@ class Budget::Stats stats_cache :voters, :participants, :authors, :balloters, :poll_ballot_voters def stats_cache(key, &block) - Rails.cache.fetch("budgets_stats/#{budget.id}/#{phases.join}/#{key}/v10", &block) + Rails.cache.fetch("budgets_stats/#{budget.id}/#{phases.join}/#{key}/#{version}", &block) end end diff --git a/app/models/concerns/statisticable.rb b/app/models/concerns/statisticable.rb index 05a8c8bff..14cb1fa9d 100644 --- a/app/models/concerns/statisticable.rb +++ b/app/models/concerns/statisticable.rb @@ -88,6 +88,10 @@ module Statisticable PercentageCalculator.calculate(fraction, total) end + def version + "v#{resource.find_or_create_stats_version.updated_at.to_i}" + end + private def base_stats_methods diff --git a/app/models/concerns/stats_versionable.rb b/app/models/concerns/stats_versionable.rb new file mode 100644 index 000000000..5f1d94ffd --- /dev/null +++ b/app/models/concerns/stats_versionable.rb @@ -0,0 +1,11 @@ +module StatsVersionable + extend ActiveSupport::Concern + + included do + has_one :stats_version, as: :process + end + + def find_or_create_stats_version + stats_version || create_stats_version + end +end diff --git a/app/models/poll.rb b/app/models/poll.rb index 7e9cef89a..5a9284d42 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -6,6 +6,7 @@ class Poll < ApplicationRecord include ActsAsParanoidAliases include Notifiable include Sluggable + include StatsVersionable translates :name, touch: true translates :summary, touch: true diff --git a/app/models/poll/stats.rb b/app/models/poll/stats.rb index 12d1b800d..a6be63640 100644 --- a/app/models/poll/stats.rb +++ b/app/models/poll/stats.rb @@ -107,7 +107,7 @@ class Poll::Stats stats_cache :participants, :voters, :recounts def stats_cache(key, &block) - Rails.cache.fetch("polls_stats/#{poll.id}/#{key}/v12", &block) + Rails.cache.fetch("polls_stats/#{poll.id}/#{key}/#{version}", &block) end end diff --git a/app/models/stats_version.rb b/app/models/stats_version.rb new file mode 100644 index 000000000..f47ddea44 --- /dev/null +++ b/app/models/stats_version.rb @@ -0,0 +1,5 @@ +class StatsVersion < ApplicationRecord + validates :process, presence: true + + belongs_to :process, polymorphic: true +end diff --git a/db/migrate/20190408133956_create_stats_versions.rb b/db/migrate/20190408133956_create_stats_versions.rb new file mode 100644 index 000000000..155731fbd --- /dev/null +++ b/db/migrate/20190408133956_create_stats_versions.rb @@ -0,0 +1,8 @@ +class CreateStatsVersions < ActiveRecord::Migration[4.2] + def change + create_table :stats_versions do |t| + t.references :process, polymorphic: true, index: true + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 857082f44..a3bff9ed4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1339,6 +1339,14 @@ ActiveRecord::Schema.define(version: 20190411090023) do t.index ["tsv"], name: "index_spending_proposals_on_tsv", using: :gin end + create_table "stats_versions", force: :cascade do |t| + t.string "process_type" + t.integer "process_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["process_type", "process_id"], name: "index_stats_versions_on_process_type_and_process_id", using: :btree + end + create_table "taggings", force: :cascade do |t| t.integer "tag_id" t.integer "taggable_id" diff --git a/spec/models/poll/stats_spec.rb b/spec/models/poll/stats_spec.rb index 335d72181..0f0957dd5 100644 --- a/spec/models/poll/stats_spec.rb +++ b/spec/models/poll/stats_spec.rb @@ -231,4 +231,30 @@ describe Poll::Stats do end end end + + describe "#version", :with_frozen_time do + context "record with no stats" do + it "returns a string based on the current time" do + expect(stats.version).to eq "v#{Time.current.to_i}" + end + + it "doesn't overwrite the timestamp when called multiple times" do + time = Time.current + + expect(stats.version).to eq "v#{time.to_i}" + + travel_to 2.seconds.from_now do + expect(stats.version).to eq "v#{time.to_i}" + end + end + end + + context "record with stats" do + before { poll.create_stats_version(updated_at: 1.day.ago) } + + it "returns the version of the existing stats" do + expect(stats.version).to eq "v#{1.day.ago.to_i}" + end + end + end end diff --git a/spec/models/stats_version_spec.rb b/spec/models/stats_version_spec.rb new file mode 100644 index 000000000..eb875ed09 --- /dev/null +++ b/spec/models/stats_version_spec.rb @@ -0,0 +1,13 @@ +require "rails_helper" + +describe StatsVersion do + describe "validations" do + it "is valid with a process" do + expect(StatsVersion.new(process: Budget.new)).to be_valid + end + + it "is not valid without a process" do + expect(StatsVersion.new(process: nil)).not_to be_valid + end + end +end