2011-09-26 9 views
8

तो, यदि मैं लूप/टैग का संग्रह बनाकर बना देता हूं, तो मुझे उम्मीद है .. इन टैगों की एक सरणी:नेस्टेड content_tags आंतरिक एचटीएमएल से बच .. क्यों?

(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>"] 

मैं उन पर शामिल होने के लिए कॉल करता हूं और मुझे अपेक्षित स्ट्रिंग मिलती है ...

(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>" 

हालांकि, अगर मैं एक ओल टैग में गहराई से एक स्तर को घोंसला करता हूं ...

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

मैं आंतरिक-एचटीएमएल पागलपन से बच गया !!!

रेल स्रोत कोड को देखते समय:

 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 

यह धोखे से दिखता है जैसे मैं बस कर सकता हूं: content_tag (: li, nil, nil, false) और यह सामग्री से बच नहीं है .. हालांकि:

content_tag(:ol, nil, nil, false) do 
    (1..5).to_a.map do 
    content_tag(:li, nil, nil, false) do 
     link_to("boo", "www.boohoo.com") 
    end 
    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_escape सिंड्रोम से पीड़ित हूं ...

तो मुझे यह जानने का एकमात्र तरीका यह है कि:

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

लेकिन .. ऐसा क्यों होता है?

+0

क्या यह सिर्फ उद्देश्य का प्रतिनिधित्व करता है या कुछ तर्क व्यवहार के लिए इस ब्लॉक को पॉप्युलेट करने के लिए सर्वर-साइड की आवश्यकता होती है? – Anatoly

उत्तर

15

यह वजह से होता रेल 3 में सेफबफर वर्ग पेश किया गया था जो स्ट्रिंग क्लास को लपेटता है और डिफॉल्ट एस्केपिंग को ओवरराइड करता है जो अन्यथा होता है जब कंसल्ट कहा जाता है।

आपके मामले में, सह ntent_tag (: li) एक उचित सेफबफर आउटपुट कर रहा है, लेकिन ऐरे # जॉइन सेफबफर को समझ में नहीं आता है और बस स्ट्रिंग आउटपुट करता है। Content_tag (: ol) को स्ट्रिंग के साथ एक सुरक्षित बफर के बजाय मूल्य के रूप में जाना जाता है और इससे बच निकलता है। इसलिए इसे घोंसले से इतना करना नहीं है क्योंकि स्ट्रिंग को एक सुरक्षित बफर नहीं लौटने में शामिल होने के साथ ऐसा करना पड़ता है।

स्ट्रिंग पर html_safe को कॉल करना, स्ट्रिंग को स्ट्रिंग पास करना, या सुरक्षित_जॉइन में सरणी पास करना, सभी एक उचित सेफबफर वापस कर देंगे और बाहरी सामग्री_टैग को इससे बचने से रोक देंगे।

अब बचने के तर्क के लिए झूठ बोलने के मामले में, यह काम नहीं करता है जब आप सामग्री टैग पर ब्लॉक पास करते हैं क्योंकि यह capture(&block) एक्शन व्यू :: हेल्पर्स :: कैप्चरहेल्पर को टेम्प्लेट में खींचने के लिए उपयोग किया जाता है, या आपके मामले में शामिल होने का आउटपुट वैल्यू, जिसके बाद यह विधि में अपना रास्ता बनाने से पहले स्ट्रिंग पर html_escape पर कॉल करने का कारण बनता है।

# 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 

के बाद से मूल्य यहाँ में शामिल होने से वापसी मान है, और रिटर्न एक स्ट्रिंग में शामिल होने के लिए, यह html_escape कॉल से पहले content_tag कोड भी अपने आप ही बच इसे करने के लिए हो जाता है।

उन दिलचस्पी

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

के लिए कुछ संदर्भ लिंक संपादित

इसे संभालने का एक और तरीका नक्शा/जुड़ने के बजाय मानचित्र/जोड़ना है, क्योंकि कम से कम एक तर्क पारित नहीं किया गया है, यह पहले तत्व का उपयोग करेगा और उस ऑब्जेक्ट का उपयोग करके दिए गए ऑपरेशन को चलाएगा, जो मैप सामग्री_टैग के मामले में होता है एक सुरक्षितबफर पर ऑपरेशन बुलाएगा।

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 

एक एक लाइनर

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

के रूप में एक छोटे से मेटा-मसाला बातें साफ करने के लिए

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

जोड़े की जरूरत है कौन html_safe ... इस रूबी है!

+0

अच्छा जवाब! आप map_reduce कैसे पहुंचे? क्या आपने अपनी खुद की विधि बनाई है या क्या यह रेल (रूबी) में बनाई गई है? – Cristian

+0

मैंने अभी इसे बनाया है, यह बंदर पर अंकुरित है, यह वास्तव में वास्तव में है, def map_reduce (op, और block) self.map (& block) .reduce (op) end – Cluster

0

सकारात्मक नहीं है, लेकिन मुझे लगता है कि एचटीएमएल से बचने से प्रत्येक "परत" (बेहतर अवधि की कमी के लिए; प्रत्येक पुनरावृत्ति) की कमी होती है - मेरा मतलब है कि आंतरिक ब्लॉक स्तर (1..5) ... पर है। और फिर बाहरी ब्लॉक स्तर (content_tag (कम से? ओएल) कर ...

+0

मुझे ऐसा नहीं लगता .. यह "शामिल" कहने से होता है .. content_tag (: div) {content_tag (: ol)} आउटपुट "

    " ... जहां content_tag (: div) {[content_tag (: ol) ] .join} आउटपुट "
    <ol></ol>
    " – patrick

    4

    अगर आप का उपयोग safe_join

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

    या सिर्फ कच्चे का उपयोग क्या होता है

    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 
    
    संबंधित मुद्दे