historiographer 4.4.1 → 4.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/DEVELOPMENT.md +124 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +14 -0
- data/README.md +16 -1
- data/Rakefile +54 -0
- data/VERSION +1 -1
- data/bin/console +10 -0
- data/bin/setup +15 -0
- data/bin/test +5 -0
- data/bin/test-all +10 -0
- data/bin/test-rails +5 -0
- data/historiographer.gemspec +38 -4
- data/lib/historiographer/history.rb +193 -60
- data/spec/combustion_helper.rb +34 -0
- data/spec/db/migrate/20250823000000_create_easy_ml_columns.rb +26 -0
- data/spec/db/migrate/20250824000000_create_test_articles.rb +26 -0
- data/spec/db/migrate/20250824000001_create_test_categories.rb +26 -0
- data/spec/db/migrate/20250825000000_create_bylines.rb +11 -0
- data/spec/db/migrate/20250826000000_create_test_users.rb +8 -0
- data/spec/db/migrate/20250826000001_create_test_user_histories.rb +18 -0
- data/spec/db/migrate/20250826000002_create_test_websites.rb +9 -0
- data/spec/db/migrate/20250826000003_create_test_website_histories.rb +19 -0
- data/spec/db/schema.rb +110 -40
- data/spec/historiographer_spec.rb +319 -1
- data/spec/integration/historiographer_safe_integration_spec.rb +154 -0
- data/spec/internal/app/models/application_record.rb +5 -0
- data/spec/internal/app/models/deploy.rb +5 -0
- data/spec/internal/app/models/user.rb +4 -0
- data/spec/internal/app/models/website.rb +5 -0
- data/spec/internal/app/models/website_history.rb +7 -0
- data/spec/internal/config/database.yml +9 -0
- data/spec/internal/config/routes.rb +2 -0
- data/spec/internal/db/schema.rb +48 -0
- data/spec/models/author.rb +1 -0
- data/spec/models/byline.rb +4 -0
- data/spec/models/post.rb +2 -0
- data/spec/models/test_article.rb +4 -0
- data/spec/models/test_article_history.rb +3 -0
- data/spec/models/test_category.rb +4 -0
- data/spec/models/test_category_history.rb +3 -0
- data/spec/models/test_user.rb +4 -0
- data/spec/models/test_user_history.rb +3 -0
- data/spec/models/test_website.rb +4 -0
- data/spec/models/test_website_history.rb +3 -0
- data/spec/rails_integration/historiographer_rails_integration_spec.rb +106 -0
- data/spec/spec_helper.rb +2 -3
- metadata +42 -4
- data/spec/foreign_key_spec.rb +0 -189
data/spec/foreign_key_spec.rb
DELETED
@@ -1,189 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe 'Foreign key handling for belongs_to associations' do
|
4
|
-
before(:all) do
|
5
|
-
@original_stdout = $stdout
|
6
|
-
$stdout = StringIO.new
|
7
|
-
|
8
|
-
ActiveRecord::Base.connection.create_table :test_users, force: true do |t|
|
9
|
-
t.string :name
|
10
|
-
t.timestamps
|
11
|
-
end
|
12
|
-
|
13
|
-
ActiveRecord::Base.connection.create_table :test_websites, force: true do |t|
|
14
|
-
t.string :name
|
15
|
-
t.integer :user_id
|
16
|
-
t.timestamps
|
17
|
-
end
|
18
|
-
|
19
|
-
ActiveRecord::Base.connection.create_table :test_website_histories, force: true do |t|
|
20
|
-
t.integer :test_website_id, null: false
|
21
|
-
t.string :name
|
22
|
-
t.integer :user_id
|
23
|
-
t.timestamps
|
24
|
-
t.datetime :history_started_at, null: false
|
25
|
-
t.datetime :history_ended_at
|
26
|
-
t.integer :history_user_id
|
27
|
-
t.string :snapshot_id
|
28
|
-
|
29
|
-
t.index :test_website_id
|
30
|
-
t.index :history_started_at
|
31
|
-
t.index :history_ended_at
|
32
|
-
t.index :snapshot_id
|
33
|
-
end
|
34
|
-
|
35
|
-
ActiveRecord::Base.connection.create_table :test_user_histories, force: true do |t|
|
36
|
-
t.integer :test_user_id, null: false
|
37
|
-
t.string :name
|
38
|
-
t.timestamps
|
39
|
-
t.datetime :history_started_at, null: false
|
40
|
-
t.datetime :history_ended_at
|
41
|
-
t.integer :history_user_id
|
42
|
-
t.string :snapshot_id
|
43
|
-
|
44
|
-
t.index :test_user_id
|
45
|
-
t.index :history_started_at
|
46
|
-
t.index :history_ended_at
|
47
|
-
t.index :snapshot_id
|
48
|
-
end
|
49
|
-
|
50
|
-
class TestUser < ActiveRecord::Base
|
51
|
-
include Historiographer
|
52
|
-
has_many :test_websites, foreign_key: 'user_id'
|
53
|
-
end
|
54
|
-
|
55
|
-
class TestWebsite < ActiveRecord::Base
|
56
|
-
include Historiographer
|
57
|
-
belongs_to :user, class_name: 'TestUser', foreign_key: 'user_id', optional: true
|
58
|
-
end
|
59
|
-
|
60
|
-
class TestWebsiteHistory < ActiveRecord::Base
|
61
|
-
include Historiographer::History
|
62
|
-
end
|
63
|
-
|
64
|
-
class TestUserHistory < ActiveRecord::Base
|
65
|
-
include Historiographer::History
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
after(:all) do
|
70
|
-
$stdout = @original_stdout
|
71
|
-
ActiveRecord::Base.connection.drop_table :test_website_histories
|
72
|
-
ActiveRecord::Base.connection.drop_table :test_websites
|
73
|
-
ActiveRecord::Base.connection.drop_table :test_user_histories
|
74
|
-
ActiveRecord::Base.connection.drop_table :test_users
|
75
|
-
Object.send(:remove_const, :TestWebsite) if Object.const_defined?(:TestWebsite)
|
76
|
-
Object.send(:remove_const, :TestWebsiteHistory) if Object.const_defined?(:TestWebsiteHistory)
|
77
|
-
Object.send(:remove_const, :TestUser) if Object.const_defined?(:TestUser)
|
78
|
-
Object.send(:remove_const, :TestUserHistory) if Object.const_defined?(:TestUserHistory)
|
79
|
-
end
|
80
|
-
|
81
|
-
describe 'belongs_to association on history models' do
|
82
|
-
it 'does not raise error about wrong column when accessing belongs_to associations' do
|
83
|
-
# This is the core issue: when a history model has a belongs_to association,
|
84
|
-
# it should not use the foreign key as the primary key for lookups
|
85
|
-
|
86
|
-
# Create a user
|
87
|
-
user = TestUser.create!(name: 'Test User', history_user_id: 1)
|
88
|
-
|
89
|
-
# Create a website belonging to the user
|
90
|
-
website = TestWebsite.create!(
|
91
|
-
name: 'Test Website',
|
92
|
-
user_id: user.id,
|
93
|
-
history_user_id: 1
|
94
|
-
)
|
95
|
-
|
96
|
-
# Get the website history
|
97
|
-
website_history = TestWebsiteHistory.last
|
98
|
-
|
99
|
-
# The history should have the correct user_id
|
100
|
-
expect(website_history.user_id).to eq(user.id)
|
101
|
-
|
102
|
-
# The belongs_to association should work without errors
|
103
|
-
# Previously this would fail with "column users.user_id does not exist"
|
104
|
-
# because it was using primary_key: :user_id instead of the default :id
|
105
|
-
expect { website_history.user }.not_to raise_error
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'allows direct creation of history records with foreign keys' do
|
109
|
-
user = TestUser.create!(name: 'Another User', history_user_id: 1)
|
110
|
-
|
111
|
-
# Create history attributes like in the original error case
|
112
|
-
attrs = {
|
113
|
-
"name" => "test.example",
|
114
|
-
"user_id" => user.id,
|
115
|
-
"created_at" => Time.now,
|
116
|
-
"updated_at" => Time.now,
|
117
|
-
"test_website_id" => 100,
|
118
|
-
"history_started_at" => Time.now,
|
119
|
-
"history_user_id" => 1,
|
120
|
-
"snapshot_id" => SecureRandom.uuid
|
121
|
-
}
|
122
|
-
|
123
|
-
# This should not raise an error about test_users.user_id not existing
|
124
|
-
# The original bug was that it would look for test_users.user_id instead of test_users.id
|
125
|
-
expect { TestWebsiteHistory.create!(attrs) }.not_to raise_error
|
126
|
-
|
127
|
-
history = TestWebsiteHistory.last
|
128
|
-
expect(history.user_id).to eq(user.id)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
describe 'snapshot associations with history models' do
|
133
|
-
it 'correctly filters associations by snapshot_id when using custom association methods' do
|
134
|
-
# First create regular history records
|
135
|
-
user = TestUser.create!(name: 'User One', history_user_id: 1)
|
136
|
-
website = TestWebsite.create!(
|
137
|
-
name: 'Website One',
|
138
|
-
user_id: user.id,
|
139
|
-
history_user_id: 1
|
140
|
-
)
|
141
|
-
|
142
|
-
# Check that regular histories were created
|
143
|
-
expect(TestUserHistory.count).to eq(1)
|
144
|
-
expect(TestWebsiteHistory.count).to eq(1)
|
145
|
-
|
146
|
-
# Now create snapshot histories directly (simulating what snapshot would do)
|
147
|
-
snapshot_id = SecureRandom.uuid
|
148
|
-
|
149
|
-
# Create user history with snapshot
|
150
|
-
user_snapshot = TestUserHistory.create!(
|
151
|
-
test_user_id: user.id,
|
152
|
-
name: user.name,
|
153
|
-
created_at: user.created_at,
|
154
|
-
updated_at: user.updated_at,
|
155
|
-
history_started_at: Time.now,
|
156
|
-
history_user_id: 1,
|
157
|
-
snapshot_id: snapshot_id
|
158
|
-
)
|
159
|
-
|
160
|
-
# Create website history with snapshot
|
161
|
-
website_snapshot = TestWebsiteHistory.create!(
|
162
|
-
test_website_id: website.id,
|
163
|
-
name: website.name,
|
164
|
-
user_id: user.id,
|
165
|
-
created_at: website.created_at,
|
166
|
-
updated_at: website.updated_at,
|
167
|
-
history_started_at: Time.now,
|
168
|
-
history_user_id: 1,
|
169
|
-
snapshot_id: snapshot_id
|
170
|
-
)
|
171
|
-
|
172
|
-
# Now test that the association filtering works
|
173
|
-
# The website history's user association should find the user history with the same snapshot_id
|
174
|
-
user_from_association = website_snapshot.user
|
175
|
-
|
176
|
-
# Since user association points to history when snapshots are involved,
|
177
|
-
# it should return the TestUserHistory with matching snapshot_id
|
178
|
-
if user_from_association.is_a?(TestUserHistory)
|
179
|
-
expect(user_from_association.snapshot_id).to eq(snapshot_id)
|
180
|
-
expect(user_from_association.name).to eq('User One')
|
181
|
-
else
|
182
|
-
# If it returns the regular TestUser (non-history), that's also acceptable
|
183
|
-
# as long as it doesn't error
|
184
|
-
expect(user_from_association).to be_a(TestUser)
|
185
|
-
expect(user_from_association.name).to eq('User One')
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|