raylar kısmi şablonlarında isteğe bağlı yerel değişkenler: (tanımlı? foo) karışıklıktan nasıl çıkarım?


225

Ben kötü bir çocuk oldum ve bir değer açıkça tanımlanmamışsa yerel değişkenler için varsayılan değerleri ayarlamak için kısmi şablonlarda aşağıdaki sözdizimini kullandım: kısmi işlerken locals hash -

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

Geçtiğimiz değişkenler (tanımlanamadığım için) geçmeyen değişkenlerin nil olarak tanımlanmış gibi (tanımsız yerine) davranmaya başladığı zamana kadar bu işe yaramış gibi görünüyordu.

Böylece çeşitli yararlı insanlar tarafından işaret edilmiş, http://api.rubyonrails.org/classes/ActionView/Base.html diyor değil kullanımına

defined? foo

bunun yerine kullanmak

local_assigns.has_key? :foo

Yollarımı değiştirmeye çalışıyorum, ancak bu birçok şablonu değiştirmek anlamına geliyor.

Önceden ücret alabilir ve bu şablonu tüm şablonlarda yapabilir miyim? İzlemem gereken bir hile var mı? Her birini test etmek için ne kadar özenle ihtiyacım var?

Yanıtlar:


324

Bunu yapıyorum:

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

1
Hgimenez'in önerisinin (yukarıda) kompakt sözdizimini gerçekten sevmeme rağmen, bu yaklaşımın çok net olma avantajı var: neler oluyor. (Yine de yerel için bir değer olarak nil geçmesine izin
vermeme dezavantajı vardır

1
Nil geçmek istemek için ne kullanıyorsun?
Ocak'ta jonnii

Aklımda özel bir durum yok. Sadece tüm sonuçları anlamaya çalışıyorum. Bu bana bu yanıtı kabul etmemi hatırlattı :-)
brahn

4
Nil sorunu aşmak için , OP bağlantı ( api.rubyonrails.org/classes/ActionView/Base.html ) <% if local_assigns.has_key? : headline%> Headline: <% = headline%> <% end%> - has_key sıfır / yanlış durumundan kaçınır ve muhtemelen buradaki yanıt gibi bir satıra kısaltılabilir
Phil

5
Lütfen Pablo'nun cevabını kontrol edin: local_assigns.fetchnil değeri olan anahtarları bile mükemmel şekilde işler. Yalnızca anahtar hiç ayarlanmamışsa varsayılan değeri döndürür .
quetzalcoatl

158

Yana local_assignsbir karma, sen de kullanabilirsiniz getirme İsteğe ile default_value.

local_assigns.fetch :foo, default_value

Bu dönecektir default_valueeğer fooayarlanmadı.

UYARI:

local_assigns.fetch :foo, default_valueNe zaman default_valuebir yöntem olduğu konusunda dikkatli olun , çünkü sonucunu geçmek için yine de çağırılacaktır fetch.

Eğer default_valuebir yöntemse, onu bir bloğa sarabilirsiniz: local_assigns.fetch(:foo) { default_value }gerekmediğinde çağrısını önlemek için.


1
Açıkça söylemeye değer: nildeğerler burada korunur. Karma içeriyorsa :fooeşleştirilmiş nil, o fetchda dönecektir nil. Yani, en azından v1.9.3'ümde. 1.8'in nasıl davrandığını hatırlamıyorum.
quetzalcoatl

Bu tamamen doğru. Bana sorun hatırlıyor local_assigns[:foo] || default_value, foo bir falsy değeri döndürdüğünde, default_valuebunun yerine kullanılacak. @some_value ||= expensive_methodMetot bir falsy değeri döndürürse , genellikle Memoization için bir sorundur , her zaman yürütülür.
Pablo Cantero

1
Bunun neden en iyi cevap olduğunu anlamayan kimse yeterince uzun süre yakut kullanmamıştır. Bravo Pablo!
mastaBlasta

2
Bir optimizasyon aşağıdaki gibidir, böylece bunu değişkenin her kullanımında 'getirme koruyucusu' kullanmak yerine şablonunuzun üst kısmında yalnızca bir kez çağırmanız gerekir. foo ||= local_assigns[:foo] = local_assigns.fetch(:foo, default_value)
sethcall

Neden işe yaramadığını merak ediyordum, ben de değişkeni yarattığını varsaydım, ama yine de döndürülen değeri kullanmak zorundayız:foo = local_assigns.fetch :foo, true
Vadorequest

84

Peki ya

<% foo ||= default_value %>

Bu "kullanım diyor foonil veya doğru değilse. Aksi atamak default_valuefoo için"


2
Yerliler karma yoluyla geçirilen sürece foo tanımlanmadığından emin değilim.
Ocak'ta jonnii

1
Bu işe yarar, ancak bunun gibi varsayılan değerleriniz varsa, belki de bir yardımcı kullanmanız gerektiğinin bir işaretidir?
psyho

2
Burada sihir yok. Konuyla ilgili daha fazla kaynak: groups.google.com/group/comp.lang.ruby/browse_thread/thread/…
hgmnz

37
Sözdizimi çok kompakt olduğu için bu sürümü gerçekten çok seviyorum. Büyük dezavantajı, varsayılan olarak üzerine yazılacağından yerel için bir değer olarak nil veya false iletemeyeceğiniz anlamına gelir.
brahn

16
@brahn, bu iyi bir nokta. Aslında, eğer foobir boolean ise bundan kaçınılmalıdır . Haklı olarak değerine sahip olabilir falseve default_valueyanlışlıkla geçersiz kılınabilir .
hgmnz

10

Bunun burada tekrarlanması gerektiğini düşünüyorum ( http://api.rubyonrails.org/classes/ActionView/Base.html adresinden ):

Belirli bir yerel değişkene belirli bir oluşturma çağrısında bir değer atanıp atanmadığını öğrenmeniz gerekiyorsa, aşağıdaki kalıbı kullanmanız gerekir:

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

Tanımlanan kullanarak test? başlık çalışmaz. Bu bir uygulama kısıtlamasıdır.


6

Benim durumumda kullanıyorum:

<% variable ||= "" %>

benim kısmi.
Bunun iyi olup olmadığı hakkında bir fikrim yok ama benim için sorun yok


Bu aslında çok iyi çalışıyor. Tanımsız ve nilkısmi çağrıda yerel olarak geçerken çalışır .
Joshua Pinter

3
Ah, aşağıda okumak, eğer variablebir boolean ise ve bunu ayarlamanız gerekiyorsa başarısız olacaktır false. Değeri kullanmak yerine varsayılan değeri kullanır false. KENDİ RİSKİNİZDE KULLANIN.
Joshua Pinter

5

Eski bir iş parçacığı olduğunu biliyorum ama işte benim küçük katkı: kısmi içinde local_assigns[:foo].presencebir koşullu kullanmak istiyorum . Sonra foosadece render çağrısında gerektiğinde ayarlayın :

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

Burada resmi Rails kılavuzuna bir göz atın . RoR 3.1.0'dan geçerlidir.


Ben arasında herhangi gerçek bir fark göremiyorum local_assigns[:foo]ve local_assigns[:foo].presence. nilAnahtar karma içinde yoksa ya da varsa değer döndürülür .
jamesmarkcook

1

Birden fazla varsayılan değişken için izin veren daha iyi bir seçenek düşünüyorum:

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

Bu Pablo'nun cevabının bir türevidir. Bu bir varsayılan ('tam') belirlememe izin veriyor ve sonunda, 'mod' hem local_assigns hem de gerçek bir yerel değişkende ayarlanıyor.

haml / ince:

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

erb:

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

0

Daha sezgisel ve kompakt:

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


3
Sana kısmi ararsanız bu başarısız olacağını düşünüyorum:locals => {:some_local => false}
brahn

0

Yerel değişkeni her aradığınızda kısmi olarak geçmek istemiyorsanız bunu yaparsınız:

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

Bu şekilde undefined variablehatayı önlersiniz . Bu, kısmi yerel değişkenli / değişkensiz aramanızı sağlar.


VEYA local_param = tanımlanmışsa local_param? (Local_param)
Kinaan Khan Sherwani

0

Yakut 2.5

Erb

Mümkün, ancak kapsamdaki varsayılan değerlerinizi bildirmeniz gerekir.

Değiştirme için kelimeyi DEĞİŞTİRİN .

# 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

Aşağıdaki gibi görünecek bir yardımcı oluşturulabilir:

somearg = opt(:somearg) { :defaultvalue }

Gibi uygulanır:

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

Nasıl ve neden hakkında ayrıntılar için bloguma bakın .

Bu çözümün, geçersiz kılınmadan değer olarak nil veya false iletmenize izin verdiğini unutmayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.