ตัวแปรเฉพาะที่เป็นตัวเลือกใน Rails เทมเพลตบางส่วน: ฉันจะออกจากระเบียบ (กำหนด? foo) ได้อย่างไร?


225

ฉันเป็นเด็กเลวและใช้ไวยากรณ์ต่อไปนี้ในแม่แบบบางส่วนของฉันเพื่อตั้งค่าเริ่มต้นสำหรับตัวแปรท้องถิ่นหากค่าไม่ได้กำหนดไว้อย่างชัดเจนใน: hash locals เมื่อแสดงบางส่วน -

<% foo = default_value unless (defined? foo) %>

สิ่งนี้ดูเหมือนว่าจะทำงานได้ดีจนกระทั่งเมื่อไม่นานมานี้เมื่อ (โดยไม่มีเหตุผลที่ฉันสามารถแยกแยะได้) ตัวแปรที่ไม่ผ่านก็เริ่มทำตัวราวกับว่าพวกมันถูกกำหนดเป็นศูนย์ (แทนที่จะไม่ได้กำหนด)

ตามที่ได้รับการชี้ให้เห็นจากคนที่เป็นประโยชน์มากมายใน SO http://api.rubyonrails.org/classes/ActionView/Base.htmlกล่าวว่าห้ามใช้

defined? foo

และแทนที่จะใช้

local_assigns.has_key? :foo

ฉันพยายามแก้ไขวิธีการของฉัน แต่นั่นหมายถึงการเปลี่ยนเทมเพลตจำนวนมาก

ฉันสามารถ / ควรชาร์จล่วงหน้าและทำการเปลี่ยนแปลงในแม่แบบทั้งหมดหรือไม่ มีความยุ่งยากใด ๆ ที่ฉันต้องระวังหรือไม่? ฉันจะต้องทดสอบแต่ละคนอย่างขยันขันแข็งแค่ไหน?

คำตอบ:


324

ฉันทำนี่:

<% some_local = default_value if local_assigns[:some_local].nil? %>

1
แม้ว่าฉันจะชอบรูปแบบกะทัดรัดของคำแนะนำของ hgimenez (ด้านบน) แต่วิธีการนี้มีข้อได้เปรียบที่ชัดเจนอีกครั้ง: เกิดอะไรขึ้น (ยังมีข้อเสียของการไม่ให้คุณผ่านศูนย์เป็นค่าสำหรับท้องถิ่น)
brahn

1
กรณีการใช้งานของคุณต้องการส่งผ่านศูนย์อะไร
jonnii

โอ้ฉันไม่มีกรณีเฉพาะในใจ แค่พยายามเข้าใจนัยยะทั้งหมด สิ่งนี้เตือนให้ฉันยอมรับคำตอบนี้ :-)
brahn

4
เพื่อแก้ไขปัญหานี้ฉันกำลังคัดลอกรหัสจากลิงก์ของ OP ( api.rubyonrails.org/classes/ActionView/Base.html ) <% ถ้า local_assigns.has_key? : พาดหัว%> หัวข้อเรื่อง: <% = พาดหัว%> <% สิ้น%> - has_key หลีกเลี่ยงการศูนย์ / สถานการณ์ที่ผิดพลาดและอาจจะสามารถลงไปหนึ่งบรรทัดเช่นคำตอบที่นี่
ฟิล

5
โปรดตรวจสอบคำตอบของ Pablo: local_assigns.fetchจัดการปุ่มได้อย่างสมบูรณ์แบบด้วยค่าศูนย์ มันจะส่งกลับค่าเริ่มต้นเฉพาะในกรณีที่ไม่ได้ตั้งค่าคีย์เลย
quetzalcoatl

158

ตั้งแต่ local_assignsเป็นกัญชาคุณยังสามารถใช้ดึงข้อมูลdefault_valueที่มีตัว

local_assigns.fetch :foo, default_value

สิ่งนี้จะส่งคืนdefault_valueถ้าfooไม่ได้ตั้งค่าไว้

คำเตือน:

ระวังด้วย local_assigns.fetch :foo, default_valueเมื่อdefault_valueเป็นวิธีการที่มันจะถูกเรียกว่าต่อไปเพื่อที่จะส่งผลให้fetchเป็นวิธีการตามที่มันจะถูกเรียกว่าอยู่แล้วเพื่อที่จะผ่านผลในการ

หากdefault_valueเป็นวิธีการของคุณคุณสามารถปิดมันในบล็อก: local_assigns.fetch(:foo) { default_value }เพื่อป้องกันการโทรเมื่อไม่จำเป็น


1
มันคุ้มที่จะบอกว่ามันชัดเจน: nilค่าจะถูกเก็บไว้ที่นี่ หากกัญชามี:fooแมปไปnilแล้วก็จะกลับfetch nilนั่นคืออย่างน้อยใน v1.9.3 ของฉัน ฉันจำไม่ได้ว่า 1.8 ประพฤติตนอย่างไร
quetzalcoatl

ถูกต้องทั้งหมด มันทำให้ฉันนึกถึงปัญหาlocal_assigns[:foo] || default_valueเมื่อ foo คืนค่าเท็จdefault_valueจะถูกใช้แทน โดยปกติจะเป็นปัญหาสำหรับการบันทึก@some_value ||= expensive_methodหากวิธีการส่งคืนค่าเท็จมันจะถูกดำเนินการเสมอ
Pablo Cantero

1
ใครก็ตามที่ไม่เข้าใจว่าทำไมคำตอบที่ดีที่สุดนี้ไม่ได้ใช้ทับทิมนานพอ Bravo Pablo!
mastaBlasta

2
การเพิ่มประสิทธิภาพมีดังต่อไปนี้ดังนั้นคุณจะต้องเรียกสิ่งนี้เพียงครั้งเดียวที่ด้านบนสุดของเทมเพลตของคุณแทนที่จะใช้ 'fetch Guard' ในทุกการใช้งานของตัวแปร foo ||= local_assigns[:foo] = local_assigns.fetch(:foo, default_value)
sethcall

ฉันสงสัยว่าทำไมมันใช้งานไม่ได้ฉันคิดว่ามันสร้างตัวแปรเช่นกัน แต่เรายังต้องใช้ค่าที่ส่งคืน:foo = local_assigns.fetch :foo, true
Vadorequest

84

เกี่ยวกับ

<% foo ||= default_value %>

สิ่งนี้บอกว่า "ใช้fooถ้าไม่เป็นศูนย์หรือจริงมิฉะนั้นให้กำหนดให้default_valueกับ foo"


2
ฉันไม่แน่ใจว่าสิ่งนี้ทำงานได้เพราะไม่ได้กำหนด foo เว้นแต่ว่าจะมีการส่งผ่านแฮชท้องถิ่น
jonnii

1
ใช้งานได้ แต่ถ้าคุณมีค่าเริ่มต้นเช่นนี้อาจเป็นสัญญาณว่าคุณควรใช้ผู้ช่วยหรือไม่?
psyho

2
ไม่มีเวทย์มนตร์ที่นี่ แหล่งข้อมูลเพิ่มเติมเกี่ยวกับหัวเรื่อง: groups.google.com/group/comp.lang.ruby/browse_thread/thread/…
hgmnz

37
ฉันชอบรุ่นนี้มากเพราะมีขนาดเล็กมาก ฉันคิดว่าข้อเสียใหญ่คือมันหมายความว่าคุณไม่สามารถผ่านศูนย์หรือเท็จเป็นค่าสำหรับท้องถิ่นแม้ว่ามันจะถูกเขียนทับโดยค่าเริ่มต้น
brahn

16
@Brahn นั่นเป็นจุดที่ดี อันที่จริงควรหลีกเลี่ยงหากfooเป็นบูลีน มันอาจมีคุณค่าอย่างถูกต้องfalseและถูกแทนที่โดยdefault_valueบังเอิญ
hgmnz

10

ฉันคิดว่าควรทำซ้ำที่นี่ (จากhttp://api.rubyonrails.org/classes/ActionView/Base.html ):

หากคุณต้องการตรวจสอบว่าตัวแปรท้องถิ่นบางตัวได้รับการกำหนดค่าในการเรียกใช้การเรนเดอร์เฉพาะหรือไม่คุณต้องใช้รูปแบบต่อไปนี้:

<% if local_assigns.has_key? :headline %>
  Headline: <%= headline %>
<% end %>

การทดสอบโดยใช้ที่กำหนดไว้? หัวเรื่องจะไม่ทำงาน นี่เป็นข้อ จำกัด ในการใช้งาน


6

ในกรณีของฉันฉันใช้:

<% variable ||= "" %>

ในส่วนของฉัน
ฉันไม่รู้ว่ามันดี แต่สำหรับฉันก็โอเค


มันใช้งานได้ดีทีเดียว ทำงานเพื่อไม่ได้กำหนดและเมื่อผ่านnilเป็นท้องถิ่นในการโทรบางส่วนเช่นกัน
Joshua Pinter

3
อาอ่านลงมาด้านล่างนี้จะล้มเหลวถ้าเป็นแบบบูลและคุณจำเป็นต้องตั้งค่าให้variable falseมันจะใช้ค่าเริ่มต้นแทนการใช้falseค่า ใช้ความเสี่ยงของคุณเอง
Joshua Pinter

5

ฉันรู้ว่ามันเป็นเธรดเก่า แต่นี่คือส่วนเล็ก ๆ ของฉัน: ฉันจะใช้local_assigns[:foo].presenceในเงื่อนไขภายในบางส่วน จากนั้นฉันตั้งค่าfooเมื่อจำเป็นในการเรียกแสดงผล:

<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>

มีลักษณะที่เต้อย่างเป็นทางการคู่มือรางที่นี่ ถูกต้องจาก RoR 3.1.0


ฉันไม่สามารถเห็นความแตกต่างที่แท้จริงใด ๆ ระหว่างและlocal_assigns[:foo] local_assigns[:foo].presenceจะส่งคืนค่าใดค่าหนึ่งnilหากไม่มีคีย์ในแฮชและค่าหากมีอยู่
jamesmarkcook

1

ฉันคิดว่าเป็นตัวเลือกที่ดีกว่าที่ช่วยให้ตัวแปรเริ่มต้นหลายตัว:

<% options = local_assigns.reverse_merge(:include_css => true, :include_js => true) %>
<%= include_stylesheets :national_header_css if options[:include_css] %>
<%= include_javascripts :national_header_js if options[:include_js] %>

1

นี่คืออนุพันธ์ของคำตอบของ Pablo สิ่งนี้ทำให้ฉันสามารถตั้งค่าเริ่มต้น ('เต็ม') และในท้ายที่สุด 'โหมด' ถูกตั้งค่าใน local_assigns และตัวแปรท้องถิ่นที่แท้จริง

haml / บาง:

- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full')

Erb:

<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full') %>

0

ใช้งานง่ายและกะทัดรัดมากขึ้น:

<% some_local = default_value unless local_assigns[:some_local] %>


3
ฉันคิดว่าสิ่งนี้จะล้มเหลวถ้าคุณโทรหาบางส่วนด้วย:locals => {:some_local => false}
brahn

0

หากคุณไม่ต้องการส่งตัวแปรท้องถิ่นไปยังบางส่วนในแต่ละครั้งที่คุณเรียกมันว่าคุณทำสิ่งนี้:

<% local_param = defined?(local_param) ? local_param : nil %>

วิธีนี้คุณหลีกเลี่ยงundefined variableข้อผิดพลาด สิ่งนี้จะช่วยให้คุณสามารถเรียกบางส่วนของคุณด้วย / ไม่มีตัวแปรท้องถิ่น


หรือ local_param = local_param หากกำหนดไว้? (local_param)
Kinaan Khan Sherwani

0

ทับทิม 2.5

Erb

เป็นไปได้ แต่คุณต้องประกาศค่าเริ่มต้นของคุณในขอบเขต

ความหลากหลายของคำสำหรับการทดแทน

# index.html.erb
...
<%= render 'some_content', VARIABLE: false %>
...

# _some_content.html.erb
...
<% VARIABLE = true if local_assigns[:VARIABLE].nil? %>
<% if VARIABLE %>
    <h1>Do you see me?</h1>
<% end %>
...

-6

ผู้ช่วยสามารถสร้างให้มีลักษณะดังนี้:

somearg = opt(:somearg) { :defaultvalue }

ดำเนินการเช่น:

module OptHelper
  def opt(name, &block)
    was_assigned, value = eval(
      "[ local_assigns.has_key?(:#{name}), local_assigns[:#{name}] ]", 
      block.binding)
    if was_assigned
      value
    else
      yield
    end
  end
end

ดูบล็อกของฉันสำหรับรายละเอียดเกี่ยวกับวิธีการและเหตุผล

โปรดทราบว่าการแก้ปัญหานี้ช่วยให้คุณสามารถผ่านศูนย์หรือเท็จเป็นค่าโดยไม่ต้องถูกแทนที่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.