เปลี่ยน id ให้เป็น hash id บน URL

ปกติเมื่อเราใช้ rails generator ในการสร้าง CRUD ไม่ว่าจะเป็น scaffold หรือ scaffold_controller จะพบว่า resources ที่ได้จะมีลักษณะคล้ายกับรูปด้านล่าง

Book Resources Book Resources

กล่าวคือเวลาเข้าถึงหนังสือเล่มหนึ่งจะต้องเรียกผ่าน /books/1 โดยที่เลข id ที่ถูกสร้างขึ้นก็จะเรียงกันไปเรื่อยๆ แบบนี้มันก็ง่ายในการสุ่มเข้าถึงหนังสือเล่มอื่นๆ วิธีการเช่นนี้อาจจะไม่เหมาะนักสำหรับนำไปใช้งานจริง ทีนี้เรามาลองเปลี่ยน id ให้เป็น hash id กันเพื่อให้การเข้าถึงข้อมูลปลอดภัยมากขึ้น

ก่อนอื่นเริ่มโดยการติดตั้ง hashids ซึ่งเป็น gem สำหรับสร้าง hash จากตัวเลข

gem 'hashids'

สร้าง Secret Class สำหรับจัดการแทนการเรียก hashids ตรงๆ

require 'hashids'

module Hashable
  module ClassMethods
    def hashids
      @hashids ||= Hashids.new "secret-book", 8
    end

    def encode(id)
      hashids.encode(id)
    end

    def decode(text)
      hashids.decode(text).first
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Secret
  include Hashable
end

ทำการ override เมธอด to_param เพื่อให้ส่งค่า hash id แทน id เมื่อมีการเรียกใช้งานเมธอด url_for

require 'secret'

class Book < ApplicationRecord
  def to_param
    Secret.encode(id)
  end
end

ถอดรหัส hash id ให้กลายเป็น id ก่อนที่จะเรียก query ผ่าน ORM

def set_book
  @book = Book.find(Secret.decode(params[:id]))
end

จะสังเกตุเห็นว่า ไม่ได้มีการแก้ไข resources ของ Book เลยแม้แต่น้อย

ทดสอบการทำงานดูซะหน่อย

Book ใช้ hash id แทน id

References