12/08/2018, 11:56

Custom Validators of devise in Ruby on Rails 4

1. Thế nào là validation? Sau khi người dùng submit dữ liệu từ client lên server thì các validation mặc định sẽ hoạt động nhằm thông báo cho người dùng đã nhập đúng hay chưa. Ví dụ, khi ta dùng gem 'devise' để authenticate thì khi người dùng không nhập gì cả mà bấm nút login thì sẽ xuất hiện ra ...

1. Thế nào là validation?

Sau khi người dùng submit dữ liệu từ client lên server thì các validation mặc định sẽ hoạt động nhằm thông báo cho người dùng đã nhập đúng hay chưa. Ví dụ, khi ta dùng gem 'devise' để authenticate thì khi người dùng không nhập gì cả mà bấm nút login thì sẽ xuất hiện ra 2 thông báo: "chưa nhập email" và "chưa nhập mật khẩu". Nhưng bây giờ chúng ta chỉ muốn xuất ra 1 thông báo và nội dung thông báo lỗi theo mong muốn như hình ảnh bên dưới thì phải làm thế nào?

login.png Để được message thông báo như trên chúng ta phải custom các validations mặc định. Cụ thể ở đây chúng ta sẽ custom validation của gem 'divise'

2. Cách custom validators

Thông thường khi khai báo devise cho model nào đó thì model đấy sẽ trông như thế này:

# app/models/user.rb
class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable,
         :validatable # Khi muốn custom validation thì ta phải bỏ thuộc tính này
  #...
end

Ta thấy một thuộc tính :validatable của gem devise, chính thuộc tính này sẽ mặc định validate các form của hệ thống đăng nhập khi được bấm nút submit or login. Vậy ta muốn custom nó trước hết ta hãy xóa thuộc tính này đi và tạo một file validator nằm trong thư mục app/validators/:

#app/validators/login_validator.rb
class LoginValidator < ActiveModel::Validator
  VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-]+(.[a-z]+)*.[a-z]+z/i

  def validate record
    if record.email.blank? && record.encrypted_password.blank?
      record.errors[:メールアドレスとパスワード] << " を入力してください。"
    elsif record.encrypted_password.blank?
      record.errors[:パスワード] << " を入力してください。"
    elsif record.email.blank?
      record.errors[:メールアドレス] << " を入力してください。"
    elsif record.email.present? && record.email !~ VALID_EMAIL_REGEX
      record.errors[:メール形式] << " が正しくありません。"
    else
      resource = record.class.find_by email: record.email,
                               encrypted_password: record.encrypted_password
      if resource.blank?
        record.errors[:メールアドレスまたはパスワード] << " が正しくありません。"
      end
    end
  end
end

Để tạo thư mục này có thể được nạp đạn tự động khi khởi động, chúng ta cần phải thêm nó vào config/application.rb

# config/application.rb

    # ...

    # add custom validators path
    config.autoload_paths += %W["#{config.root}/app/validators/"]

    # ...

Vậy sau khi tao ra được file login_validator.rb cho devise, một câu hỏi đặt ra là gọi login_validator.rb này ở đâu? Chúng ta sẽ tạo ra một class controller SessionsController được kế thừa từ Devise::SessionsController

#app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
  def new
    if user_signed_in?
      redirect_to root_path
    else
      self.resource = resource_class.new(sign_in_params)

      # Chúng ta sẽ gọi LoginValidator ở đây
      resource.validates_with(LoginValidator) unless sign_in_params.empty?

      clean_up_passwords(resource)
      yield resource if block_given?
      respond_with(resource, serialize_options(resource))
    end
  end
end

=> Như vậy chúng ta đã custom được validator của gem 'devise' khi thực hiện chức năng login

3. Kết luận

Qua ví dụ mẫu ở trên ta có thể thấy rằng việc thực hiện custom validation của gem 'devise' khá là dễ dàng và gọn nhẹ. Tương tự như việc custom validation của 'devise' chúng ta có thể sử dụng phương pháp này cho nhiều các model khác với nhiều chức năng như thêm, sửa, xóa... chúng ta có thể tùy biến được số lượng message và nội dung các lỗi được phát hiện khi thực các chức năng nào đó của các model.

4.

0