Sorry if this sounds obvious but i'm getting confused.
I'm trying to build a navigation list helper.
At the moment it receives a list of links from an array.
module ApplicationHelper
def site_pages
%w{index about contact promotions}
end
def nav_builder list
list.map do |l|
content_tag :li do
content_tag :a, :href => "#{l}_path" do
l
end
end
end
end
end
But when I run the page it ouput everything is the page as an array.
[<li>index</li> <li>about</li> <li>contact</li> <li>promotions</li>]
instead of displaying a list of links.
Is there anything special to do?
==EDIT==
I call my builder this way:
<%= nav_builder site_pages %>
The helper is expected to return a String of HTML, rather than an Array. Try joining the Array elements into a single String:
def nav_builder list
list.map do |l|
content_tag :li do
content_tag :a, :href => "#" do
"test"
end
end
end.join("\n").html_safe
end
Related
I have a text field that user's put in data that I'm converting to list items. So they may enter in the text area:
Apple
Tomato
Wrench
So I have the following that works:
<% regional_services = #region.services.split("\n") %>
<ul>
<%regional_services.each do |services| %>
<li><%=services%></li>
<%end%>
</ul>
It outputs correctly with something like
Apple
Tomato
Wrench
But I'm trying to get it to work in a helper instead since it's ugly in the view.
So I have the following:
def other_service
if #region.services.present?
something = #region.services.split("\r\n")
content_tag(:ul) do
content_tag(:li, something.each {|alpha| alpha })
end
else
content_tag(:p, 'Here is text')
end
end
It ends up outputting like:
["Apple", "Tomato", "Wrench"]
So it looks like it's not applying the iteration on the list item so I tried the following:
def other_service
if #region.services.present?
regional_service = #region.services.split("\n")
content_tag(:ul) do
regional_service.each do |service|
content_tag(:li, service)
end
end
else
content_tag(:p, 'Here is text')
end
end
No error but it's actually not displaying anything on the pages that actually have items. So how do I do a content_tag ul with an iteration?
each returns the array, so the block of content_tag :ul is going to receive an array itself as an inner HTML. Which is apparently not what you wanted.
In order to add HTML to an output buffer, you would use concat:
content_tag :ul do
regional_service.each do |service|
concat content_tag(:li, service)
end
end
I'm having a helper for displaying the tags of a post
# Show action
%p Tags #{ link_tags #post }
# Helper
def link_tags post
raw post.tag_list.map{ |t|
link_to t, posts_path(tag: t.name)
}.join(', ')
end
However I'm getting an error on screen
undefined method `name' for "ruby":String
How can I fix this? As a side note the code on my sidebar (where I list all post-tags) where I tried to copy from works fine
- tag_cloud Post.tag_counts, %w(tag) do |tag, css_class|
= link_to tag.name, posts_path(tag: tag.name), :class => css_class
post.tag_list will give you an array of tags as strings.
What you are looking for is probably post.tags which should return an array of ActsAsTaggableOn objects.
Here you have tutorial about tags on posts
I am trying to create helper method that displays the navigation. How ever my helper displays an array even though i am using content_tag. Was wondering if i was doing something wrong.
module SubscriberNavigation
def navigation
get_menu_items.find_each.map do |menu|
content_tag(:li, link_to("#{ menu.title.try(:capitalize) }", "#{ menu.url.downcase }"))
end
end
def get_menu_items
#get_menu_items ||= Subscriber::Menu.all
end
end
And when i display
<%= navigation %>
An array of records in being displayed. Instead of content_tag list items.
["<li>Contacts</li>", "<li>Terms and conditions</li>", "<li>About us</li>"]
I tried .html_safe etc but looks like i'm missing something.
It is returning an Array. You can try this:
<%= navigation.join(' ').html_safe %>
I'm trying a helper method that will output a list of items, to be called like so:
foo_list( ['item_one', link_to( 'item_two', '#' ) ... ] )
I have written the helper like so after reading 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
However I just get an empty UL in that case, if I do this as a test:
def foo_list items
content_tag :ul do
content_tag(:li, 'foo')
end
end
I get the UL & LI as expected.
I've tried swapping it around a bit doing:
def foo_list items
contents = items.map {|item| content_tag(:li, item)}
content_tag( :ul, contents )
end
In that case I get the whole list but the LI tags are html escaped (even though the strings are HTML safe). Doing content_tag(:ul, contents.join("\n").html_safe ) works but it feels wrong to me and I feel content_tag should work in block mode with a collection somehow.
Try this:
def foo_list items
content_tag :ul do
items.collect {|item| concat(content_tag(:li, item))}
end
end
I couldn't get that work any better.
If you were using HAML already, you could write your helper like this:
def foo_list(items)
haml_tag :ul do
items.each do |item|
haml_tag :li, item
end
end
end
Usage from view:
- foo_list(["item_one", link_to("item_two", "#"), ... ])
Output would be correctly intended.
You could use content_tag_for, which works with collections:
def foo_list(items)
content_tag(:ul) { content_tag_for :li, items }
end
Update: In Rails 5 content_tag_for (and div_for) were moved into a separate gem. You have to install the record_tag_helper gem in order to use them.
Along with answers above, this worked for me well:
(1..14).to_a.each do |age|
concat content_tag :li, "#{link_to age, '#'}".html_safe
end
The big issue is that content_tag isn't doing anything smart when it receives arrays, you need to send it already processed content. I've found that a good way to do this is to fold/reduce your array to concat it all together.
For example, your first and third example can use the following instead of your items.map/collect line:
items.reduce(''.html_safe) { |x, item| x << content_tag(:li, item) }
For reference, here is the definition of concat that you're running into when you execute this code (from 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
How does rails get away with the following in an .erb file?
<%= yield :sidebar %>
<%= yield :other_bar %>
<%= yield :footer %>
How are they able to yield multiple times in the same context to different symbols? Is this some kind of rails magic?
I'm totally familiar with:
def some_method(arg1, arg2, &block)
yield(:block)
end
To my knowledge following doesn't work:
def some_incorrect_method(arg1, &block1, &block2)
yield(:block1)
yield(:block2)
end
So how are they doing it? How do they make it work?
They are passing a symbol into yield...
yield :symbol
...not yielding to a different block.
It works more like this:
def some_method(arg1, arg2, &block)
yield(:some_symbol1)
yield(:some_symbol2)
end
some_method do |symbol|
case symbol
when :some_symbol1
# do A
when :some_symbol2
# do B
else
# unrecognised symbol?
end
end
Do you mean http://apidock.com/rails/ActionView/Helpers/CaptureHelper/content_for ?