(Tôi đã gửi bài đăng này vào danh sách của mình cách đây vài tháng. Nếu bạn thích nó và muốn đọc nhiều hơn giống như nó, bạn nên đăng ký!)
Tôi đã gặp phải một tình huống kỳ lạ vào ngày hôm trước với một trong các ứng dụng của mình.
Giả sử bạn có một Article
và những bài báo này lần đầu tiên được tạo dưới dạng bản nháp. Những bản nháp này phải nhẹ. Bạn muốn có thể tạo và chỉnh sửa chúng ngay lập tức mà không cần nội dung hoặc thậm chí là tiêu đề.
Nhưng khi bạn xuất bản những bài báo này, bạn cần phải có thêm một số xác nhận. Chúng phải có tiêu đề, nội dung và tất cả phần còn lại của nội dung đó.
Bạn có thể viết một loạt if
để tự kiểm tra. Nhưng bạn sẽ không có tất cả các xử lý biểu mẫu đẹp mà bạn nhận được từ Rails. Và tôi nhận thấy rằng việc sử dụng Rails cho những thứ mà Rails xử lý tốt sẽ giúp bạn đỡ phải đau đầu hơn rất nhiều sau này. Có cách nào để sử dụng xác thực cho việc này không?
if
và unless
?
Hỗ trợ xác thực :if
và :unless
nhưng điều này không phải lúc nào cũng rõ ràng:
class Article < ActiveRecord::Base
# validate in draft mode
validates_presence_of :author_id
# validate only when published
validates_presence_of :body, unless: lambda { |o| o.draft? }
...
end
Ngoài ra, đây không phải là cách tôi muốn xuất bản một bài báo. Tôi muốn nghĩ về việc xuất bản một bài báo như một hành động , không phải là một trạng thái trong bài viết, vì vậy việc đặt và kiểm tra một thuộc tính không phải là câu trả lời phù hợp.
Một tính năng Rails ít được biết đến, được ghi lại một cách nhẹ nhàng
Vấn đề này hoàn toàn phù hợp với các ngữ cảnh xác thực của Rails. Lần đầu tiên tôi biết về các ngữ cảnh xác thực tùy chỉnh từ một ý chính mà DHH đã viết. Nhưng thật khó để tìm ra lời giải thích tốt về những thứ này là gì và cách sử dụng chúng.
Tài liệu cho các ngữ cảnh tùy chỉnh khá mỏng. Đề cập duy nhất về nó mà tôi có thể tìm thấy trong tài liệu API là ở đây. Và tài liệu API cho những xác thực này hoàn toàn không đề cập đến ngữ cảnh tùy chỉnh! Điều này đặc biệt khó khăn - nếu bạn không biết cái gì đó được gọi là gì, làm cách nào để tìm thêm tài liệu về nó?
Cuối cùng tôi đã tìm thấy một cái nhìn tổng quan tốt ở đây:https://blog.arkency.com/2014/04/mastering-rails-validations-contexts/. Rất đáng để đọc. Hãy xem ví dụ của chúng ta trông như thế nào:
class Article < ActiveRecord::Base
# validate in draft mode
validates_presence_of :author_id
# validate only when published
validates_presence_of :body, on: :publish
...
end
class ArticleController < ApplicationController
respond_to :html
def create
@article = Article.create(article_params)
respond_with @article
end
def publish
@article = Article.find(params[:id])
@article.attributes = article_params
@article.save(context: :publish)
respond_with @article
end
private
def article_params
params.
require(:article).
permit(:body, :title, :author_id)
end
end
Không tệ lắm! Điều kỳ lạ duy nhất là phải sử dụng save
thay vì update
trong phương pháp xuất bản. Điều đó xảy ra vì update
không thể lấy ngữ cảnh xác thực làm tham số. (Có thể đó là cơ hội cho một yêu cầu kéo?)
Ngoài tiết kiệm
Các ngữ cảnh xác thực tùy chỉnh hữu ích hơn là chỉ lưu bản ghi theo những cách khác nhau. Các ngữ cảnh hoạt động với valid?
:
@article.valid?(:publish)
vì vậy bạn có thể sử dụng ngữ cảnh xác thực ở bất cứ đâu bạn muốn để trả lời câu hỏi: “Đối tượng này có thuộc tính này không? Và nếu không, tại sao không? ”
DHH tạo một phương thức kết thúc bằng -able?
ủy quyền cho valid?(:context)
). Tôi thực sự thích giao diện của nó:
class Article
validate :has_been_published, on: :view
validate :is_not_spam, on: :view
def viewable?
valid? :view
end
private
def has_been_published
if published_at.future?
errors.add(:published_at, "is in the future")
end
end
def is_not_spam
if is_spam?(body)
errors.add(:body, "has been detected as spam")
end
end
end
Bằng cách này, khi bạn kiểm tra nó, bạn sẽ nhận được nhiều thông tin hơn chỉ là true
hoặc false
:
unless @article.viewable?
# @article.errors is now filled out
end
Bài báo có thể xem được không? Chà, tại sao không?
Vừa đủ nhẹ
Có một số cách khác để bạn có thể nhận được loại hành vi xác thực này. Bạn có thể tạo ActiveModel
tùy chỉnh các đối tượng dịch vụ với các xác nhận của riêng chúng. Bạn có thể sử dụng :if
hoặc :unless
về xác nhận của bạn. Nhưng giống như nhiều thứ trong Rails, ngữ cảnh xác thực tùy chỉnh là sự thỏa hiệp tốt giữa khả năng đọc và tính linh hoạt.