Computer >> Máy Tính >  >> Lập trình >> Ruby

Mỗi ... Hoặc Khác

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:

app / views / users / index.html.erb
<% 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ứ:

app / views / users / index.html.erb
<%= render @users %>
app / views / users / _user.html.erb
<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:

app / views / users / index.html.erb
<%= render(@users) || render('empty') %>
app / views / users / _user.html.erb
<p><%= user.name %></p>
app / views / users / _empty.html.erb
<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 đó!