-1

Rails 6 có gì mới?

Rails 6 đã được release và nó được tích hợp nhiều tính năng rất có lợi cho các ứng dụng kể cả lớn lẫn nhỏ, có vẻ như rất nhiều cải thiện về tốc độ cũng như khả năng mở rộng đã được mang đến trong Rails 6.

Mình đã đọc qua CHANGELOGs từng phần của Rails 6 (ActiveRecord, ActionPack, ActiveSupport, etc.) và chọn ra một vài tính năng mà mình cảm thấy thú vị nhất.


Active Record

Thêm API cơ bản cho việc chuyển đổi kết nối nhằm mục đích hỗ trợ đa cơ sở dữ liệu.

Eileen M. Uchitelle đã trích xuất từ codebase của Github và đưa tính năng tuyệt vời này vào Rails, một giải pháp nhằm chuyển đổi kết nối cơ sở dữ liệu cho một model cụ thể hoặc một query cụ thể. Code của tính năng này là một phần trong pull request sau: https://github.com/rails/rails/pull/34052, nó được viết doc khá là đầy đủ và dễ đọc.

class AnimalsModel < ApplicationRecord
  self.abstract_class = true

  connects_to database: { writing: :animals_primary, reading: :animals_replica }
end

class Dog < AnimalsModel
  # connected to both the animals_primary db for writing and the animals_replica for reading
end

Các truy vấn bị chậm trong job có thể được đọc từ một bản sao của cơ sở dữ liệu bằng một API đơn giản

ActiveRecord::Base.connected_to(database: :slow_replica) do
  SlowReplicaModel.first
end

Còn file database.yml lúc này sẽ cần dài hơn một chút

development:
  primary:
    database: my_primary_db
    user: root
  primary_replica:
    database: my_primary_db
    user: ro_user
    replica: true
  animals:
    database: my_animals_db
    user: root
  animals_replica
    database: my_animals_db
    user: ro_user
    replica: true

Gannon McGibbon sau đó đã thêm vào một chút code nhằm hỗ trợ hash và config url trong database hash của ActiveRecord::Base.connected_to và giúp chúng ta có khả năng viết được đoạn code như sau

User.connected_to(database: { writing: "postgres://foo" }) do
  User.create!(name: "Gannon")
end

config = { "adapter" => "sqlite3", "database" => "db/readonly.sqlite3" }
User.connected_to(database: { reading: config }) do
  User.count
end

Thêm Relation#pick, pluck dành cho các giá trị đơn

Như tiêu đề, dùng pick sẽ tượng tự pluck nhưng dùng cho các giá trị đơn

Person.where(id: 1).pick(:name, :email_address)
# SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
# => ['Tung K', 'nguyen.thanh.tungk@sun-asterisk.com']

Có thể config được các cột được sắp xếp ngầm

Đối với các ứng dụng không sử dụng ID tăng dần, tính năng này thật là quý giá. Bây giờ chúng ta sẽ có thể thiết lập thứ tự của các bản ghi chỉ với một dòng lệnh.

class User < ActiveRecord::Base
  self.implicit_order_column = "created_at"
end 

Action Mailbox

Action mailbox đã được mang đến trong phiên bản thứ sáu của Ruby on Rails, mình chắc rằng sẽ có nhiều bài viết về tính năng này trong tương lai. Action Mailbox cung cấp một bộ công cụ cho phép các ứng dụng có thể tích hợp một cách tốt hơn các luồng emails đến.

Config cơ bản có trong Action Mailbox Basics Rails Guide, có một vài ý tưởng thú vị về tính năng này đó là các cuộc hội thoại sẽ có thể diễn ra tự động trong cả platform và email và có thể hoán đổi cho nhau, ví dụ như comment trên Github từ email, email trợ giúp biến thành ticket...

COMMENTS_REGEX = /^comment\+(.+)@example\.com/i

# app/mailboxes/application_mailbox.rb
class ApplicationMailbox < ActionMailbox::Base
  routing COMMENTS_REGEX => :comments
end

# app/mailboxes/comments_mailbox.rb
class CommentsMailbox < ApplicationMailbox
  def process
    user = User.find_by(email: mail.from)
    post_uuid = COMMENTS_REGEX.match(mail.to)[1]
    
    post = Post.find_by(uuid: post_uuid)
    post.comments.create(user: user, content: mail.body)
  end
end

Chú ý rằng Action Mailbox cần có Active Job và Active Storage và cần một bảng trong database cho nó. Hầu hết tài liệu về các class cũng có sẵn tại ActionMailbox::Base class documentation, ActionMailbox::InboundEmail class documentation và làm việc với email được parse được thực hiện bằng cách sử dụng gem Mail.


Action Text

Action Text chính là Trix editor của Basecamp được đưa vào trong các model của ActiveRecord. Nó cho chúng ta method has_rich_text và chúng ta có thể apply nó vào model mà mình muốn và Action Text sẽ xử lý các việc còn lại. Action Text require ActiveStorage và một số bảng để lưu metadata của nó nên hãy lưu ý rằng bạn sẽ cần phải chuyển sang dùng một ActiveStorage provider mà không lưu trên ổ cứng nếu như ứng dụng của bạn cần có hơn một server.

Tài liệu về tính năng này có trên Rails Guides và nó khá là dễ hiểu.


Action Pack

ActionDispatch::HostAuthorization

Host Authorization là một middleware mới giúp chống lại các cuộc tấn công rebinding DNS (là kiểu tấn công bằng cách tạo các đường link dẫn tới các trang web có chứa mã JS độc hại) bằng cách chỉ ra rõ ràng các hosts có thể gửi request đến.

Theo mặc định, nó được đặt cho tất cả các ứng dụng Rails 6 và cho phép request tới các host sau ở môi trường development IPAddr.new (“0.0.0.0/0”), IPAddr.new (“:: / 0”), “localhost”], config của nó có thể nhận các mảng RegExp, Proc, IPAddrString. Điều này có nghĩa là với Rails 6, chúng ta sẽ cần đặt tên miền của mình một cách rõ ràng trong các file cấu hình môi trường.

Rails.application.config.hosts = [
  IPAddr.new("0.0.0.0/0"), # All IPv4 addresses.
  IPAddr.new("::/0"),      # All IPv6 addresses.
  "localhost"              # The localhost reserved dom
  
Rails.application.config.hosts << "product.com"
  
Rails.application.config.hosts << /.*\.product\.com/

metadata purpose dành cho cookie được sign/encrypt

Rails giờ đây đã có thể ngăn chặn các cuộc tấn công bằng cách sao chép các giá trị đã được sign/encrypt của một cookie này và sử dụng nó làm giá trị của một cookie khác.

Rails có thể làm được như vậy bằng cách lưu trữ tên cookie trong trường purpose rồi sign/encrypt nó cùng với giá trị của cookie. Sau đó, khi được đọc từ phía server, tên cookie sẽ được verify bằng purpose và khi đó các cookie đã bị tấn công sẽ được loại bỏ.

Enable config action_dispatch.use_cookies_with_metadata để sử dụng tính năng này.

Truyền thêm tham số vào các request GET ngầm thông qua #follow_redirect!

Giờ đây chúng ta đã có thể truyền thêm các tham số vào các request GET ngầm bằng cách thêm tham số cho method follow_redirect!.

def create
  # do stuff
  # method that have redirect
  follow_redirect!(params: { user: params[:user_id] })
end

Action View

Thêm allocations vào trong việc phân tích đo đạc render template

Rails 6 sẽ report về việc phân bổ đối tượng được thực hiện trong các views, điều này sẽ cho phép developer biết được lượng thời gian dành cho việc phân bổ và thu thập các đối tượng trong bộ nhớ của các process.

  Rendered posts/_form.html.erb (Duration: 7.1ms | Allocations: 6004)
  Rendered posts/new.html.erb within layouts/application (Duration: 8.3ms | Allocations: 6654)
Completed 200 OK in 858ms (Views: 848.4ms | ActiveRecord: 0.4ms | Allocations: 1539564)

Active Job

Thêm các instrumentation hooks enqueue_retry.active_job, retry_stopped.active_job, và discard.active_job

Rails có một lượng instrumentation hooks rất phong phú được tích hợp vào Active Support và nó dàn trải trên toàn bộ framework.

Nó cho phép bạn lắng nghe các sự kiện xảy ra trong suốt vòng đời của các request, các truy vấn SQL và các Job.

Với việc bổ sung thêm enqueue_retry.active_job, retry_stopped.active_jobdiscard.active_job giúp cho việc phân tích và handle Job dựa trên status của chúng càng trở nên dễ dàng hơn.

Cho phép truyền vào #retry_on và #discard_on nhiều exception

retry_on Errno::ECONNREFUSED, SocketError, Timeout::Error, attempts: 5

Active Model

Cho phép đổi tên thuộc tính khi dùng #has_secure_password

Trước đây, thuộc tính mặc định khi dùng #has_secure_password là 'pasword'

class User < ActiveRecord::Base
  has_secure_password :recovery_password, validations: false
end
user = User.new()
user.recovery_password = "42password"
user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uX..."
user.authenticate_recovery_password('42password') # => user

Active Storage

File upload lên khi được assign vào một record sẽ được lưu vào storage khi record được save thay vì lưu vào storage ngay lập tức

Ở Rails 5.2, files sẽ được lưu ngay lập tức vào storage khi được assign

@user.avatar = params[:avatar]

Giờ đây cơ chế của nó đã chính xác hơn khi chỉ lưu khi @user.save

Dùng gem ImageProcessing cho Active Storage và các biến thể của nó, deprecate MiniMagick

ImageProcessing hỗ trợ một số macro tốt hơn như :resize_to_fit, :resize_to_fill và có tích hợp sẵn libvips thay thế cho ImageMagick.

Việc thay đổi cũng dễ dàng bằng cách cấu hình Rails như thông thường

Rails.application.config.active_storage.variant_processor = :vips

Action Mailer

Thêm MailDeliveryJob, deprecate DeliveryJobParameterized::DeliveryJob

MailDeliveryJob được sử dụng cho cả việc send mail thường và mail được tham số hóa


Zeitwerk

Zeitwerk là một code loader mới cho Ruby. Nó hiệu quả, an toàn cho luồng và phù hợp với cú pháp hằng số của Ruby.

Với một cấu trúc thư mục theo đúng quy tắc, Zeitwerk sẽ load các class và module khi cần, nghĩa là bạn không cần phải viết các lệnh require trong file của mình.

Zeitwerk được mặc định kích hoạt trong Rails 6.

Tuy nhiên, nếu bạn không muốn sử dụng nó, bạn luôn có thể sử dụng loader cũ bằng cách config trong application.rb.

config.autoload = :classic

Source: https://medium.com/rubyinside/whats-coming-to-rails-6-0-8ec79eea66da


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí