Skip to content

Commit d141623

Browse files
committed
[#72917] Improve migration and add migration spec
1 parent 5875bdb commit d141623

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed

db/migrate/20260312121938_initialize_historic_identifiers.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,16 @@ class InitializeHistoricIdentifiers < ActiveRecord::Migration[8.1]
3232
def up
3333
execute <<~SQL.squish
3434
INSERT INTO friendly_id_slugs (slug, sluggable_id, sluggable_type, scope, created_at)
35-
SELECT identifier, id, 'Project', NULL, NOW()
36-
FROM projects
37-
WHERE identifier IS NOT NULL
35+
SELECT p.identifier, p.id, 'Project', NULL, NOW()
36+
FROM projects p
37+
WHERE p.identifier IS NOT NULL
38+
AND NOT EXISTS (
39+
SELECT 1 FROM friendly_id_slugs fis
40+
WHERE fis.slug = p.identifier
41+
AND fis.sluggable_id = p.id
42+
AND fis.sluggable_type = 'Project'
43+
AND fis.scope IS NULL
44+
)
3845
SQL
3946
end
4047

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
require "spec_helper"
32+
require Rails.root.join("db/migrate/20260312121938_initialize_historic_identifiers.rb")
33+
34+
RSpec.describe InitializeHistoricIdentifiers, type: :model do
35+
subject(:execute_migration) { ActiveRecord::Migration.suppress_messages { described_class.new.up } }
36+
37+
let!(:project1) { create(:project, identifier: "project-one") }
38+
let!(:project2) { create(:project, identifier: "project-two") }
39+
let!(:project3) { create(:project, identifier: "project-three") }
40+
41+
before do
42+
FriendlyId::Slug.delete_all
43+
end
44+
45+
it "succeeds" do
46+
expect { execute_migration }.not_to raise_error
47+
end
48+
49+
it "creates friendly_id_slugs entries for all projects" do
50+
expect { execute_migration }.to change(FriendlyId::Slug, :count).by(3)
51+
end
52+
53+
it "creates entries with correct attributes" do
54+
execute_migration
55+
56+
slug1 = FriendlyId::Slug.find_by(sluggable_id: project1.id, sluggable_type: "Project")
57+
expect(slug1).to have_attributes(
58+
slug: "project-one",
59+
sluggable_id: project1.id,
60+
sluggable_type: "Project",
61+
scope: nil
62+
)
63+
64+
slug2 = FriendlyId::Slug.find_by(sluggable_id: project2.id, sluggable_type: "Project")
65+
expect(slug2).to have_attributes(
66+
slug: "project-two",
67+
sluggable_id: project2.id,
68+
sluggable_type: "Project",
69+
scope: nil
70+
)
71+
72+
slug3 = FriendlyId::Slug.find_by(sluggable_id: project3.id, sluggable_type: "Project")
73+
expect(slug3).to have_attributes(
74+
slug: "project-three",
75+
sluggable_id: project3.id,
76+
sluggable_type: "Project",
77+
scope: nil
78+
)
79+
end
80+
81+
it "sets created_at timestamp" do
82+
execute_migration
83+
84+
slug = FriendlyId::Slug.find_by(sluggable_id: project1.id, sluggable_type: "Project")
85+
expect(slug.created_at).to be_present
86+
expect(slug.created_at).to be_within(5.minutes).of(Time.zone.now)
87+
end
88+
89+
context "when friendly_id_slugs entries already exist" do
90+
before do
91+
FriendlyId::Slug.create!(
92+
slug: "existing-slug",
93+
sluggable_id: project1.id,
94+
sluggable_type: "Project"
95+
)
96+
end
97+
98+
it "does not delete / overwrite existing values" do
99+
expect { execute_migration }.to change(FriendlyId::Slug, :count).by(3)
100+
expect(FriendlyId::Slug.find_by(slug: "existing-slug")).to be_present
101+
end
102+
end
103+
end

0 commit comments

Comments
 (0)