Wednesday

18-06-2025 Vol 19

Comparing params.expect to params.require and params.fetch

Params.expect vs. Params.require vs. Params.fetch di Rails: Panduan Lengkap

Dalam pengembangan aplikasi Rails, menangani parameter permintaan (request parameters) dengan aman dan efisien adalah hal yang krusial. Rails menyediakan beberapa metode untuk mengakses dan memvalidasi parameter, di antaranya adalah params.expect, params.require, dan params.fetch. Memahami perbedaan dan kegunaan masing-masing metode sangat penting untuk menulis kode yang robust, aman, dan mudah dipelihara. Artikel ini akan membahas secara mendalam ketiga metode tersebut, membandingkannya, dan memberikan panduan praktis tentang kapan dan bagaimana menggunakannya.

Daftar Isi

  1. Pendahuluan
    • Mengapa Penanganan Parameter Penting?
    • Sekilas tentang params di Rails
  2. Params.require: Validasi Kehadiran Parameter
    • Definisi dan Sintaks
    • Contoh Penggunaan
    • Menangani Pengecualian ActionController::ParameterMissing
    • Kasus Penggunaan Terbaik
  3. Params.fetch: Mengambil Parameter dengan Nilai Default
    • Definisi dan Sintaks
    • Contoh Penggunaan
    • Nilai Default dan Blok
    • Kasus Penggunaan Terbaik
  4. Params.expect: Validasi Berdasarkan Schema (Rails 7.1+)
    • Definisi dan Sintaks
    • Contoh Penggunaan
    • Manfaat Validasi Schema
    • Konfigurasi Schema
    • Kasus Penggunaan Terbaik
  5. Perbandingan: Require vs. Fetch vs. Expect
    • Tabel Perbandingan
    • Kapan Menggunakan Masing-Masing Metode
    • Studi Kasus: Skenario Praktis
  6. Praktik Terbaik Penanganan Parameter
    • Keamanan: Mencegah Kerentanan
    • Kode yang Bersih dan Mudah Dibaca
    • Pengujian
  7. Kesimpulan

1. Pendahuluan

1.1 Mengapa Penanganan Parameter Penting?

Parameter adalah data yang dikirimkan ke aplikasi web dari klien (browser, aplikasi mobile, dll.) melalui permintaan HTTP. Penanganan parameter yang tepat sangat penting karena beberapa alasan:

  • Keamanan: Parameter yang tidak divalidasi dapat menyebabkan kerentanan keamanan seperti SQL injection, Cross-Site Scripting (XSS), dan Mass Assignment.
  • Integritas Data: Memastikan bahwa data yang diterima sesuai dengan format dan tipe yang diharapkan mencegah kesalahan dan inkonsistensi data.
  • Pengalaman Pengguna: Memberikan pesan kesalahan yang jelas dan informatif ketika parameter yang dibutuhkan tidak ada atau tidak valid meningkatkan pengalaman pengguna.
  • Robustness: Kode yang menangani parameter dengan baik lebih tahan terhadap kesalahan dan perubahan tak terduga.

1.2 Sekilas tentang params di Rails

Objek params di Rails adalah hash yang menyimpan semua parameter permintaan yang dikirimkan ke controller. Parameter ini dapat berasal dari:

  • URL: Parameter yang dikirimkan sebagai bagian dari URL (misalnya, /products/123).
  • Query String: Parameter yang dikirimkan setelah tanda tanya (?) di URL (misalnya, /products?category=electronics&page=2).
  • Body Permintaan: Parameter yang dikirimkan dalam body permintaan HTTP (biasanya digunakan untuk permintaan POST, PUT, dan PATCH).

Objek params dapat diakses di dalam controller action. Contoh:

def create
  @product = Product.new(params[:product]) # BERPOTENSI MASALAH KEAMANAN!
  if @product.save
    redirect_to @product
  else
    render 'new'
  end
end

Kode di atas rentan terhadap Mass Assignment. Kita akan membahas cara mengatasi masalah ini dengan params.require dan params.permit nanti. Namun, sebelum itu, mari kita lihat lebih dekat params.require, params.fetch, dan params.expect.

2. Params.require: Validasi Kehadiran Parameter

2.1 Definisi dan Sintaks

params.require digunakan untuk memastikan bahwa parameter tertentu ada dalam objek params. Jika parameter tidak ada, maka akan memunculkan pengecualian ActionController::ParameterMissing.

Sintaks:

params.require(:parameter_name)

:parameter_name adalah simbol yang merepresentasikan nama parameter yang ingin Anda validasi.

2.2 Contoh Penggunaan

Misalnya, kita memiliki formulir yang mengirimkan parameter :user dengan atribut :name dan :email.

def create
  @user = User.new(user_params)
  if @user.save
    redirect_to @user
  else
    render 'new'
  end
end

private

def user_params
  params.require(:user).permit(:name, :email, :password, :password_confirmation)
end

Dalam contoh ini, params.require(:user) memastikan bahwa parameter :user ada. Jika parameter :user tidak ada, maka akan memunculkan ActionController::ParameterMissing.

Setelah memastikan parameter :user ada, kita menggunakan .permit untuk menentukan atribut mana yang diizinkan (whitelist). Ini adalah cara yang aman untuk menangani Mass Assignment.

2.3 Menangani Pengecualian ActionController::ParameterMissing

Anda dapat menangani pengecualian ActionController::ParameterMissing secara global dalam aplikasi Rails Anda menggunakan rescue_from di dalam ApplicationController.

class ApplicationController < ActionController::Base
  rescue_from ActionController::ParameterMissing, with: :parameter_missing

  private

  def parameter_missing(exception)
    render json: { error: exception.message }, status: :bad_request
  end
end

Dengan kode di atas, setiap kali ActionController::ParameterMissing muncul, metode parameter_missing akan dipanggil, dan respons JSON dengan pesan kesalahan dan status bad request akan dikembalikan.

2.4 Kasus Penggunaan Terbaik

  • Ketika suatu parameter harus ada untuk memproses permintaan.
  • Untuk memastikan bahwa data yang diperlukan untuk membuat atau memperbarui sebuah model ada.
  • Sebagai lapisan pertama validasi sebelum melakukan operasi database.

3. Params.fetch: Mengambil Parameter dengan Nilai Default

3.1 Definisi dan Sintaks

params.fetch digunakan untuk mengambil parameter dari objek params. Jika parameter tidak ada, maka akan mengembalikan nilai default yang diberikan. Ini berbeda dengan params.require yang akan memunculkan pengecualian jika parameter tidak ada.

Sintaks:

params.fetch(:parameter_name, default_value)

:parameter_name adalah simbol yang merepresentasikan nama parameter yang ingin Anda ambil.

default_value adalah nilai yang akan dikembalikan jika parameter tidak ada.

Anda juga dapat memberikan blok sebagai nilai default:

params.fetch(:parameter_name) { |key| # kode untuk menghasilkan nilai default }

Blok akan dieksekusi hanya jika parameter tidak ada. Parameter key dalam blok adalah nama parameter yang tidak ditemukan.

3.2 Contoh Penggunaan

Misalnya, kita ingin mengambil nomor halaman dari parameter :page. Jika parameter :page tidak ada, kita ingin menggunakan nilai default 1.

def index
  @page = params.fetch(:page, 1).to_i
  @products = Product.paginate(page: @page, per_page: 20)
end

Dalam contoh ini, params.fetch(:page, 1) akan mengembalikan nilai parameter :page jika ada. Jika tidak, maka akan mengembalikan 1.

Contoh lain menggunakan blok:

def show
  @product = Product.find(params.fetch(:id) { raise ActiveRecord::RecordNotFound, "Product ID not provided" })
end

Dalam contoh ini, jika parameter :id tidak ada, blok akan dieksekusi dan memunculkan pengecualian ActiveRecord::RecordNotFound dengan pesan yang sesuai.

3.3 Nilai Default dan Blok

Memilih antara nilai default langsung dan blok tergantung pada kebutuhan Anda:

  • Nilai Default Langsung: Digunakan ketika nilai default sederhana dan tidak memerlukan komputasi yang kompleks.
  • Blok: Digunakan ketika nilai default memerlukan komputasi yang kompleks, memanggil metode lain, atau memunculkan pengecualian.

Menggunakan blok dapat meningkatkan performa karena blok hanya dieksekusi jika parameter tidak ada.

3.4 Kasus Penggunaan Terbaik

  • Ketika parameter bersifat opsional dan memiliki nilai default yang masuk akal.
  • Untuk menyediakan nilai default untuk parameter paginasi, filter, atau opsi lainnya.
  • Ketika Anda perlu melakukan komputasi untuk menghasilkan nilai default.
  • Ketika Anda ingin memunculkan pengecualian kustom jika parameter tidak ada.

4. Params.expect: Validasi Berdasarkan Schema (Rails 7.1+)

4.1 Definisi dan Sintaks

params.expect adalah fitur baru yang diperkenalkan di Rails 7.1 yang memungkinkan Anda untuk mendefinisikan dan memvalidasi skema untuk parameter Anda. Ini memberikan cara yang lebih deklaratif dan terstruktur untuk memvalidasi parameter dibandingkan dengan menggunakan params.require dan params.permit secara manual.

Sintaks:

params.expect(schema)

schema adalah objek yang mendefinisikan struktur dan tipe data yang diharapkan dari parameter.

4.2 Contoh Penggunaan

Misalnya, kita ingin memvalidasi parameter :user dengan atribut :name (string yang diperlukan) dan :age (integer opsional).

def create
    permitted_params = params.expect({
      user: {
        name: :string,
        age: :integer,
      }
    })

    @user = User.new(permitted_params[:user])

    if @user.save
      redirect_to @user
    else
      render 'new'
    end
  end

Dalam contoh ini, params.expect memvalidasi bahwa parameter :user ada, memiliki atribut :name yang berupa string, dan secara opsional memiliki atribut :age yang berupa integer. Jika validasi gagal, ActionController::BadRequest akan dimunculkan. Parameter yang lolos validasi akan dikembalikan dalam bentuk hash permitted_params.

4.3 Manfaat Validasi Schema

  • Deklaratif: Skema mendefinisikan struktur parameter yang diharapkan secara eksplisit.
  • Terstruktur: Memudahkan untuk memahami dan memelihara validasi parameter.
  • Otomatis: Validasi dilakukan secara otomatis berdasarkan skema yang didefinisikan.
  • Konsisten: Memastikan validasi parameter konsisten di seluruh aplikasi.

4.4 Konfigurasi Schema

Anda dapat mendefinisikan skema validasi secara terpisah dan menggunakannya kembali di berbagai controller actions. Ini membantu menjaga kode Anda tetap DRY (Don't Repeat Yourself).

# app/schemas/user_schema.rb
    class UserSchema
      SCHEMA = {
        user: {
          name: :string,
          email: :string,
          age: :integer
        }
      }

      def self.schema
        SCHEMA
      end
    end

    # app/controllers/users_controller.rb
    def create
      permitted_params = params.expect(UserSchema.schema)
      @user = User.new(permitted_params[:user])

      if @user.save
        redirect_to @user
      else
        render 'new'
      end
    end
    

4.5 Kasus Penggunaan Terbaik

  • Ketika Anda ingin memvalidasi parameter berdasarkan skema yang telah ditentukan.
  • Untuk memastikan bahwa parameter memiliki struktur dan tipe data yang benar.
  • Ketika Anda ingin mendefinisikan validasi parameter secara deklaratif dan terstruktur.
  • Saat menggunakan Rails 7.1 atau lebih tinggi.

5. Perbandingan: Require vs. Fetch vs. Expect

5.1 Tabel Perbandingan

Fitur params.require params.fetch params.expect
Tujuan Memastikan kehadiran parameter Mengambil parameter dengan nilai default Validasi parameter berdasarkan skema
Perilaku jika parameter tidak ada Memunculkan ActionController::ParameterMissing Mengembalikan nilai default Memunculkan ActionController::BadRequest (jika skema tidak sesuai)
Nilai Default Tidak ada Ya (wajib) Tidak ada (validasi berbasis skema)
Validasi Tambahan Tidak ada (hanya kehadiran) Tidak ada Ya (berdasarkan skema)
Ketersediaan Rails semua versi Rails semua versi Rails 7.1+

5.2 Kapan Menggunakan Masing-Masing Metode

  • params.require: Gunakan ketika parameter harus ada untuk memproses permintaan. Contoh: ID produk saat menghapus produk.
  • params.fetch: Gunakan ketika parameter bersifat opsional dan memiliki nilai default yang masuk akal. Contoh: Nomor halaman dalam paginasi.
  • params.expect: Gunakan ketika Anda ingin memvalidasi parameter berdasarkan skema yang kompleks dan memastikan tipe data yang benar. Contoh: Data pengguna yang dikirimkan dari formulir.

5.3 Studi Kasus: Skenario Praktis

Skenario 1: Membuat Komentar

Kita ingin membuat komentar pada sebuah postingan. Parameter yang dibutuhkan adalah :post_id (ID postingan) dan :body (isi komentar).

def create
  @post = Post.find(params.require(:post_id)) # Post ID harus ada
  @comment = @post.comments.build(comment_params)

  if @comment.save
    redirect_to @post
  else
    render 'new'
  end
end

private

def comment_params
  params.require(:comment).permit(:body) # Isi komentar harus ada dan hanya mengizinkan atribut 'body'
end

Skenario 2: Memfilter Produk

Kita ingin memfilter produk berdasarkan kategori dan harga. Parameter :category dan :price bersifat opsional.

def index
  @category = params.fetch(:category, 'all') # Jika tidak ada kategori, tampilkan semua
  @price = params.fetch(:price, 1000).to_i # Jika tidak ada harga, gunakan 1000 sebagai default

  @products = Product.filter(category: @category, price: @price)
end

Skenario 3: Update Data Pengguna (Rails 7.1+)

Kita ingin memperbarui data pengguna dengan parameter :name (string), :email (string), dan :age (integer opsional).

def update
      permitted_params = params.expect({
        user: {
          name: :string,
          email: :string,
          age: :integer
        }
      })

      @user = User.find(params[:id])
      if @user.update(permitted_params[:user])
        redirect_to @user
      else
        render 'edit'
      end
    end
    

6. Praktik Terbaik Penanganan Parameter

6.1 Keamanan: Mencegah Kerentanan

  • Gunakan params.require untuk memastikan kehadiran parameter yang dibutuhkan.
  • Gunakan params.permit untuk menentukan atribut mana yang diizinkan (whitelist).
  • Hindari menggunakan params[:parameter_name] secara langsung tanpa validasi.
  • Validasi tipe data parameter (misalnya, menggunakan .to_i, .to_f).
  • Enkripsi data sensitif (misalnya, password).

6.2 Kode yang Bersih dan Mudah Dibaca

  • Gunakan nama variabel yang deskriptif.
  • Pisahkan logika penanganan parameter ke dalam metode privat.
  • Gunakan komentar untuk menjelaskan tujuan dari setiap baris kode.
  • Ikuti konvensi kode Rails.

6.3 Pengujian

  • Tulis unit test untuk memvalidasi penanganan parameter.
  • Uji kasus positif (parameter ada dan valid).
  • Uji kasus negatif (parameter tidak ada atau tidak valid).
  • Gunakan test doubles (mocks dan stubs) untuk mengisolasi unit yang diuji.

7. Kesimpulan

Memahami dan menggunakan params.require, params.fetch, dan params.expect (di Rails 7.1+) dengan benar sangat penting untuk membangun aplikasi Rails yang aman, robust, dan mudah dipelihara. Pilih metode yang tepat sesuai dengan kebutuhan Anda, ikuti praktik terbaik penanganan parameter, dan selalu uji kode Anda secara menyeluruh.

Dengan menerapkan prinsip-prinsip yang dibahas dalam artikel ini, Anda dapat meningkatkan kualitas kode Anda, mengurangi risiko kerentanan keamanan, dan memberikan pengalaman pengguna yang lebih baik.

```

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *