Skip to content

Commit ea64586

Browse files
authored
Merge pull request #77 from fastruby/feature/seed-archived-puzzles
[IIRR-39] Add archived puzzle seeds for low success rate filter testing
2 parents 674161a + 8b4a570 commit ea64586

2 files changed

Lines changed: 112 additions & 12 deletions

File tree

db/seeds.rb

Lines changed: 110 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# db/seeds.rb
22

33
# ====== Create Puzzle records ======
4+
# Archived entries carry `sent_at` and a fixed `success_rate` (% of 10 users
5+
# who answer correctly). Rates <= 80 appear in the "low success rate" filter;
6+
# rates > 80 do not. Entries without `state` default to :pending.
47
puzzles = [
58
{
69
question: "Ruby or Rails provided this method? Array.new(5) { |i| i * 2 }",
@@ -26,16 +29,104 @@
2629
question: "Ruby or Rails provided this method? params[:id]",
2730
answer: :rails,
2831
explanation: "`params[:id]` is used in Rails to fetch query parameters or URL parameters in controller actions."
32+
},
33+
{
34+
question: "Ruby or Rails provided this method? before_action :authenticate_user!",
35+
answer: :rails,
36+
explanation: "`before_action` is a Rails callback defined in `ActionController::Callbacks`. It runs specified methods before controller actions.",
37+
state: :archived,
38+
sent_at: 7.days.ago,
39+
success_rate: 20
40+
},
41+
{
42+
question: "Ruby or Rails provided this method? 42.times { puts 'hello' }",
43+
answer: :ruby,
44+
explanation: "`Integer#times` is a core Ruby method that iterates a block a specified number of times.",
45+
state: :archived,
46+
sent_at: 6.days.ago,
47+
success_rate: 40
48+
},
49+
{
50+
question: "Ruby or Rails provided this method? User.where(active: true).order(:name)",
51+
answer: :rails,
52+
explanation: "`where` and `order` are ActiveRecord query methods provided by Rails to build SQL queries.",
53+
state: :archived,
54+
sent_at: 5.days.ago,
55+
success_rate: 50
56+
},
57+
{
58+
question: "Ruby or Rails provided this method? 'hello world'.split(' ')",
59+
answer: :ruby,
60+
explanation: "`String#split` is a core Ruby method that divides a string into an array based on a delimiter.",
61+
state: :archived,
62+
sent_at: 4.days.ago,
63+
success_rate: 70
64+
},
65+
{
66+
question: "Ruby or Rails provided this method? flash[:notice] = 'Saved!'",
67+
answer: :rails,
68+
explanation: "`flash` is a Rails feature provided by `ActionDispatch::Flash` for passing messages between requests.",
69+
state: :archived,
70+
sent_at: 3.days.ago,
71+
success_rate: 80
72+
},
73+
{
74+
question: "Ruby or Rails provided this method? [1, 2, 3].reduce(:+)",
75+
answer: :ruby,
76+
explanation: "`Enumerable#reduce` (also `inject`) is a core Ruby method that combines elements using a binary operation.",
77+
state: :archived,
78+
sent_at: 2.days.ago,
79+
success_rate: 90
80+
},
81+
{
82+
question: "Ruby or Rails provided this method? validates :email, presence: true, uniqueness: true",
83+
answer: :rails,
84+
explanation: "`validates` is an ActiveModel/ActiveRecord method from Rails that adds validation rules to models.",
85+
state: :archived,
86+
sent_at: 1.day.ago,
87+
success_rate: 100
2988
}
3089
]
3190

91+
success_rate_by_question = puzzles.each_with_object({}) do |p, h|
92+
h[p[:question]] = p[:success_rate] if p[:success_rate]
93+
end
94+
3295
puzzles.each do |p|
3396
Puzzle.find_or_create_by!(question: p[:question]) do |puzzle|
3497
puzzle.answer = p[:answer]
3598
puzzle.explanation = p[:explanation]
99+
puzzle.state = p[:state] if p[:state]
100+
puzzle.sent_at = p[:sent_at]
36101
end
37102
end
38103

104+
# ====== Clone a few archived puzzles so the "hide cloned" filter has data ======
105+
# Mix of pending and archived clones to exercise both states.
106+
cloned_sources = [
107+
{ question: "Ruby or Rails provided this method? before_action :authenticate_user!", state: :pending },
108+
{ question: "Ruby or Rails provided this method? User.where(active: true).order(:name)", state: :pending },
109+
{ question: "Ruby or Rails provided this method? 42.times { puts 'hello' }", state: :archived, sent_at: 12.hours.ago },
110+
{ question: "Ruby or Rails provided this method? flash[:notice] = 'Saved!'", state: :archived, sent_at: 6.hours.ago }
111+
]
112+
113+
cloned_sources.each do |source|
114+
parent = Puzzle.find_by(question: source[:question])
115+
next unless parent
116+
next if Puzzle.where(original_puzzle_id: parent.id).exists?
117+
118+
Puzzle.create!(
119+
question: "#{parent.question} (clone)",
120+
answer: parent.answer,
121+
explanation: parent.explanation,
122+
link: parent.link,
123+
suggested_by: parent.suggested_by,
124+
state: source[:state],
125+
sent_at: source[:sent_at],
126+
original_puzzle: parent
127+
)
128+
end
129+
39130
# ====== Create the Server ======
40131
server = Server.find_or_create_by!(server_id: 1179555097060061245) do |s|
41132
s.name = "OmbuTest"
@@ -63,19 +154,26 @@
63154

64155
# Associate user with the server if not already linked
65156
user.servers << server unless user.servers.include?(server)
157+
end
158+
159+
# ====== Seed answers for archived puzzles ======
160+
# Real users only answer puzzles after they've been sent (archived state).
161+
# For each archived puzzle, mark the first `success_rate / 10` users correct
162+
# and the rest incorrect, so each puzzle hits its target rate exactly.
163+
server_users = server.users.order(:id)
164+
165+
Puzzle.archived.each do |puzzle|
166+
base_question = puzzle.original_puzzle&.question || puzzle.question
167+
correct_count = success_rate_by_question.fetch(base_question, 50) / 10
66168

67-
# Seed random answers for this user if they have none
68-
if user.answers.where(server_id: server.id).empty?
69-
3.times do
70-
puzzle = Puzzle.all.sample
71-
Answer.find_or_create_by!(
72-
user_id: user.id,
73-
puzzle_id: puzzle.id,
74-
server_id: server.id
75-
) do |answer|
76-
answer.choice = [ "ruby", "rails" ].sample
77-
answer.is_correct = [ true, false ].sample
78-
end
169+
server_users.each_with_index do |user, idx|
170+
Answer.find_or_create_by!(
171+
user_id: user.id,
172+
puzzle_id: puzzle.id,
173+
server_id: server.id
174+
) do |answer|
175+
answer.choice = [ "ruby", "rails" ].sample
176+
answer.is_correct = idx < correct_count
79177
end
80178
end
81179
end

test/jobs/daily_puzzle_job_test.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class DailyPuzzleJobTest < ActiveJob::TestCase
4141
end
4242

4343
test "marks the selected puzzle as archived and sets sent_at" do
44+
Puzzle.approved.where(sent_at: nil).delete_all
45+
4446
puzzle = Puzzle.create!(
4547
question: "Approved unsent puzzle question",
4648
answer: "ruby",

0 commit comments

Comments
 (0)