Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

แต่ละ... หรืออย่างอื่น

ฉันชอบ each แต่ฉันมีปัญหากับมัน จะเกิดอะไรขึ้นเมื่อคุณมีคอลเล็กชันที่ว่างเปล่า

หากคุณเรียก [].each จะไม่มีอะไรเกิดขึ้นและ [] จะถูกส่งกลับ บางครั้งนั่นคือสิ่งที่คุณต้องการ แต่บ่อยครั้งกว่านั้น โดยเฉพาะอย่างยิ่งเมื่อคุณสร้าง UI คุณจะต้องจัดการรายการว่างด้วยวิธีพิเศษ เช่น ฉันมักจะต้องการแสดงข้อความอื่นเมื่อไม่มีข้อมูล

แต่เนื่องจาก [].each ส่งกลับ [] ไม่ใช่ nil คุณกำลังเขียนสิ่งนี้อยู่:

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 -%>

ใช้งานได้ แต่รู้สึกอึดอัด ฉันอยากจะพูดว่า "ทำสิ่งนี้กับแต่ละรายการในคอลเล็กชันนี้ เว้นแต่จะไม่มีอะไรอยู่ในนั้น ในกรณีนี้ให้ทำอย่างอื่นทั้งหมด" ฉันต้องการบางอย่างเช่น each ด้วย “หรืออย่างอื่น”

Rendering Rails Collections

ในมุมมองของคุณ Rails ช่วยคุณได้ การแสดงคอลเลกชั่นของสิ่งต่าง ๆ นั้นยอดเยี่ยม:

app/views/users/index.html.erb
<%= render @users %>
app/views/users/_user.html.erb
<p><%= user.name %></p>

เมื่อ render ถูกส่งผ่าน @users มันแสดงผล _user.html.erb หนึ่งครั้งสำหรับผู้ใช้แต่ละคนใน @users . คุณสามารถข้าม each โดยสิ้นเชิง

เป็นโบนัส ถ้า @users ว่างเปล่า render คืนค่า nil อย่างที่เราต้องการ! ดังนั้นคุณจึงสามารถเขียนสิ่งนี้ และรับผลลัพธ์เหมือนกับเวอร์ชันดั้งเดิม:

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>

ตรงไปตรงมามากขึ้น เมื่อคุณเข้าใจแบบแผนของ Rails แล้ว

สิ่งที่อยู่นอกมุมมองคืออะไร

หากคุณติดตาม Rails render ด้วยคอลเล็กชันเป็นวิธีที่รวดเร็วและมีประสิทธิภาพในการแสดงคอลเล็กชันของออบเจ็กต์

แต่บางครั้งคุณอาจไม่ต้องการจัดการกับส่วนเพิ่มเติมในการแสดงผลแต่ละรายการ หรือ render จะไม่สนับสนุนการออกแบบของคุณ หรือคุณจะไม่อยู่ในมุมมองด้วยซ้ำ

ทางออกที่ดีที่สุดที่ฉันพบคือ presence .

list.presence เหมือนกับ:

if list.present?
  list
else
  nil
end

นั่นคือ คุณจะได้รับรายการกลับมาหากมีอะไรอยู่ในนั้น และ nil ถ้าว่าง

ด้วย presence , คุณสามารถเขียน:

@users.each do |user|
  puts user.name
end.presence || puts("You don't have any users.")

สิ่งนี้จะพิมพ์ชื่อแต่ละชื่อหากมีผู้ใช้ใน @users หรือ You don't have any users อย่างอื่น

ถึงกระนั้นฉันก็ทำได้โดยไม่มี presence . รู้สึกเหมือนแฮ็คเพราะมันเป็นหนึ่ง หากได้รับการสนับสนุน สิ่งที่ดีกว่านี้:

@users.each do |user|
  puts user.name
end || puts("You don't have any users.")

หรือ Smalltalk-ish:

@users.each(if_empty: lambda { puts "You don't have any users." }) do |user|
  puts user.name
end

หรือแม้กระทั่ง (อ้าปากค้าง!):

for user in @users
  puts user.name
else
  puts "You don't have any users."
end

แต่สำหรับตอนนี้ฉันมักจะไปกับ presence หรือ if blank?; else each รูปแบบ

คุณคิดว่าแบบไหนดีกว่ากัน? คุณจัดการกับรายการว่างได้อย่างไร? คุณพบวิธีที่ดีกว่าหรือไม่? ถ้าเป็นเช่นนั้นบอกฉัน!