12/08/2018, 13:52

Custom Validators

1. Validations là gì? Validations là các thao tác kiểm chứng dữ liệu hợp lệ theo các yêu cầu của người dùng trước khi được gửi lên server và lưu vào database. Ví dụ: người dùng nhập 1 form đăng ký account, thì các validations sẽ đảm bảo rằng người dùng không được bỏ trống các trường email, ...

1. Validations là gì?

Validations là các thao tác kiểm chứng dữ liệu hợp lệ theo các yêu cầu của người dùng trước khi được gửi lên server và lưu vào database. Ví dụ: người dùng nhập 1 form đăng ký account, thì các validations sẽ đảm bảo rằng người dùng không được bỏ trống các trường email, username, password. Hay email phải đúng định dạng, password có độ dài tối thiểu là 6 ...

2. Các loại validations

Rails cung cấp Validation Helpers thông dụng hoặc chúng ta có thể Custom Validations theo ý của mình.

ActiveRecord cung cấp sẵn một số Validations Helpers cho người dùng sử dụng trực tiếp như:

  • Không được bỏ trống
    validates :name, presence: true
  • Yêu cầu checked
    validates :terms_of_service, acceptance: true
  • Độ dài
    validates :name, length: { minimum: 2 }
    validates :bio, length: { maximum: 500 }
    validates :password, length: { in: 6..20 }
    validates :registration_number, length: { is: 6 }
etc...

3. Thực hiện Custom Validates

Khi các Validation Helpers không đủ cho yêu cầu sử dụng, chúng ta có thể viết các validators riêng hoặc validation method nếu bạn muốn.

3.1. Custom Validators

Custom Validators là những class kế thừa từ ActiveModel::Validator. Những class này phải implement các validate method để lấy đối số (record) và thực hiện validation nó. Custom Validator được gọi bằng validates_with method.

   class MyValidator < ActiveModel::Validator
     def validate(record)
       unless record.name.starts_with? 'X'
       record.errors[:name] << 'Need a name starting with X please!'
       end
     end
   end

   class Person
     include ActiveModel::Validations
     validates_with MyValidator
   end

Cách dễ nhất để tạo một custom validator với các thuộc tính riêng là sử dụng kế thừa từ ActiveModel::EachValidator. Khi đó, class custom validator phải implement một method là validate_each gồm 3 đối số: record, attribute, and value.

    class EmailValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        unless value =~ /A([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})z/i
          record.errors[attribute] << (options[:message] || "is not an email")
        end
      end
    end

    class Person < ApplicationRecord
      validates :email, presence: true, email: true
    end

Như trong ví dụ trên, có thể kết hợp validations cơ bản và custom validators

3.2. Custom Methods

Bạn có thể tạo ra các method để làm điều kiện kiểm tra và đưa ra messages cảnh báo. Sau đó bạn phải đăng ký các method này để sử dụng cho validates.

    class Invoice < ApplicationRecord
      validate :active_customer, on: :create

      def active_customer
        errors.add(:customer_id, "is not active") unless customer.active?
      end
    end

4. Sử dụng Validation Errors

Rails cung cấp một số method để làm việc với các lỗi và hỏi về tính hợp lệ của object

Dưới đây một số Errors Method thường được sử dụng:

4.1. errors

Trả về các thể hiện của class ActiveModel::Errors bao gồm toàn bộ các lỗi. Mỗi key là một tên thuộc tính và giá trị của mảng là chuỗi các lỗi:

      class Person < ApplicationRecord
      validates :name, presence: true, length: { minimum: 3 }
      end

      person = Person.new
      person.valid? # => false
      person.errors.messages
       # => {:name=>["can't be blank", "is too short (minimum is 3 characters)"]}

      person = Person.new(name: "John Doe")
      person.valid? # => true
      person.errors.messages # => {}

4.2. errors[ ]

errors[ ] được dùng khi muốn in ra lỗi của một thuộc tính cụ thể:

      class Person < ApplicationRecord
        validates :name, presence: true, length: { minimum: 3 }
      end

      person = Person.new(name: "John Doe")
      person.valid? # => true
      person.errors[:name] # => []

      person = Person.new(name: "JD")
      person.valid? # => false
      person.errors[:name] # => ["is too short (minimum is 3 characters)"]

4.3. errors.add

Cho phép thêm một error message liên quan đến 1 thuộc tính cụ thể. Trong đó có đối số của thuộc tính và error message:

      class Person < ApplicationRecord
        def a_method_used_for_validation_purposes
        errors.add(:name, "cannot contain the characters !@#%*()_-+=")
        end
      end

      person = Person.create(name: "!@#")

      person.errors[:name]
       # => ["cannot contain the characters !@#%*()_-+="]

      person.errors.full_messages
       # => ["Name cannot contain the characters !@#%*()_-+="]

4.4. errors[:base]

Bạn có thể thêm error messages có liên quan đến trạng thái của toàn thể objects thay vì một thuộc tính cụ thể. Bạn có thể sử dụng phương pháp này khi muốn nói rằng object không hợp lệ mà không có vấn đề gì với các thuộc tính của nó:

      class Person < ApplicationRecord
        def a_method_used_for_validation_purposes
        errors[:base] << "This person is invalid because ..."
        end
      end

4.5. errors.clear

Sử dụng khi bạn muốn xóa tất cả các messages trong danh sách lỗi. Tất nhiên, error.clear khi được gọi sẽ không làm 1 đối tượng không hợp lệ trở thành có giá trị. Nó chỉ làm rỗng danh sách các lỗi lúc này, nhưng nếu cố gắng lưu nó vào database thì validations sẽ chạy lại và danh sách các lỗi lại được đưa ra :

      class Person < ApplicationRecord
        validates :name, presence: true, length: { minimum: 3 }
      end

      person = Person.new
      person.valid? # => false
      person.errors[:name]
       # => ["can't be blank", "is too short (minimum is 3 characters)"]

      person.errors.clear
      person.errors.empty? # => true

      person.save # => false

      person.errors[:name]
       # => ["can't be blank", "is too short (minimum is 3 characters)"]

4.6. errors.size

Trả về tổng số lỗi của 1 đối tượng cụ thể:

      class Person < ApplicationRecord
        validates :name, presence: true, length: { minimum: 3 }
      end

      person = Person.new
      person.valid? # => false
      person.errors.size # => 2

      person = Person.new(name: "Andrea", email:"andrea@example.com")
      person.valid? # => true
      person.errors.size # => 0

Tổng kết : bài biết mong muốn mang lại cho các bạn cái nhìn tổng quan về validations, cách thực hiện Custom Validations và sử dụng error messages hiển thị validations

Tham khảo: http://guides.rubyonrails.org/active_record_validations.html

0