Docs: http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

Từ trong Rails 4 StrongParamaters được thêm. Vậy ý nghĩa, cách sử dụng của nó là gì hôm nay mình sẽ giới thiệu với các bạn về nó.

Strong Parameters và Mass Assignment

  • StrongParameters là 1 phương pháp để đối phó với lỗi bảo mật khi sử dụng tính năng Mass Assignment.

  • Mass Assignment là 1 tính năng cực kì tiện lợi cho phép update 1 model – khi tạo mới hoặc thay đổi – bằng hash của Ruby.

# không sử dụng mass assignment
user = User.find(1)
user.name = "Rock Khuya"
user.email = "sample@gmail.com"
user.save

# sử dụng mass assignment
user = User.find(1)
user.update(name: "Rock Khuya", email: "sample@gmail.com")

Điều này đặc biệt tiện lợi khi cần thay đổi nhiều dữ liệu cùng lúc. Ví dụ trong controller này:

class ProfileController < ApplicationController
  def update
    user = current_user
    # params = {name: "Rock Khuya", email: "sample@gmail.com"}
    user.update(params[:user])
  end
end

Tuy nhiên, điều này ẩn chứa 1 lỗi khá nghiêm trọng, đó là ta không kiểm soát được những giá trị trong params. Nếu hacker thêm vào những giá trị như {password: "12345678", admin: true} thì mặc nhiên user sẽ bị thay đổi password hoặc trở thành admin.

Cách sử dụng

StrongParameters được thêm vào để ngăn chặn lỗi này.

class ProfileController < ApplicationController
  def update
    user = current_user
    # params = {name: "Rock Khuya", email: "sample@gmail.com"}
    user.update(user_params)
  end

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

StrongParameters giống như 1 bộ lọc các giá trị được phép thay đổi.

Cách sử dụng rất đơn giản :

  • require(:user) bắt buộc trong params phải có key là user
  • permit(:name, :email) trong key user chỉ cho phép name và email

Ví dụ khác, trong trường hợp params không có key user, Rails sẽ báo lỗi. Điều này khá bất tiện, do đó ta có thể sử dụng fetch khai báo mặc định.


2
params.fetch(:article, {}).permit(:headline, :content)
# Nếu params[:article] có thì sử dụng giá trị đó, nếu không thì được coi là {}

Strong Parameters và nest

Giả sử 1 user có nhiều địa chỉ, khi đó ta có :

has_many :addresses, :dependent => :destroy
accepts_nested_attributes_for :addresses

Cách viết Strong Parameters cho trường hợp này :

def user_params
  params.require(:user).permit( :name, :email,
    :addresses_attributes => [:location, :zip, :prefecture, :street])
end

debug Strong Parameters

Strong Parameters tiện lợi và mạnh mẽ thật, song đôi khi lại là ác mộng khi debug. Vì đôi khi mọi thứ đều hoàn hảo, chỉ trừ việc quên không khai báo trong Strong Parameters và 1 giá trị nào đó bị loại bỏ. Mình từng bị 1 lần viết code cho upload ảnh, khi đó sẽ có thêm 1 giá trị mới là :_destroy, mình quên không khai báo và debug hết … 1 ngày.

Để khắc phục điều này, ta có thể thay đổi setting trong config/application.rb ( cho từng môi trường cụ thể config/environments/xyz.rb) để khi có 1 giá trị không được cho phép ở trong params, Rails sẽ gọi lỗi lên :

config.action_controller.action_on_unpermitted_parameters = :raise

Thuộc tính ảo cũng phải khai báo

Với những thuộc tính ảo, không tồn tại trên DB, ta vẫn phải khai báo với Strong Parameters. Ví dụ như confirmed, _destroy, …

class Paper < ActiveRecord::Base
  # thuộc tính này không được lưu trên DB
  attr_accessor :confirmed

  def create
    @paper = Paper.new(paper_params)

    # Nếu không được confirmed sẽ báo lỗi
    if @paper.save
      redirect_to @paper, notice: "failed."
    else
      render action: "new"
    end
  end

  private

    def paper_params
      params.require(:paper).permit(:confirmed)
    end

end

Hy vọng bài viết này sẽ giúp các bạn nhanh chóng làm quen hơn với Rails. Thân.