Tuần trước, tại RailsConf 2017, Rails 5.1 phát hành.
Nếu theo dõi thông báo, bạn đã thấy các feature lớn: tích hợp JavaScript hiện đại tốt hơn, encrypted secrets, system tests. Và feature yêu thích cá nhân: cuối cùng loại bỏ combo lạ form_for và form_tag, thay bằng form_with. Rất mong được thử.
Nhưng lý do tôi yêu Rails không phải feature lớn. Là những cải tiến nhỏ, liên tục. Những quality-of-life changes khiến tôi hạnh phúc hơn khi viết Rails app. Rails 5.1 đầy rẫy chúng.
Tag helpers nhất quán hơn
Đã dùng Rails tag helpers như tag và content_tag?
<%= content_tag :p, @user.name, class: "name" %>
Rails 5.1 thêm cú pháp tag helper mới.
Dùng tag.div hoặc tag.br, không còn lo thứ tự tham số và hai method khác nhau:
<%= tag.p @user.name, class: "name" %>
<%= tag.br %>
Tag helper mới hỗ trợ HTML5 mặc định, và cho tạo custom element:
<%= tag.pea @user.name, class: "name" %>
<!-- thành <pea class="name">Justin Weiss</pea> -->
Assert hơn chỉ sự khác biệt (assert_changes)
Tôi thích assert_difference. Trước assert_difference, tôi mất quá nhiều thời gian quản lý biến local trong test:
old_score = @user.score
@user.answer_question!(...)
assert_equal old_score + 10, @user.score
Với assert_difference, rõ ràng hơn ý định:
assert_difference "@user.score", 10 do
@user.answer_question!(...)
end
Rails 5.1, assert_changes tiến xa hơn.
assert_difference chỉ check thay đổi count. Nhưng assert_changes check thay đổi non-numerical: string, nil -> value, v.v.:
assert_changes "users(:justin).name", from: "Justin", to: "Bob" do
@user.update_attributes(name: "Bob")
end
Thay string, có thể cho lambda:
assert_changes -> { users(:justin).name }, from: "Justin", to: "Bob" do
@user.update_attributes(name: "Bob")
end
to: chấp nhận bất cứ gì so sánh bằng ===. Tiện khi biết có gì đó về giá trị nhưng không biết chính xác:
assert_changes -> { users(:justin).updated_at }, to: ActiveSupport::TimeWithZone do
@user.update_attributes(name: "Bob")
end
Delegate mọi thứ (delegate_missing_to)
Trong Rails code, thấy method delegate. Delegation hữu ích khi muốn thêm behavior lên class khác mà không inherit:
class Player
delegate :id, :name, to: :@user
def initialize(user)
@user = user
end
def points
Game.points_for_user(user.id)
end
end
Nhưng đôi khi muốn forward tất cả sang class wrap.
Có vài cách làm với Ruby: method_missing hoặc SimpleDelegator. Để phù hợp hơn với delegate, delegate_missing_to được thêm vào Rails 5.1. Nó làm đúng như tên: method không có trong Player sẽ tìm trên @user.
class Player
delegate_missing_to :@user
def initialize(user)
@user = user
end
def points
Game.points_for_user(user.id)
end
end
Bonus: alias_method_chain đã biến mất!
Một feature yêu thích Ruby 2 là Module#prepend. Rất thích, viết bài hy vọng nó thay thế alias_method_chain.
Tính đến Rails 5.1, alias_method_chain chính thức bị loại - thay bằng prepend.
Phiên bản Rails mới luôn thú vị. Nhưng chi tiết mới tạo nên vẻ đẹp của Rails. Những thay đổi nhỏ khiến bạn hạnh phúc hơn với code hàng ngày.
Làm sao tìm ra những thay đổi đó? Đọc changelogs. Xem pull requests thú vị. Xem feature nhỏ 5.1 nào làm cuộc đời bạn dễ dàng hơn.
Và khi tìm ra điều hay, đừng giữ riêng. Chia sẻ ở đây để cùng học!