Migrating Away from Devise Part 6: Trackable Module and Tests
Published: January 24, 2025
This is the sixth part of a multi-part series about moving from devise to the Rails generated authentication system
- Part 1 - Setup and Sessions
- Part 2 - User Sign-in
- Part 3 - Password Recovery
- Part 4 - Email Confirmation Setup
- Part 5 - User Sign-up
- Part 6 - Trackable Module and Tests
In the user model, this method will update the old trackable columns. This is based heavily off of devise's implementation.
def update_trackables(request)
self.last_sign_in_at = current_sign_in_at || Time.now.utc
self.current_sign_in_at = Time.now.utc
self.last_sign_in_ip = current_sign_in_ip || request.remote_ip
self.current_sign_in_ip = request.remote_ip
self.sign_in_count ||= 0
self.sign_in_count += 1
save(validate: false)
end
When we create a new session for the user in the Authorization
module, the new method will be called.
def start_new_session_for(user)
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
Current.session = session
user.update_trackables(request) # Here's the new code
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
end
end
In regards to testing, devise provided a set of helper methods along with warden to sign in users. It also provided a helper method for fixtures.
test_helper.rb
contains a TEST_PASSWORD
constant with a password string that can be used by fixtures and test (such as "testing123"). It can be applied to fixtures for users like the following.
<% password_digest = BCrypt::Password.create(TEST_PASSWORD) %>
one:
email: one@internet.com
username: one
password_digest: <%= password_digest %>
confirmed_at: <%= Time.now %>
test_helper.rb
includes this helper method to sign in a given user to generate a session for unit, controller, and integration tests.
TEST_PASSWORD = "testing123"
class ActiveSupport::TestCase
# Run tests in parallel with specified workers
parallelize(workers: :number_of_processors)
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
def sign_in(user)
post session_path, params: { user: { username: user.username, password: TEST_PASSWORD } }
end
end
For system tests, a similar helper method works in application_system_test_case.rb
.
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]
def sign_in(user)
visit new_session_path
fill_in "Username", with: user.username
fill_in "Password", with: TEST_PASSWORD
click_on "Sign in"
assert_text "Successfully signed in."
end
end
And... that's it! This should complete the process of removing devise from your app. Remove the gem from your Gemfile
if you haven't done so already as well as the initializer. Commit the branch, open a PR, review it, merge, and deploy. Depending on how long you've taken to do this process, the sessions
table should have enough active sessions from part 1 to keep existing users signed in.