2011-09-26 16 views
8

Yani, eğer bir döngü/li etiketlerim varsa, beklediğim gibi olsun .. bu etiketlerin bir dizisi:iç içe content_tags iç html kaçmak .. neden?

(1..5).to_a.map do 
    content_tag(:li) do 
    link_to("boo", "www.boohoo.com") 
    end 
end 

=> ["<li><a href=\"www.boohoo.com\">boo</a></li>", "<li><a href=\"www.boohoo.com\">boo</a></li>", "<li><a href=\"www.boohoo.com\">boo</a></li>", "<li><a href=\"www.boohoo.com\">boo</a></li>", "<li><a href=\"www.boohoo.com\">boo</a></li>"] 

Onlara katılmayı çağırıyorum ve beklenen bir dize aldım ...

(1..5).to_a.map do 
    content_tag(:li) do 
    link_to("boo", "www.boohoo.com") 
    end 
end.join 

=> "<li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li>" 

Bununla birlikte, bir ol etiketinde bu seviyeyi daha derin bir yuvaya yerleştirirsem ...

content_tag(:ol) do 
    (1..5).to_a.map do 
    content_tag(:li) { link_to("boo", "www.boohoo.com") } 
    end.join 
end 

=> "<ol>&lt;li&gt;&lt;a href=&quot;www.boohoo.com&quot;&gt;boo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;www.boohoo.com&quot;&gt;boo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;www.boohoo.com&quot;&gt;boo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;www.boohoo.com&quot;&gt;boo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;www.boohoo.com&quot;&gt;boo&lt;/a&gt;&lt;/li&gt;</ol>" 

İç html deliğinden kaçınıyorum !!!

Raylara baktığınızda

 def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block) 
    if block_given? 
     options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) 
     content_tag_string(name, capture(&block), options, escape) 
    else 
     content_tag_string(name, content_or_options_with_block, options, escape) 
    end 
    end 

    private 

    def content_tag_string(name, content, options, escape = true) 
     tag_options = tag_options(options, escape) if options 
     "<#{name}#{tag_options}>#{escape ? ERB::Util.h(content) : content}</#{name}>".html_safe 
    end 

Sadece aldatıcı bir şekilde yapabildiğim gibi görünüyor: content_tag (: li, nil, nil, false) ve içeriğinden kaçış yok .. Ancak:

Ben hala istenmeyen html_escape sendromu çekiyorum ...

Bunu önlemek için bildiğim tek yolu yapmaktır:

content_tag(:ol) do 
    (1..5).to_a.map do 
    content_tag(:li) do 
     link_to("boo", "www.boohoo.com") 
    end 
    end.join.html_safe 
end 

=> "<ol><li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li><li><a href=\"www.boohoo.com\">boo</a></li></ol>" 

Ama .. Neden bu oluyor?

+0

bu yalnızca bir amacı temsil eder veya bazı mantıksal davranışlar bu bloğu doldurmak için sunucu tarafı gerektirir mi? – Anatoly

cevap

15

Çünkü olur Rails 3'te, String sınıfını saran SafeBuffer sınıfı tanıtıldı ve concat çağrıldığında aksi takdirde ortaya çıkacak varsayılan çıkıştan geçersiz kılındı.

Durumunuzda, ntent_tag (: li) düzgün bir SafeBuffer çıkarıyor, ancak Array # join SafeBuffer'ları anlamıyor ve sadece bir String veriyor. Content_tag (: ol) daha sonra bir SafeBuffer yerine değer olarak bir String ile çağrılır ve onu çıkarır. Bu yüzden, bir String'i bir SafeBuffer döndürmeyen birleştirme ile yaptığı gibi yuvalama ile ilgili yapmak zorunda değil.

Dize üzerinde html_safe çağrılıyor, Dize işlenmemiş olarak iletiliyor veya diziyi safe_join öğesine aktarmanız uygun bir SafeBuffer döndürecek ve dış content_tag öğesinin bundan kaçmasını engelleyecektir.

Kaçış bağımsız değişkenine yanlış iletme durumunda, bu, şablona çekmek için kullanılan capture(&block) ActionView :: Helpers :: CaptureHelper çağrılıyor olduğundan, içerik etiketine bir blok geçirdiğinizde işe yaramıyor. veya sizin davanızın çıkış değeri, daha sonra html_escape dizesini content_tag_string yöntemine girmeden önce dizeye çağırmasına neden olur.Buradaki değerin katılmak dönüş değerdir ve döndürür bir dize katılmak yana content_tag kodu bile kendi kaçmalarına ile kendisine ulaşmadan önce

# action_view/helpers/tag_helper.rb 
    def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block) 
    if block_given? 
     options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) 
     # capture(&block) escapes the string from join before being passed 
     content_tag_string(name, capture(&block), options, escape) 
    else 
     content_tag_string(name, content_or_options_with_block, options, escape) 
    end 
    end 

    # action_view/helpers/capture_helper.rb 
    def capture(*args) 
    value = nil 
    buffer = with_output_buffer { value = yield(*args) } 
    if string = buffer.presence || value and string.is_a?(String) 
     ERB::Util.html_escape string 
    end 
    end 

, bu html_escape çağırır.

ilgilenenler

https://github.com/rails/rails/blob/v3.1.0/actionpack/lib/action_view/helpers/capture_helper.rb

https://github.com/rails/rails/blob/v3.1.0/actionpack/lib/action_view/helpers/tag_helper.rb

http://yehudakatz.com/2010/02/01/safebuffers-and-rails-3-0/

http://railsdispatch.com/posts/security

için bazı referans bağlantıları düzenle

Bunu işlemenin bir başka yolu da, harita/birleştirmeden ziyade bir harita/küçültme yapmaktır; çünkü bir argüman geçmezse, ilk öğeyi kullanır ve söz konusu işlemi, bu işlevi kullanarak çalışır. Bir SafeBuffer'da işlemi çağırıyor olacak. Tek astar

content_tag(:ul) { collection.map {|item| content_tag(:li) { link_to(...) }}.reduce(:<<) } 

olarak

content_tag(:ol) do 
    (1..5).to_a.map do 
    content_tag(:li) do 
     link_to(...) 
    end 
    end.reduce(:<<) 
    # Will concat using the SafeBuffer instead of String with join 
end 

ihtiyacı Kim

ul_tag { collection.map_reduce(:<<) {|item| li_link_to(...) } } 

şeyleri temizlemek için biraz meta baharat ekleyin html_safe ... Bu Ruby!

+0

Güzel yanıt! Map_reduce'a nasıl geldiniz? Kendi yöntemini yaptınız mı yoksa Rails (Ruby) mi inşa ettiniz? – Cristian

+0

Ben sadece bunu yaptım, Bu Enumerable üzerinde yamalı, sadece gerçekten, def map_reduce (op, & blok) self.map (& blok) .reduce (op) end – Cluster

0

Olumlu değil, ama html kaçışının her "katman" da gerçekleştiğini düşünüyorum (daha iyi bir terimin yokluğu için; her yineleme) - ne demek iç blok seviyesinde (1..5)…. ve daha sonra dış blok seviyesinde (content_tag (en:? Eğer safe_join

content_tag(:ol) do 
    safe_join (1..5).to_a.map { 
     content_tag(:li) { link_to("boo", "www.boohoo.com") } 
    }, '' 
end 

Ya da sadece ham kullanmak kullanmak ne olur ol) do ...

+0

Ben öyle düşünmüyorum .. "join" çağrısından oluyor .. content_tag (: div) {content_tag (: ol)} "

    " çıktıları ... İçerik_tag (: div) {[content_tag (: ol) ] .join} "
    <ol></ol>
    " çıktıları – patrick

    4

    content_tag(ol) do 
        1.upto(5) { 
        raw content_tag(:li) { link_to 'boo', 'www.boohoo.com' } 
        # or maybe 
        # raw content_tag(:li) { raw link_to('boo', 'www.boohoo.com') } 
        } 
    end