Rails 6 Features: What's New and Why It Matters
Bài đăng này đã không được cập nhật trong 5 năm
Mục đích của bài viết là giúp bạn làm quen với các tính năng chính đã được thêm vào Rails 6 và áp dụng để có thể giúp làm cho ứng dụng tốt hơn và tiết kiệm thời gian phát triển. Và phiên bản này được mong chờ vì nhiều điều hay ho mà nó cung cấp cho ta.
Môi trường yêu cầu: Rails 6 yêu cầu Ruby 2.5+ và cơ sở dữ liệu được nâng cấp.
Testing in Rails 6
Mong muốn các trường hợp thử nghiệm sẽ bao phủ hết phạm vi của mã code. Tuy nhiên, việc test sẽ trở nên vô cùng nặng nề bắt buộc chúng ta phải chờ đợi trong vài phút, có thể là vài giờ mới có thể thực hiện các trường hợp như mong muốn.
Và vì thế, Rails 6 đã đưa ra một câu trả lời thỏa mãn, đó là...
Parallel Testing
Một phương thức mới đã được cung cấp đó chính là parallelize
của ActiveSupport::TestCase
. Nó cho phép chúng ta chạy song song các trường hợp test với phương pháp rẽ nhánh.
Để sử dụng được thì cần thêm vào file test_helper.rb
parallelize(workers: 2)
Nếu như trước đây, chúng ta thường chạy test với những dòng lệnh như thế này
bin/rails test OR bin/rspec spec
thì giờ ta có thể thay thế chúng bởi
PARALLEL_WORKERS=15 rails test OR PARALLEL_WORKERS=15 rspec spec
Nếu bạn muốn xem chi tiết hơn thì có thể tham khảo thêm ở đây
Bulk Insert and Upsert
Đôi khi ta rơi vào trường hợp, cần phải thêm nhiều bản ghi vào cùng một lúc và như vậy, Rails 6 ra đời một phương thức mới là insert_all
để giải quyết vấn đề đó. Một câu truy vấn sql về insert được tạo ra Và nó sẽ thực hiện một lệnh truy vấn sql duy nhất mà không thực hiện thêm bất kỳ một callbacks nào. Từ đó giảm bớt các truy vấn không cần thiết và việc thực thi được tối ưu hơn. Có một phương pháp bổ sung là upsert_all
cho phép sử dụng thao tác upsert
Ta có thể xem qua ví dụ
- insert_all với việc bỏ qua các bản ghi trùng lặp
result = Article.insert_all(
[
{ id: 1,
title: 'Handling 1M Requests Per Second',
author: 'John',
slug: '1m-req-per-second' },
{ id: 1, # duplicate 'id' here
title: 'Type Safety in Elm',
author: 'George',
slug: 'elm-type-safety' },
{ id: 2,
title: 'Authentication with Devise - Part 1',
author: 'Laura',
slug: 'devise-auth-1' },
{ id: 3,
title: 'Authentication with Devise - Part 1',
author: 'Laura', # duplicate 'title' & 'author' here
slug: 'devise-auth-2' },
{ id: 4,
title: 'Dockerizing and Deploying Rails App to Kubernetes',
author: 'Paul',
slug: 'rails-on-k8s' }
]
)
puts Article.count
# 3
Phuơng thức insert_all
chấp nhận tham số đầu vào là một mảng các hash như là một Active Record và các key trong hash phải giống nhau. Và khi có conflic hay trùng lặp về khóa ràng buộc giữa các hàng (bản ghi), thì nó sẽ tự động bỏ qua các bản ghi bị conflic và tiếp tục chèn các bản ghi tiếp theo mà không hề bị gián đoạn, ngắt quãng.
Với ví dụ trên, ta có thể thấy, có 2 bản ghi bị vi phạm khóa ràng buộc trên bảng articles và chúng đều bị bỏ qua và không thực hiện chèn vào cơ sở dữ liệu.
Còn với insert_all!
thì thay vì bỏ qua những bản ghi bị lỗi thì nó sẽ đưa ra một thông điệp lỗi ActiveRecord::RecordNotUnique
- upsert_all
Với insert_all
, ta sẽ bỏ qua những bản ghi bị lỗi hoặc đưa ra một ngoại lệ khi gặp một bản sao với insert_all!
và chung quy thì đều là bỏ qua việc thực thi những bản ghi không hợp lệ. Và đôi khi, ta muốn cập nhật lại bản ghi khi có sự cố trùng lặp xảy ra, hoặc sẽ là việc chèn thêm một bản ghi mới. Và với upsert_all
, ta hoàn toàn có thể thực hiện được việc đó.
result = Article.upsert_all(
[
{ id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
{ id: 1, .... }, # duplicate 'id' here
{ id: 2, .... },
{ id: 3, .... }, # duplicate 'title' and 'author' here
{ id: 4, .... },
{ id: 5, .... }, # duplicate 'slug' here
{ id: 6, .... }
]
)
puts Article.count
# 5
Với upsert_all thì nó không hỗ trợ unique_by
nếu bạn đang sử dụng cơ sở dữ liệu là Mysql.
Insert, insert! và upsert
Các phuơng thức này là các hàm bao quanh insert_all
, insert_all!
, upsert_all
, tuơng ứng như vậy, chúng cũng có phuơng thức hoạt động tuơng tự nhau.
-
insert
: được sử dụng để chèn một bản ghi duy nhất vào cơ sở dữ liệu. Nếu bản ghi đó bị lỗi, trùng lặp về khóa ràng buộc, thì nó sẽ bỏ qua việc thực hiện chèn bản ghi đó vào cơ sở dữ liệu mà không đưa ra bất kỳ một ngoại lệ nào. -
insert!
: phương thức này cũng cho phép chèn một bản ghi vào cơ sở dữ liệu, nhưng sẽ đưa ra một thông điệp lỗi tới người phát triểnActiveRecord::RecordNotUnique
nếu bản ghi đó bị lỗi, trùng lặp về khóa ràng buộc. -
upsert
: phương thức chèn hoặc cập nhật một duy nhất vào cơ sở dữ liệu tương tự như cách upsert_all hoạt động.
Xem qua một số ví dụ sau:
Article.insert({ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, unique_by: :slug)
# is same as
Article.insert_all([{ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }], unique_by: :slug)
Article.insert!({ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, returning: %w[ id title ])
# is same as
Article.insert_all!([{ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }], returning: %w[ id title ])
Article.upsert({ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, unique_by: :slug, returning: %w[ id title ])
# is same as
Article.upsert_all([{ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }], unique_by: :slug, returning: %w[ id title ])
Truncate Database
Thực hiện lệnh dưới đây, đồng nghĩa với việc xóa tất cả các bảng trong cơ sở dữ liệu của bạn, và bạn có thể tiến hành việc thêm mới sau đó.
rails db:truncate_all
Delete_by and destroy_by
Rails cung cấp các phuơng thức như find_by, find_or_initialize_by và find_or_create_by để tìm kiếm, khởi tạo, và tạo mới bản ghi dựa trên các điều kiện đã có. Còn những phương thức để tự xóa hoặc hủy các bản ghi thì không có sẵn.
Và Rails 6 đã bổ sung hai phuơng thức delete_by
và destroy_by
để ActiveRecord::Relation
có thể xóa hoặc hủy tất cả các bản ghi phù hợp với điều kiện yêu cầu.
Nếu như trước đây, chúng ta thực hiện việc đó bằng những câu lệnh như
User.where(is_active: false).delete_all
User.where(is_active: false).destroy_all
thì giờ đây, ta đã có các phương thức tiện lợi hơn để thực hiện điều tuơng tự
User.delete_by(is_active: false)
User.destroy_by(is_active: false)
Action Text
action_text
có nội dung văn bản phong phú và chỉnh sửa được trong Rails.
Cài đặt có thể thực hiện: chạy dòng lệnh
rails action_text:install
để thêm vào gói Yarn
Thêm rich text vào model hiện có
# app/models/message.rb
class Message < ApplicationRecord
has_rich_text :content
end
Và ở view, ta đã có thể sử dụng nó với biểu mẫu form
<%# app/views/messages/_form.html.erb %>
<%= form_with(model: message) do |form| %>
<div class="field">
<%= form.label :content %>
<%= form.rich_text_area :content %>
</div>
<% end %>
Và kết quả thu đuợc trên trang
<%= @message.content %>
Kết luận: Rails 6 được phát hành và cung cấp những cải tiến, trong đó, có những tính năng nổi bật nhằm tiết kiệm rất nhiều thời gian trong giai đoạn phát triển cũng như cải thiện trong vấn để về bảo mật.
Tài liệu tham khảo: Rails 6 Features: What's New and Why It Matters
All rights reserved