2011-01-12 20 views
25

Tôi đang cố gắng một phương pháp helper mà sẽ đưa ra một danh sách các mục, được gọi là như vậy:Vòng & đầu ra content_tags trong content_tag trong helper

foo_list(['item_one', link_to('item_two', '#') ... ]) 

Tôi đã viết các helper như vậy sau khi đọc Using helpers in rails 3 to output html:

def foo_list items 
    content_tag :ul do 
     items.collect {|item| content_tag(:li, item)} 
    end 
end 

Tuy nhiên tôi chỉ nhận được một UL trống trong trường hợp đó, nếu tôi làm điều này như một thử nghiệm:

def foo_list items 
    content_tag :ul do 
     content_tag(:li, 'foo') 
    end 
end 

Tôi nhận được UL & LI như mong đợi.

Tôi đã thử trao đổi nó xung quanh một chút thực hiện:

def foo_list items 
    contents = items.map {|item| content_tag(:li, item)} 
    content_tag(:ul, contents) 
end 

Trong trường hợp đó tôi nhận được toàn bộ danh sách nhưng các thẻ LI là html loại trừ (mặc dù các dây là HTML an toàn). Làm công việc content_tag(:ul, contents.join("\n").html_safe) nhưng nó cảm thấy sai với tôi và tôi cảm thấy content_tag nên hoạt động trong chế độ khối với một bộ sưu tập bằng cách nào đó.

Trả lời

43

Hãy thử điều này:

def foo_list items 
    content_tag :ul do 
     items.collect {|item| concat(content_tag(:li, item))} 
    end 
end 
+0

Điều đó hoạt động, tôi đã cố gắng làm concat xung quanh việc thu thập, trước đây hơn là trong vòng. Với concat bên trong proc sau đó thu thập là không cần thiết và bạn có thể sử dụng một items.each (hoặc iterators khác). – DEfusion

+3

Bằng cách này bạn đang gọi concat trên mỗi phần tử. Tôi nghĩ rằng sẽ rẻ hơn khi làm items.collect {}. Tham gia ("") html_safe –

7

Tôi không thể làm việc đó tốt hơn.

Nếu bạn đang sử dụng HAML đã có, bạn có thể viết helper của bạn như thế này:

def foo_list(items) 
    haml_tag :ul do 
    items.each do |item| 
     haml_tag :li, item 
    end 
    end 
end 

Cách sử dụng từ quan điểm:

- foo_list(["item_one", link_to("item_two", "#"), ... ]) 

Output sẽ được dự định một cách chính xác.

+0

Cảm ơn, đây là siêu trơn! –

2

Vấn đề lớn là content_tag mà không làm bất cứ điều gì thông minh khi nó nhận được mảng, bạn cần phải gửi nó nội dung đã được xử lý. Tôi đã tìm thấy rằng một cách tốt để làm điều này là để gấp/giảm mảng của bạn để concat nó tất cả cùng nhau.

Ví dụ, ví dụ đầu tiên và thứ ba của bạn có thể sử dụng sau đây thay vì dòng items.map/collect của bạn:

items.reduce(''.html_safe) { |x, item| x << content_tag(:li, item) } 

Để tham khảo, đây là định nghĩa của concat rằng bạn đang chạy vào khi bạn thực thi mã này (từ actionpack/lib/action_view/helpers/tag_helper.rb).

def concat(value) 
    if dirty? || value.html_safe? 
    super(value) 
    else 
    super(ERB::Util.h(value)) 
    end 
end 
alias << concat 
5

Bạn có thể sử dụng content_tag_for, mà làm việc với các bộ sưu tập:

def foo_list(items) 
    content_tag(:ul) { content_tag_for :li, items } 
end 

Cập nhật: Trong Rails 5 content_tag_for (và div_for) đã được chuyển thành một viên ngọc riêng biệt. Bạn phải cài đặt viên đá quý record_tag_helper để sử dụng chúng.

+0

content_tag_for bị xóa trong Rails 5 – hellion

3

Cùng với câu trả lời ở trên, điều này làm việc cho tôi cũng:

(1..14).to_a.each do |age| 
    concat content_tag :li, "#{link_to age, '#'}".html_safe 
end 
+1

Có thể cần thay đổi <% = thành <% trong mẫu khi thực hiện việc này. – nruth

Các vấn đề liên quan