Building Mortimer, day 2
This is rapidly turning into a series of posts on building Mortimer (see what happens the day after) – learn about the beginning up until this moment, and Vol 4 reboot, day 1.
Day 2
I was cheating – day 1 was not nearly finished and I felt having at least one more thing ...
Punches
Being anxious getting to the core of it all – the punching in and out. So what better way to finish a rather long and bumpy day than solving yet another use case
as a user I will punch in and out
Not the greatest use case of the century but anyways:
rails g scaffold Punch user:references...
Immediately I made an important change to the punches#create
method:
# POST /punches or /punches.json
def create
@punch = Punch.new(punch_params)
@punch.user = current_user
@punch.punched_at = DateTime.now
...
No punch should ever be "punched" by anybody else – at least that's what I know "right now" 😉
TDD'ing from there presented me with day 1's last bump:
Not sure why this error is raised but the remedy is surmountable:
def destroy
@punch.destroy!
respond_to do |format|
format.html {
redirect_to punches_url,
allow_other_host: true,
notice: "Punch was successfully destroyed."
}
format.json { head :no_content }
end
end
(and likewise for #create and #update)
Teams
-- meanwhile far away in a distant galaxy...duuut, duuut!! I almost jumped out of bed, full of excitement for what this day will bring.
rails g scaffold Team name, email
With that out of the way I could focus on the next use case being
as a user I will be assigned to a team
Needless to say that not all businesses will operate with the notion of teams – some may just consider the company, the team! In those situations what are we to do? I went with the null: true
meaning that I will not have SQLite raise hell if I do not provide a team for a new user. Here is a little post about this 'not null' thing.
rails g migration add_team_id_to_user team:references
Make the user belong_to a team with
class User < ApplicationRecord
belongs_to :team, optional: true
end
and make sure the team knows about the users
class Team < ApplicationRecord
has_many :users, dependent: :destroy
end
Having 'said' that I instantly realized that there was foul play somewhere in here! Deleting a team would rip us of all signed up users assigned to this team! Making a mental note about that would not cut it – I had to, ferociously, attack this use case while still fresh off the bat!
Deleting record(s)
Coming from vol 1-3 I knew how to handle this one! Add a modal_control, start hacking and by no time I'd be right back in the code soup that I knew so well!
But using the 'system prompt' felt somewhat cheap - but that would be a task for some other time to do pricey stuff I decided, the sentiment being that I had taken no theme, no CSS framework into consideration thus any worries about a sordid modal versus system prompt were idle.
Making sure that the delete button would only be available if a team had no assigned users felt like the right way to go! So the use case was
as a user I will only be able to delete teams with no assigned users
Now the job was manageable!
My tests came out like this
require "test_helper"
class TeamsControllerTest < ActionDispatch::IntegrationTest
...
test "should destroy team with no attached users" do
assert_difference("Team.count", -1) do
delete team_url(@team)
end
assert_redirected_to teams_url
end
test "should not destroy team with attached users" do
assert_difference("Team.count", 0) do
@team2 = teams(:two)
delete team_url(@team2)
end
assert_redirected_to teams_url
end
end
Making them red was fixed in the users.yml
with
one:
...
team: two
two:
...
team:
Making them green was just about as easy
class TeamsController < ApplicationController
before_action :authenticate_user!
...
# DELETE /teams/1 or /teams/1.json
def destroy
options = { allow_other_host: true }
result = @team.destroy! if @team.users.empty?
if result
options[:notice] = "Team was successfully destroyed."
else
options[:alert] = "Team has users attached and cannot be destroyed."
end
respond_to do |format|
format.html { redirect_to teams_url, options }
format.json { head :no_content }
end
end
...
end
and with that, I reckoned teams to be done with – for the time being at least 😉
Wait! What about the system test? Yeah - right - okay! But it's not pretty. I hit one more bump! Setting up a system test for teams was practically done for me.
require "application_system_test_case"
class TeamsTest < ApplicationSystemTestCase
setup do
sign_in users(:one)
@team = teams(:one)
end
test "visiting the index" do
visit teams_url
assert_selector "h1", text: "Teams"
end
test "should create team" do
visit teams_url
click_on "New team"
fill_in "Email", with: @team.email
fill_in "Name", with: @team.name
click_on "Create Team"
assert_text "Team was successfully created"
click_on "Back"
end
test "should update Team" do
visit team_url(@team)
click_on "Edit this team", match: :first
fill_in "Email", with: @team.email
fill_in "Name", with: @team.name
click_on "Update Team"
assert_text "Team was successfully updated"
click_on "Back"
end
test "should destroy Team" do
visit team_url(@team)
click_on "Destroy this team", match: :first
assert_text "Team was successfully destroyed"
end
end
But creating a team yelled
at me the very second I hit [Enter] on rails test:system
- and my reaction was WTF? 😧
Out of the box Rails comes with Selenium enabled as the 'driver' for a "headless" browser. Apparently browser testing in Rails has come a long way since Selinium had its hay-days. Here is a post on changing that to Cuprite and here is another on focused with Minitest (the Rails standard test framework).
None of them, however, dives straight into the reason why Capybara somehow "forgets" about the logged_in_user; 🤔
I posted in the discussions tab on the Capybara GitHub repo – but no word yet.
Mortimer was (close to) feature complete (if looking at it from the basic functionality side of things) and I was happy to commit, and tag it 0.2.0_teams – what a day!