The past week I've been working on a little web app that lets you post to a Twitter account as a group: http://samentweeten.nl. It's a tool for volunteers so they can share a Twitter account for campaigning or communicate from a single organisation or brand.
Usually, I use Devise for registration and authentication. For building samentweeten.nl, I wanted to discover implementing basic registration and authentication with
has_secure_password and the Rails bare minimum.
Here's the view code for my sign up form. It's nothing special. Just a simple form that asks for Email and Password. It uses
bootstrap_form_for from the bootstrap-forms gem.
<div class="container"> <div class="row"> <div class="col-sm-offset-3 col-sm-6" style="margin-top: 100px"> <div class="panel panel-default"> <div class="panel-heading"> Maak een account </div> <div class="panel-body"> <%= bootstrap_form_for :account do |f| %> <%= f.email_field :email, class: "input-lg" %> <%= f.password_field :password, class: "input-lg" %> <%= f.submit "Account aanmaken", class: "btn btn-block btn-lg btn-primary" %> <% end %> </div> </div> </div> </div> </div>
This view is accessible on
/signup. The form also posts to
/signup so my
routes.rb looks like this:
Rails.application.routes.draw do get "signup" => "signup#new" post "signup" => "signup#create" end
The controller for these two routes looks as follows:
class SignupController < ApplicationController def new end def create @account = Account.new(account_params) if @account.save cookies.signed[:account_id] = @account.id redirect_to dashboard_url else render :new end end private def account_params params.require(:account).permit(:email, :password) end end
Account model I've added
has_secure_password like so:
class Account < ApplicationRecord has_secure_password ... end
In the code for my
SignupController, you can see that I set a signed cookie
account_id to the id of the
Account record that gets created. I'll be using this cookie to verify if the user is logged in on subsequent requests.
Authorizing if a user is logged in
ApplicationController I've added a few helper methods that let me verify and fetch the logged in account. By adding these methods here, I can use them in all the controllers throughout my app.
class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception helper_method :account_signed_in?, :current_account protected def authenticate_account cookies.delete(:account_id) && redirect_to(root_url) if current_account.blank? end def current_account @current_account ||= Account.find_by(id: cookies.signed[:account_id]) end def account_signed_in? current_account.present? end end
I use the
authenticate_account method as a
before_action in all controllers that need a valid account. This method will redirect to the
root_url when no account is logged in. As a bonus, the method clears the
account_id from the cookies when the requested
Account has disappeared. Clearing the cookie is useful for clearing sessions of accounts that were removed.
current_account method is a quick alias that lets me access the current logged in account from any controller or view. I store the result in the
@current_account instance variable, so the database is never queried more than necessary inside a single request when calling the
current_account method multiple times.
The third method
account_signed_in? is just a syntactic sugar method that I can use in my views, inspired by Devise.