Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,17 @@ th {
gap: 0.3em;
}

.field-error {
color: #dc3545;
font-size: 12px;
margin-top: 4px;
font-weight: 500;
}

input.error, textarea.error {
width: 100%;
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}


11 changes: 5 additions & 6 deletions app/controllers/puzzles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@ def edit

def update
@puzzle = Puzzle.find(params[:id])
if @puzzle.update(puzzle_params)
respond_to do |format|

respond_to do |format|
if @puzzle.update(puzzle_params)
format.turbo_stream
format.html { redirect_to puzzles_path, notice: "Puzzle updated." }
format.json { render json: { success: true, puzzle: @puzzle } }
end
else
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.replace(@puzzle, partial: "puzzles/form", locals: { puzzle: @puzzle }) }
else
format.turbo_stream { render turbo_stream: turbo_stream.replace("modal", partial: "puzzles/edit_modal", locals: { puzzle: @puzzle }), status: :unprocessable_entity }
Copy link
Member Author

@JuanVqz JuanVqz Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the reason the errors didn't show up at Fiona's PR; the first element should be the turbo frame's name.

Also had to move the edit.html.erb view content into a partial _edit_modal.html.erb because this turbo stream needed it to render the errors

format.html { render :edit, status: :unprocessable_entity }
format.json { render json: { success: false, errors: @puzzle.errors.full_messages }, status: :unprocessable_entity }
end
Expand Down
2 changes: 2 additions & 0 deletions app/models/puzzle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ class Puzzle < ApplicationRecord
enum :state, { approved: 0, rejected: 1, pending: 2, archived: 3 }
has_many :answers

validates :question, presence: true

scope :archived, -> { where(state: :archived).order(sent_at: :desc) }
end
11 changes: 11 additions & 0 deletions app/views/puzzles/_edit_modal.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<turbo-frame id="modal">
<div data-controller="modal" data-action="modal#close" class="modal-overlay">
<div data-modal-target="content" class="modal-content" onclick="event.stopPropagation()">
<h2 class="text-xl mb-4">Edit Puzzle</h2>

<%= render "form", puzzle: puzzle %>

<button data-action="modal#close" class="btn close-btn">Close</button>
</div>
</div>
</turbo-frame>
7 changes: 5 additions & 2 deletions app/views/puzzles/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<%=form_with model: @puzzle do |f| %>
<%= form_with model: puzzle do |f| %>
<div class="modal-area">
<%= f.label :question %>
<%= f.text_area :question %>
<%= f.text_area :question, class: puzzle.errors[:question].any? ? "error" : "" %>
<% if puzzle.errors[:question].any? %>
<div class="field-error"><%= puzzle.errors[:question].first %></div>
<% end %>
</div>

<div class="modal-area">
Expand Down
15 changes: 1 addition & 14 deletions app/views/puzzles/edit.html.erb
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
<turbo-frame id="modal">
<div data-controller="modal" data-action="click->modal#close"class="modal-overlay">
<div data-modal-target="content"
class="modal-content"
onclick="event.stopPropagation()">
<h2 class="text-xl mb-4">Edit Puzzle</h2>

<%= render "form", puzzle: @puzzle %>

<button data-action="modal#close"
class="btn close-btn">Close</button>
</div>
</div>
</turbo-frame>
<%= render "edit_modal", puzzle: @puzzle %>
37 changes: 37 additions & 0 deletions test/controllers/puzzles_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,41 @@ class PuzzlesControllerTest < ActionDispatch::IntegrationTest
get puzzles_path
assert_response :success
end

test "should show error message when editing puzzle with invalid data" do
puzzle = puzzles(:one)

patch puzzle_path(puzzle), params: {
puzzle: {
question: "",
answer: "rails",
explanation: "Updated explanation",
link: "https://example.com"
}
}, as: :turbo_stream

assert_response :unprocessable_entity

assert_select "div.field-error", "can't be blank"
assert_select "textarea.error"
end

test "should successfully update puzzle with valid data" do
puzzle = puzzles(:one)

patch puzzle_path(puzzle), params: {
puzzle: {
question: "Updated question",
answer: "rails",
explanation: "Updated explanation",
link: "https://example.com"
}
}, as: :turbo_stream

assert_response :success

puzzle.reload
assert_equal "Updated question", puzzle.question
assert_equal "Updated explanation", puzzle.explanation
end
end
17 changes: 17 additions & 0 deletions test/fixtures/puzzles.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
one:
question: "Ruby or Rails provided this method? render json: @user"
answer: "rails"
explanation: "This is a test puzzle"
link: "https://example.com"
state: "approved"
sent_at: <%= 1.day.ago %>
suggested_by: "test_user"

two:
question: "Ruby or Rails provided this method? puts 'Hello, World!'"
answer: "ruby"
explanation: "This is a test puzzle 2"
link: ""
state: "pending"
sent_at: <%= 2.days.ago %>
suggested_by: "test_user"
52 changes: 52 additions & 0 deletions test/models/puzzle_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require "test_helper"

class PuzzleTest < ActiveSupport::TestCase
test "validates presence of question" do
puzzle = Puzzle.new(
question: "What is the capital of France?",
answer: "rails",
explanation: "This is a test puzzle",
link: "https://example.com",
state: "approved",
suggested_by: "test_user"
)
assert puzzle.valid?
end

test "validates question presence - fails without question" do
puzzle = Puzzle.new(
answer: "rails",
explanation: "This is a test puzzle",
link: "https://example.com",
state: "approved",
suggested_by: "test_user"
)
assert_not puzzle.valid?
assert_includes puzzle.errors[:question], "can't be blank"
end

test "defines answer enum with correct values" do
assert_equal 0, Puzzle.answers[:ruby]
assert_equal 1, Puzzle.answers[:rails]
end

test "defines state enum with correct values" do
assert_equal 0, Puzzle.states[:approved]
assert_equal 1, Puzzle.states[:rejected]
assert_equal 2, Puzzle.states[:pending]
assert_equal 3, Puzzle.states[:archived]
end

test "defaults state to pending" do
puzzle = Puzzle.new(
question: "Test question",
answer: "ruby",
explanation: "Test explanation"
)
assert_equal "pending", puzzle.state
end

test "has many answers" do
assert_respond_to Puzzle.new, :answers
end
end