From 5fadd12be6bb2fef1da4caec37723c44a5011852 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Tue, 9 May 2017 14:40:22 +0900 Subject: [PATCH] Protect the latest event from automatic deletion when using MySQL Detecting the database type by the name this time, because ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter is defined only if the mysql2 gem is loaded. This works around #1940 for the most typical cases. --- app/models/event.rb | 17 ++++++++++++++--- spec/models/event_spec.rb | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/app/models/event.rb b/app/models/event.rb index 024c7f5e..3f2f1cc9 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -28,6 +28,15 @@ class Event < ActiveRecord::Base where("expires_at IS NOT NULL AND expires_at < ?", Time.now) } + case ActiveRecord::Base.connection.adapter_name + when /\Amysql/i + # Protect the Event table from InnoDB's AUTO_INCREMENT Counter + # Initialization by always keeping the latest event. + scope :to_expire, -> { expired.where.not(id: maximum(:id)) } + else + scope :to_expire, -> { expired } + end + scope :with_location, -> { where.not(lat: nil).where.not(lng: nil) } @@ -72,9 +81,11 @@ class Event < ActiveRecord::Base # Look for Events whose `expires_at` is present and in the past. Remove those events and then update affected Agents' # `events_counts` cache columns. This method is called by bin/schedule.rb periodically. def self.cleanup_expired! - affected_agents = Event.expired.group("agent_id").pluck(:agent_id) - Event.expired.delete_all - Agent.where(:id => affected_agents).update_all "events_count = (select count(*) from events where agent_id = agents.id)" + transaction do + affected_agents = Event.expired.group("agent_id").pluck(:agent_id) + Event.to_expire.delete_all + Agent.where(id: affected_agents).update_all "events_count = (select count(*) from events where agent_id = agents.id)" + end end protected diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index e5458c4e..92d34b70 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -118,6 +118,20 @@ describe Event do Event.cleanup_expired! expect(Event.find_by_id(event.id)).not_to be_nil end + + it "always keeps the latest Event regardless of its expires_at value only if the database is MySQL" do + Event.delete_all + event1 = agents(:jane_weather_agent).create_event expires_at: 1.minute.ago + event2 = agents(:bob_weather_agent).create_event expires_at: 1.minute.ago + + Event.cleanup_expired! + case ActiveRecord::Base.connection.adapter_name + when /\Amysql/i + expect(Event.all.pluck(:id)).to eq([event2.id]) + else + expect(Event.all.pluck(:id)).to be_empty + end + end end describe "after destroy" do