Tôi yêu each
, nhưng tôi có một vấn đề với nó. Điều gì xảy ra khi bạn có một bộ sưu tập trống?
Nếu bạn gọi [].each
, sẽ không có gì xảy ra và []
sẽ được trả lại. Đôi khi, đó là những gì bạn muốn. Nhưng thường xuyên hơn, đặc biệt là khi bạn đang xây dựng giao diện người dùng, bạn sẽ muốn xử lý các danh sách trống theo một cách đặc biệt. Ví dụ:tôi thường muốn hiển thị một thông báo khác khi tôi không có bất kỳ dữ liệu nào.
Nhưng kể từ [].each
trả về []
, không phải nil
, bạn đang gặp khó khăn khi viết một cái gì đó như thế này:
<% if @users.empty? -%>
<p>You don't have any users. <%= link_to "Add one!", new_user_path %></p>
<% else -%>
<% @users.each do |user| -%>
<p><%= user.name %></p>
<% end -%>
<% end -%>
Điều đó hiệu quả, nhưng nó cảm thấy khó xử. Tôi muốn nói:“Làm điều này với từng mục trong bộ sưu tập này, trừ khi không có gì trong đó, trong trường hợp đó, hãy làm điều này hoàn toàn khác”. Tôi muốn một cái gì đó giống như each
, với “hoặc khác.”
Rendering Rails Collections
Bên trong chế độ xem của bạn, Rails có thể trợ giúp. Thật tuyệt khi hiển thị các bộ sưu tập của mọi thứ:
<%= render @users %>
<p><%= user.name %></p>
Khi render
được chuyển @users
, nó hiển thị _user.html.erb
một lần cho mỗi người dùng bên trong @users
. Bạn có thể bỏ qua each
hoàn toàn.
Như một phần thưởng, nếu @users
trống, render
trả về nil
, giống như chúng tôi muốn! Vì vậy, bạn có thể viết cái này và nhận được kết quả giống như phiên bản gốc:
<%= render(@users) || render('empty') %>
<p><%= user.name %></p>
<p>You don't have any users. <%= link_to "Add one!", new_user_path %></p>
Nó trực tiếp hơn rất nhiều, khi bạn hiểu các quy ước của Rails.
Bên ngoài chế độ xem thì sao?
Nếu bạn làm theo Rails, hãy render
với một bộ sưu tập là một cách nhanh chóng và mạnh mẽ để hiển thị các bộ sưu tập các đối tượng.
Nhưng đôi khi bạn sẽ không muốn xử lý thêm một phần để hiển thị từng mục. Hoặc render
sẽ không hỗ trợ thiết kế của bạn. Hoặc bạn thậm chí sẽ không ở bên trong một chế độ xem.
Giải pháp tốt nhất mà tôi tìm thấy cho đến nay là presence
.
list.presence
giống như:
if list.present?
list
else
nil
end
Tức là, bạn sẽ lấy lại danh sách nếu nó có bất kỳ thứ gì trong đó và nil
nếu nó trống.
Với sự hiện diện của presence
, bạn có thể viết:
@users.each do |user|
puts user.name
end.presence || puts("You don't have any users.")
Điều này sẽ in từng tên nếu có người dùng trong @users
hoặc You don't have any users
mặt khác.
Tuy nhiên, tôi vẫn có thể làm được mà không có presence
. Nó giống như một cuộc tấn công, bởi vì nó là một. Nếu nó được hỗ trợ, một cái gì đó như thế này có thể tốt hơn:
@users.each do |user|
puts user.name
end || puts("You don't have any users.")
hoặc Smalltalk-ish:
@users.each(if_empty: lambda { puts "You don't have any users." }) do |user|
puts user.name
end
hoặc thậm chí (thở hổn hển!):
for user in @users
puts user.name
else
puts "You don't have any users."
end
Tuy nhiên, hiện tại, tôi thường chỉ sử dụng presence
hoặc if blank?; else each
mẫu.
Bạn nghĩ cái nào tốt hơn? Làm thế nào để bạn xử lý danh sách trống? Bạn đã tìm ra cách tốt hơn chưa? Nếu vậy, hãy cho tôi biết về điều đó!