Mulai April 2020, bandithijo.com akan menggunakan subdomain GitHub menjadi bandithijo.github.io. Penggunaan domain .com tidak sejalan dengan cara pandang saya terhadap sebuah blog, dimana blog harus bisa tetap hidup tanpa saya. Terima kasih (^_^) (bandithijo, 2020/03/25) ●

Mempertahankan Data pada Form ketika User Belum Melakukan Authentication

Ditulis: 2020/01/01 Diperbaharui: 2020/01/01
Rails Tips

بسم الله الرحمن الرحيم

Prerequisite

Ruby 2.6.3 Rails 5.2.3 PostgreSQL 11.5

Prakata

Mengawali tahun 2020 ini, saya mencatat mengenai Ruby on Rails.

Kali ini mengenai bagaimana cara memberikan user experience flow yang baik dengan web aplikasi yang menggunakan form saat pengguna belum melakukan authentication.

Permasalahan

Dalam mengisi form, misalkan form pemesanan (order), yang memiliki banyak inputan data, tentunya pengguna akan merasa kesal, apabila sudah memasukkan banyak data, namun saat menekan tombol submit, dan harus melakukan sign in atau sign up terlebih dahulu, setelah itu, data yang pengguna masukkan pada order form tadi sudah menghilang. Artinya, pengguna harus memasukkan kembali data-data yang sudah ia masukkan sebelumnya.

User experience flow di atas, tentunya akan membuat user merasa kesal.

Penyelesaian Masalah

Kebetulan, web aplikasi kali ini menggunakan Devise gem untuk menghandle proses authentication.1

Saya dapat memanfaatkan helper-helper module yang sudah disediakan oleh Devise.

Seperti, untuk membawa user kembali ke halaman sebelumnya, dengan stored_location_for dari Devise::Controllers::StoreLocation.

Untuk menyelesaikan permasalahan di atas, saya akan memodifikasi controller-controller yang menghandle proses-proses di atas.

Proses di atas terdiri dari:

  1. Order, yang dihandle oleh Users::OrderExperiencesController#create
  2. Sign In, yang dihandle oleh Users::SessionsController
  3. Sign Out, yang dihandle oleh Users::RegistrationsController


Bagaimana memertahankan data yang sudah dimasukkan sebelumnya pada Order form?

Untuk membuat data yang ada pada form menjadi persistent, saya akan memanfaatkan session.2 Kemudian, setelah user melakukan authentication, session akan di-passing ke dalam variable dan akan dikosongkan.

Order Experiences Controller

Karena proses order experience ini di-handle oleh action :create, maka saya perlu memodifikasi isi dari action ini.

# app/controllers/users/order_experiences_controller.rb

class Users::OrderExperiencesController < ApplicationController
  # pastikan untuk tidak memfilter action :create, karena akan dihandling oleh
  # redirect rule yang akan dibuat
  before_action :authenticate_user!, except: [:create]

  def create
    # mengecek apakah pengunjung sudah sign in/sign up
    if current_user.nil?
      # menyimpan data dari form ke dalam session, yang akan digunakan setelah login/register
      session[:order] = params
      # redirect ke user login/register page
      redirect_to new_user_session_path
    else
      # jika user sudah login, diproses seperti biasa
      order = current_traveler.orders.create(order_params)
      redirect_to users_order_experience_path(order.id)
    end
  end

  ...
  ...

  private

  def order_params
    params.require(:order).permit(
      :trip_date, :time_slot, :total_traveler, :experience_id,
      traveler_attributes: [:id, :full_name, :email, :phone]
    )
  end
end

Pastikan pada callback before_action :authenticate_user!, buat pengecualian untuk action :create.

Selanjutnya, tinggal memodifikasi controller yang menghandle proses login/register.

Sessions & Registrations Controller

Kedua controller ini adalah controller yang digenerate oleh Devise.

# app/controllers/users/sessions_controller.rb

# frozen_string_literal: true

class Users::SessionsController < Devise::SessionsController
  ...

  ...
  ...

  protected

  ...
  ...

  # path yang akan dituju setelah sign in
  def after_sign_in_path_for(resource_or_scope)
    # memeriksa apakah ada data order yang tersimpan pada session
    if session[:order].present?
      # membuat order dengan data yang tersimpan pada session
      order = current_traveler.orders.create(session[:order]["order"])
      # mengosongkan session
      session[:order] = nil
      # redirect ke halaman order
      users_order_experience_path(order.id)
    else
      # jika tidak ada data order yang tersimpan pada session
      stored_location_for(resource_or_scope) || super
    end
  end
end
# app/controllers/users/registrations_controller.rb

# frozen_string_literal: true

class Users::RegistrationsController < Devise::RegistrationsController
  ...

  ...
  ...

  protected

  ...
  ...

  # path yang akan dituju setelah sign up
  def after_sign_up_path_for(resource_or_scope)
    # memeriksa apakah ada data order yang tersimpan pada session
    if session[:order].present?
      # membuat order dengan data yang tersimpan pada session
      @order = current_traveler.orders.create(session[:order]["order"])
      # mengosongkan session
      session[:order] = nil
      # redirect ke halaman order
      users_order_experience_path(@order.id)
    else
      # jika tidak ada data order yang tersimpan pada session
      stored_location_for(resource_or_scope) || super
    end
  end

  ...
  ...
end

Selesai!

Mungkin pada kesempatan yang lain, akan saya buatkan reponya.

Mudah-mudahan bermanfaat.

Terima kasih.

(^_^)

Referensi

  1. How To: Redirect back to current page after sign in, sign out, sign up, update
    Diakses tanggal: 2020/01/01

  2. Action Controller Overview > Session
    Diakses tanggal: 2020/01/01

  3. blog.justinthiele.com/retaining-form-data-through-a-login-process-a
    Diakses tanggal: 2020/01/01

Penulis

logo_author

BanditHijo adalah nama pena saya – meminjam istilah keren dari para penulis. Teman-teman menyebut saya sebagai GNU/Linux Enthusiast. Saya memang gemar mengutak-atik sistem operasi ini. Bukan karena hobi tapi karena saya perlu untuk menggunakannya. Hehe.

- Rizqi Nur Assyaufi