historiographer 1.0.0
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 +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.standalone_migrations +6 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +196 -0
- data/Guardfile +70 -0
- data/LICENSE.txt +20 -0
- data/README.md +124 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/historiographer.gemspec +108 -0
- data/init.rb +18 -0
- data/lib/historiographer/history.rb +175 -0
- data/lib/historiographer/history_migration.rb +78 -0
- data/lib/historiographer/history_migration_mysql.rb +54 -0
- data/lib/historiographer/mysql_migration.rb +7 -0
- data/lib/historiographer/postgres_migration.rb +7 -0
- data/lib/historiographer/safe.rb +33 -0
- data/lib/historiographer.rb +235 -0
- data/spec/db/database.yml +27 -0
- data/spec/db/migrate/20161121212228_create_posts.rb +19 -0
- data/spec/db/migrate/20161121212229_create_post_histories.rb +10 -0
- data/spec/db/migrate/20161121212230_create_authors.rb +13 -0
- data/spec/db/migrate/20161121212231_create_author_histories.rb +10 -0
- data/spec/db/migrate/20161121212232_create_users.rb +9 -0
- data/spec/db/migrate/20171011194624_create_safe_posts.rb +19 -0
- data/spec/db/migrate/20171011194715_create_safe_post_histories.rb +9 -0
- data/spec/db/schema.rb +121 -0
- data/spec/examples.txt +21 -0
- data/spec/historiographer_spec.rb +395 -0
- data/spec/spec_helper.rb +40 -0
- metadata +258 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateSafePosts < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :safe_posts do |t|
|
4
|
+
t.string :title, null: false
|
5
|
+
t.text :body, null: false
|
6
|
+
t.integer :author_id, null: false
|
7
|
+
t.boolean :enabled, default: false
|
8
|
+
t.datetime :live_at
|
9
|
+
t.datetime :deleted_at
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index :safe_posts, :author_id
|
15
|
+
add_index :safe_posts, :enabled
|
16
|
+
add_index :safe_posts, :live_at
|
17
|
+
add_index :safe_posts, :deleted_at
|
18
|
+
end
|
19
|
+
end
|
data/spec/db/schema.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your
|
6
|
+
# database schema. If you need to create the application database on another
|
7
|
+
# system, you should be using db:schema:load, not running all the migrations
|
8
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
9
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
10
|
+
#
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define(version: 2017_10_11_194715) do
|
14
|
+
|
15
|
+
create_table "author_histories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
16
|
+
t.integer "author_id", null: false
|
17
|
+
t.string "full_name", null: false
|
18
|
+
t.text "bio"
|
19
|
+
t.datetime "deleted_at"
|
20
|
+
t.datetime "created_at", null: false
|
21
|
+
t.datetime "updated_at", null: false
|
22
|
+
t.datetime "history_started_at", null: false
|
23
|
+
t.datetime "history_ended_at"
|
24
|
+
t.integer "history_user_id"
|
25
|
+
t.index ["author_id"], name: "index_author_histories_on_author_id"
|
26
|
+
t.index ["deleted_at"], name: "index_author_histories_on_deleted_at"
|
27
|
+
t.index ["history_ended_at"], name: "index_author_histories_on_history_ended_at"
|
28
|
+
t.index ["history_started_at"], name: "index_author_histories_on_history_started_at"
|
29
|
+
t.index ["history_user_id"], name: "index_author_histories_on_history_user_id"
|
30
|
+
end
|
31
|
+
|
32
|
+
create_table "authors", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
33
|
+
t.string "full_name", null: false
|
34
|
+
t.text "bio"
|
35
|
+
t.datetime "deleted_at"
|
36
|
+
t.datetime "created_at", null: false
|
37
|
+
t.datetime "updated_at", null: false
|
38
|
+
t.index ["deleted_at"], name: "index_authors_on_deleted_at"
|
39
|
+
end
|
40
|
+
|
41
|
+
create_table "post_histories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
42
|
+
t.integer "post_id", null: false
|
43
|
+
t.string "title", null: false
|
44
|
+
t.text "body", null: false
|
45
|
+
t.integer "author_id", null: false
|
46
|
+
t.boolean "enabled", default: false
|
47
|
+
t.datetime "live_at"
|
48
|
+
t.datetime "deleted_at"
|
49
|
+
t.datetime "created_at", null: false
|
50
|
+
t.datetime "updated_at", null: false
|
51
|
+
t.datetime "history_started_at", null: false
|
52
|
+
t.datetime "history_ended_at"
|
53
|
+
t.integer "history_user_id"
|
54
|
+
t.index ["author_id"], name: "index_post_histories_on_author_id"
|
55
|
+
t.index ["deleted_at"], name: "index_post_histories_on_deleted_at"
|
56
|
+
t.index ["enabled"], name: "index_post_histories_on_enabled"
|
57
|
+
t.index ["history_ended_at"], name: "index_post_histories_on_history_ended_at"
|
58
|
+
t.index ["history_started_at"], name: "index_post_histories_on_history_started_at"
|
59
|
+
t.index ["history_user_id"], name: "index_post_histories_on_history_user_id"
|
60
|
+
t.index ["live_at"], name: "index_post_histories_on_live_at"
|
61
|
+
t.index ["post_id"], name: "index_post_histories_on_post_id"
|
62
|
+
end
|
63
|
+
|
64
|
+
create_table "posts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
65
|
+
t.string "title", null: false
|
66
|
+
t.text "body", null: false
|
67
|
+
t.integer "author_id", null: false
|
68
|
+
t.boolean "enabled", default: false
|
69
|
+
t.datetime "live_at"
|
70
|
+
t.datetime "deleted_at"
|
71
|
+
t.datetime "created_at", null: false
|
72
|
+
t.datetime "updated_at", null: false
|
73
|
+
t.index ["author_id"], name: "index_posts_on_author_id"
|
74
|
+
t.index ["deleted_at"], name: "index_posts_on_deleted_at"
|
75
|
+
t.index ["enabled"], name: "index_posts_on_enabled"
|
76
|
+
t.index ["live_at"], name: "index_posts_on_live_at"
|
77
|
+
end
|
78
|
+
|
79
|
+
create_table "safe_post_histories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
80
|
+
t.integer "safe_post_id", null: false
|
81
|
+
t.string "title", null: false
|
82
|
+
t.text "body", null: false
|
83
|
+
t.integer "author_id", null: false
|
84
|
+
t.boolean "enabled", default: false
|
85
|
+
t.datetime "live_at"
|
86
|
+
t.datetime "deleted_at"
|
87
|
+
t.datetime "created_at", null: false
|
88
|
+
t.datetime "updated_at", null: false
|
89
|
+
t.datetime "history_started_at", null: false
|
90
|
+
t.datetime "history_ended_at"
|
91
|
+
t.integer "history_user_id"
|
92
|
+
t.index ["author_id"], name: "index_safe_post_histories_on_author_id"
|
93
|
+
t.index ["deleted_at"], name: "index_safe_post_histories_on_deleted_at"
|
94
|
+
t.index ["enabled"], name: "index_safe_post_histories_on_enabled"
|
95
|
+
t.index ["history_ended_at"], name: "index_safe_post_histories_on_history_ended_at"
|
96
|
+
t.index ["history_started_at"], name: "index_safe_post_histories_on_history_started_at"
|
97
|
+
t.index ["history_user_id"], name: "index_safe_post_histories_on_history_user_id"
|
98
|
+
t.index ["live_at"], name: "index_safe_post_histories_on_live_at"
|
99
|
+
t.index ["safe_post_id"], name: "index_safe_post_histories_on_safe_post_id"
|
100
|
+
end
|
101
|
+
|
102
|
+
create_table "safe_posts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
103
|
+
t.string "title", null: false
|
104
|
+
t.text "body", null: false
|
105
|
+
t.integer "author_id", null: false
|
106
|
+
t.boolean "enabled", default: false
|
107
|
+
t.datetime "live_at"
|
108
|
+
t.datetime "deleted_at"
|
109
|
+
t.datetime "created_at", null: false
|
110
|
+
t.datetime "updated_at", null: false
|
111
|
+
t.index ["author_id"], name: "index_safe_posts_on_author_id"
|
112
|
+
t.index ["deleted_at"], name: "index_safe_posts_on_deleted_at"
|
113
|
+
t.index ["enabled"], name: "index_safe_posts_on_enabled"
|
114
|
+
t.index ["live_at"], name: "index_safe_posts_on_live_at"
|
115
|
+
end
|
116
|
+
|
117
|
+
create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
118
|
+
t.string "name"
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
data/spec/examples.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
example_id | status | run_time |
|
2
|
+
--------------------------------------- | ------ | --------------- |
|
3
|
+
./spec/historiographer_spec.rb[1:1:1] | passed | 0.00794 seconds |
|
4
|
+
./spec/historiographer_spec.rb[1:1:2] | passed | 0.04572 seconds |
|
5
|
+
./spec/historiographer_spec.rb[1:1:3] | passed | 0.03308 seconds |
|
6
|
+
./spec/historiographer_spec.rb[1:2:1] | passed | 0.0742 seconds |
|
7
|
+
./spec/historiographer_spec.rb[1:2:2] | passed | 0.00138 seconds |
|
8
|
+
./spec/historiographer_spec.rb[1:2:3:1] | passed | 0.01369 seconds |
|
9
|
+
./spec/historiographer_spec.rb[1:2:3:2] | passed | 0.059 seconds |
|
10
|
+
./spec/historiographer_spec.rb[1:2:3:3] | passed | 0.00794 seconds |
|
11
|
+
./spec/historiographer_spec.rb[1:2:4] | passed | 0.00348 seconds |
|
12
|
+
./spec/historiographer_spec.rb[1:2:5] | passed | 0.03144 seconds |
|
13
|
+
./spec/historiographer_spec.rb[1:2:6] | passed | 0.01239 seconds |
|
14
|
+
./spec/historiographer_spec.rb[1:3:1] | passed | 0.04853 seconds |
|
15
|
+
./spec/historiographer_spec.rb[1:4:1] | passed | 0.03917 seconds |
|
16
|
+
./spec/historiographer_spec.rb[1:5:1] | passed | 0.03402 seconds |
|
17
|
+
./spec/historiographer_spec.rb[1:5:2] | passed | 0.02494 seconds |
|
18
|
+
./spec/historiographer_spec.rb[1:6:1] | passed | 0.0287 seconds |
|
19
|
+
./spec/historiographer_spec.rb[1:7:1] | passed | 0.07329 seconds |
|
20
|
+
./spec/historiographer_spec.rb[1:7:2] | passed | 0.01293 seconds |
|
21
|
+
./spec/historiographer_spec.rb[1:8:1] | passed | 0.08211 seconds |
|
@@ -0,0 +1,395 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class Post < ActiveRecord::Base
|
4
|
+
include Historiographer
|
5
|
+
end
|
6
|
+
|
7
|
+
class PostHistory < ActiveRecord::Base
|
8
|
+
end
|
9
|
+
|
10
|
+
class SafePost < ActiveRecord::Base
|
11
|
+
include Historiographer::Safe
|
12
|
+
end
|
13
|
+
|
14
|
+
class SafePostHistory < ActiveRecord::Base
|
15
|
+
end
|
16
|
+
|
17
|
+
class Author < ActiveRecord::Base
|
18
|
+
include Historiographer
|
19
|
+
end
|
20
|
+
|
21
|
+
class AuthorHistory < ActiveRecord::Base
|
22
|
+
end
|
23
|
+
|
24
|
+
class User < ActiveRecord::Base
|
25
|
+
end
|
26
|
+
|
27
|
+
describe Historiographer do
|
28
|
+
before(:all) do
|
29
|
+
@now = Timecop.freeze
|
30
|
+
end
|
31
|
+
|
32
|
+
after(:all) do
|
33
|
+
Timecop.return
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:username) { "Test User" }
|
37
|
+
|
38
|
+
let(:user) do
|
39
|
+
User.create(name: username)
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:create_post) do
|
43
|
+
Post.create(
|
44
|
+
title: "Post 1",
|
45
|
+
body: "Great post",
|
46
|
+
author_id: 1,
|
47
|
+
history_user_id: user.id
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:create_author) do
|
52
|
+
Author.create(
|
53
|
+
full_name: "Breezy",
|
54
|
+
history_user_id: user.id
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "History counting" do
|
59
|
+
it "creates history on creation of primary model record" do
|
60
|
+
expect {
|
61
|
+
create_post
|
62
|
+
}.to change {
|
63
|
+
PostHistory.count
|
64
|
+
}.by 1
|
65
|
+
end
|
66
|
+
|
67
|
+
it "appends new history on update" do
|
68
|
+
post = create_post
|
69
|
+
|
70
|
+
expect {
|
71
|
+
post.update(title: "Better Title")
|
72
|
+
}.to change {
|
73
|
+
PostHistory.count
|
74
|
+
}.by 1
|
75
|
+
end
|
76
|
+
|
77
|
+
it "does not append new history if nothing has changed" do
|
78
|
+
post = create_post
|
79
|
+
|
80
|
+
expect {
|
81
|
+
post.update(title: post.title)
|
82
|
+
}.to_not change {
|
83
|
+
PostHistory.count
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "History recording" do
|
89
|
+
it "records all fields from the parent" do
|
90
|
+
post = create_post
|
91
|
+
post_history = post.histories.first
|
92
|
+
|
93
|
+
expect(post_history.title).to eq post.title
|
94
|
+
expect(post_history.body).to eq post.body
|
95
|
+
expect(post_history.author_id).to eq post.author_id
|
96
|
+
expect(post_history.post_id).to eq post.id
|
97
|
+
expect(post_history.history_started_at.to_s).to eq @now.in_time_zone(Historiographer::UTC).to_s
|
98
|
+
expect(post_history.history_ended_at).to be_nil
|
99
|
+
expect(post_history.history_user_id).to eq user.id
|
100
|
+
|
101
|
+
post.update(title: "Better title")
|
102
|
+
post_histories = post.histories.reload.order("id asc")
|
103
|
+
first_history = post_histories.first
|
104
|
+
second_history = post_histories.second
|
105
|
+
|
106
|
+
expect(first_history.history_ended_at.to_s).to eq @now.in_time_zone(Historiographer::UTC).to_s
|
107
|
+
expect(second_history.history_ended_at).to be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "cannot create without history_user_id" do
|
111
|
+
post = Post.create(
|
112
|
+
title: "Post 1",
|
113
|
+
body: "Great post",
|
114
|
+
author_id: 1,
|
115
|
+
)
|
116
|
+
expect(post.errors.to_h).to eq({ :history_user_id => "must be an integer" })
|
117
|
+
|
118
|
+
expect {
|
119
|
+
post.send(:record_history)
|
120
|
+
}.to raise_error(
|
121
|
+
Historiographer::HistoryUserIdMissingError
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
context "When Safe mode" do
|
126
|
+
it "creates history without history_user_id" do
|
127
|
+
expect(Rollbar).to receive(:error).with("history_user_id must be passed in order to save record with histories! If you are in a context with no history_user_id, explicitly call #save_without_history")
|
128
|
+
|
129
|
+
post = SafePost.create(
|
130
|
+
title: "Post 1",
|
131
|
+
body: "Great post",
|
132
|
+
author_id: 1,
|
133
|
+
)
|
134
|
+
expect(post.errors.to_h.keys).to be_empty
|
135
|
+
expect(post).to be_persisted
|
136
|
+
expect(post.histories.count).to eq 1
|
137
|
+
expect(post.histories.first.history_user_id).to be_nil
|
138
|
+
end
|
139
|
+
|
140
|
+
it "creates history with history_user_id" do
|
141
|
+
expect(Rollbar).to_not receive(:error)
|
142
|
+
|
143
|
+
post = SafePost.create(
|
144
|
+
title: "Post 1",
|
145
|
+
body: "Great post",
|
146
|
+
author_id: 1,
|
147
|
+
history_user_id: user.id
|
148
|
+
)
|
149
|
+
expect(post.errors.to_h.keys).to be_empty
|
150
|
+
expect(post).to be_persisted
|
151
|
+
expect(post.histories.count).to eq 1
|
152
|
+
expect(post.histories.first.history_user_id).to eq user.id
|
153
|
+
end
|
154
|
+
|
155
|
+
it "skips history creation if desired" do
|
156
|
+
post = SafePost.new(
|
157
|
+
title: "Post 1",
|
158
|
+
body: "Great post",
|
159
|
+
author_id: 1
|
160
|
+
)
|
161
|
+
|
162
|
+
post.save_without_history
|
163
|
+
expect(post).to be_persisted
|
164
|
+
expect(post.histories.count).to eq 0
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "can override without history_user_id" do
|
169
|
+
expect {
|
170
|
+
post = Post.new(
|
171
|
+
title: "Post 1",
|
172
|
+
body: "Great post",
|
173
|
+
author_id: 1,
|
174
|
+
)
|
175
|
+
|
176
|
+
post.save_without_history
|
177
|
+
}.to_not raise_error
|
178
|
+
end
|
179
|
+
|
180
|
+
it "can override without history_user_id" do
|
181
|
+
expect {
|
182
|
+
post = Post.new(
|
183
|
+
title: "Post 1",
|
184
|
+
body: "Great post",
|
185
|
+
author_id: 1,
|
186
|
+
)
|
187
|
+
|
188
|
+
post.save_without_history!
|
189
|
+
}.to_not raise_error
|
190
|
+
end
|
191
|
+
|
192
|
+
it "does not record histories when main model fails to save" do
|
193
|
+
class Post
|
194
|
+
after_save :raise_error, prepend: true
|
195
|
+
|
196
|
+
def raise_error
|
197
|
+
raise "Oh no, db issue!"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
expect { create_post }.to raise_error
|
202
|
+
expect(Post.count).to be 0
|
203
|
+
expect(PostHistory.count).to be 0
|
204
|
+
|
205
|
+
Post.skip_callback(:save, :after, :raise_error)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "Scopes" do
|
210
|
+
it "finds current histories" do
|
211
|
+
post1 = create_post
|
212
|
+
post1.update(title: "Better title")
|
213
|
+
|
214
|
+
post2 = create_post
|
215
|
+
post2.update(title: "Better title")
|
216
|
+
|
217
|
+
expect(PostHistory.current.pluck(:title)).to all eq "Better title"
|
218
|
+
expect(post1.current_history.title).to eq "Better title"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "Associations" do
|
223
|
+
it "names associated records" do
|
224
|
+
post1 = create_post
|
225
|
+
expect(post1.histories.first).to be_a(PostHistory)
|
226
|
+
|
227
|
+
expect(post1.histories.first.post).to be(post1)
|
228
|
+
|
229
|
+
author1 = create_author
|
230
|
+
expect(author1.histories.first).to be_a(AuthorHistory)
|
231
|
+
|
232
|
+
expect(author1.histories.first.author).to be(author1)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "Histories" do
|
237
|
+
it "does not allow direct updates of histories" do
|
238
|
+
post1 = create_post
|
239
|
+
hist1 = post1.histories.first
|
240
|
+
|
241
|
+
expect(hist1.update(title: "A different title")).to be false
|
242
|
+
expect(hist1.reload.title).to eq post1.title
|
243
|
+
|
244
|
+
expect(hist1.update!(title: "A different title")).to be false
|
245
|
+
expect(hist1.reload.title).to eq post1.title
|
246
|
+
|
247
|
+
hist1.title = "A different title"
|
248
|
+
expect(hist1.save).to be false
|
249
|
+
expect(hist1.reload.title).to eq post1.title
|
250
|
+
|
251
|
+
hist1.title = "A different title"
|
252
|
+
expect(hist1.save!).to be false
|
253
|
+
expect(hist1.reload.title).to eq post1.title
|
254
|
+
end
|
255
|
+
|
256
|
+
it "does not allow destroys of histories" do
|
257
|
+
post1 = create_post
|
258
|
+
hist1 = post1.histories.first
|
259
|
+
original_history_count = post1.histories.count
|
260
|
+
|
261
|
+
expect(hist1.destroy).to be false
|
262
|
+
expect(hist1.destroy!).to be false
|
263
|
+
|
264
|
+
expect(post1.histories.count).to be original_history_count
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "Deletion" do
|
269
|
+
it "records deleted_at on primary and history if you use acts_as_paranoid" do
|
270
|
+
class Post
|
271
|
+
acts_as_paranoid
|
272
|
+
end
|
273
|
+
|
274
|
+
post = create_post
|
275
|
+
|
276
|
+
expect {
|
277
|
+
post.destroy
|
278
|
+
}.to change {
|
279
|
+
PostHistory.count
|
280
|
+
}.by 1
|
281
|
+
|
282
|
+
expect(Post.unscoped.where.not(deleted_at: nil).count).to eq 1
|
283
|
+
expect(Post.unscoped.where(deleted_at: nil).count).to eq 0
|
284
|
+
expect(PostHistory.where.not(deleted_at: nil).count).to eq 1
|
285
|
+
expect(PostHistory.where(deleted_at: nil).count).to eq 1
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
describe "Scopes" do
|
290
|
+
it "finds current" do
|
291
|
+
post = create_post
|
292
|
+
post.update(title: "New Title")
|
293
|
+
post.update(title: "New Title 2")
|
294
|
+
|
295
|
+
expect(PostHistory.current.count).to be 1
|
296
|
+
end
|
297
|
+
|
298
|
+
it "finds current even when the db is updated in an invalid way" do
|
299
|
+
postgresql = <<-SQL
|
300
|
+
INSERT INTO post_histories (
|
301
|
+
title,
|
302
|
+
body,
|
303
|
+
post_id,
|
304
|
+
author_id,
|
305
|
+
history_started_at,
|
306
|
+
history_ended_at
|
307
|
+
) VALUES (
|
308
|
+
'Post 1',
|
309
|
+
'Text',
|
310
|
+
1,
|
311
|
+
1,
|
312
|
+
now() - INTERVAL '1 day',
|
313
|
+
NULL
|
314
|
+
), (
|
315
|
+
'Post 1',
|
316
|
+
'Different text',
|
317
|
+
1,
|
318
|
+
1,
|
319
|
+
now() - INTERVAL '12 hours',
|
320
|
+
NULL
|
321
|
+
), (
|
322
|
+
'Post 1',
|
323
|
+
'Even more different text',
|
324
|
+
1,
|
325
|
+
1,
|
326
|
+
now() - INTERVAL '12 hours',
|
327
|
+
NULL
|
328
|
+
)
|
329
|
+
SQL
|
330
|
+
|
331
|
+
mysql = <<-SQL
|
332
|
+
INSERT INTO post_histories (
|
333
|
+
title,
|
334
|
+
body,
|
335
|
+
post_id,
|
336
|
+
author_id,
|
337
|
+
created_at,
|
338
|
+
updated_at,
|
339
|
+
history_started_at,
|
340
|
+
history_ended_at
|
341
|
+
) VALUES (
|
342
|
+
'Post 1',
|
343
|
+
'Text',
|
344
|
+
1,
|
345
|
+
1,
|
346
|
+
now(),
|
347
|
+
now(),
|
348
|
+
now() - INTERVAL 1 day,
|
349
|
+
NULL
|
350
|
+
), (
|
351
|
+
'Post 1',
|
352
|
+
'Different text',
|
353
|
+
1,
|
354
|
+
1,
|
355
|
+
now(),
|
356
|
+
now(),
|
357
|
+
now() - INTERVAL 12 hour,
|
358
|
+
NULL
|
359
|
+
), (
|
360
|
+
'Post 1',
|
361
|
+
'Even more different text',
|
362
|
+
1,
|
363
|
+
1,
|
364
|
+
now(),
|
365
|
+
now(),
|
366
|
+
now() - INTERVAL 12 hour,
|
367
|
+
NULL
|
368
|
+
)
|
369
|
+
SQL
|
370
|
+
|
371
|
+
sql = nil
|
372
|
+
case PostHistory.connection.instance_variable_get(:@config)[:adapter]
|
373
|
+
when "mysql2"
|
374
|
+
sql = mysql
|
375
|
+
when "postgresql"
|
376
|
+
sql = postgresql
|
377
|
+
end
|
378
|
+
|
379
|
+
PostHistory.connection.execute(sql)
|
380
|
+
|
381
|
+
expect(PostHistory.current.count).to be 1
|
382
|
+
expect(PostHistory.current.first.body).to eq "Even more different text"
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
describe "User associations" do
|
387
|
+
it "links to user" do
|
388
|
+
post = create_post
|
389
|
+
author = create_author
|
390
|
+
|
391
|
+
expect(post.current_history.user.name).to eq username
|
392
|
+
expect(author.current_history.user.name).to eq username
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
ENV["HISTORIOGRAPHY_ENV"] = "test"
|
2
|
+
|
3
|
+
require_relative "../init.rb"
|
4
|
+
require "ostruct"
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.expect_with :rspec do |expectations|
|
8
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
9
|
+
end
|
10
|
+
|
11
|
+
config.mock_with :rspec do |mocks|
|
12
|
+
mocks.verify_partial_doubles = true
|
13
|
+
end
|
14
|
+
|
15
|
+
config.filter_run :focus
|
16
|
+
config.run_all_when_everything_filtered = true
|
17
|
+
|
18
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
19
|
+
|
20
|
+
if config.files_to_run.one?
|
21
|
+
config.default_formatter = 'doc'
|
22
|
+
end
|
23
|
+
|
24
|
+
config.profile_examples = 10
|
25
|
+
|
26
|
+
config.order = :random
|
27
|
+
|
28
|
+
Kernel.srand config.seed
|
29
|
+
|
30
|
+
config.before(:suite) do
|
31
|
+
DatabaseCleaner.strategy = :transaction
|
32
|
+
DatabaseCleaner.clean_with(:truncation)
|
33
|
+
end
|
34
|
+
|
35
|
+
config.around(:each) do |example|
|
36
|
+
DatabaseCleaner.cleaning do
|
37
|
+
example.run
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|