I am trying to create a dynamic menu using the following construct:
<%- menu_list = [ 'first', 'second', 'third'] -%>
<ul>
<%- menu_list.each do |m| -%>
<%= link_to "List All #{m.titlecase.pluralize} <m>_path %>
<%- end -%>
</ul>
What I cannot determine is what I have to do to replace <m> so that the
link_to has a target. I have tried string substitution ("#{m}"_path)
but that gives a compile error:
_erbout.concat(( link_to "List All #{m.titlecase.pluralize}",
("#{m}"_path) ).to_s); _erbout.concat "
I am sure that there must be a fairly straight forward way to do this.
Can someone point it out to me?
Now I have a related question. Some of these methods may or may not
have routes depending upon when and where they are invoked. So, I have a
guard conditional set up:
<%- role_list.each do |m| -%>
<li> <%= "#{m.titlecase}" %>
<%= if defined? "#{m.pluralize}_path" then
link_to "List All #{m.titlecase.pluralize}",
send("#{m.pluralize}_path")
else
nil
end %>
</li>
<%- end -%>
When the guard is explicit ( if defined? firsts_path then ...) this
works. But I do not know how to test for a dynamically formed method
name. How is this done in Ruby?
<ul>
<%- role_list.each do |m| -%>
<li> <%= "#{m.titlecase}" %>
<! guard against missing path method this way -->
<%= link_to "List All #{m.titlecase.pluralize}",
send("#{m.pluralize}_path") \
if respond_to? "#{m.pluralize}_path" %>
<!-- or this way -->
<%= if respond_to? "#{m.pluralize}_path" then
link_to "List All #{m.titlecase.pluralize}",
send("#{m.pluralize}_path")
else
nil
end %>
</li>
<%- end -%>
</ul>
Can you explain to me the different behaviours between defined? and
respond_to? in this instance. I am not clear why defined? would work
with symbolized path names but not work with the same parameterized
string.to_sym.
respond_to? asks whether the object responds to some method. Since you
want to know whether self responds to the path generator that's the
one.
defined? is more generic. That's a special operator in the sense that
Ruby does *not* evaluate its argument. I don't know the whole story
(anyone?) but a posteriori defined? works at parse time or something
like that to interpret the argument expression in a special way.
For example, if SOME_CONSTANT is unknown
defined? SOME_CONSTANT
does *not* raise NameError, it does not evaluate the argument. It
silently returns nil. If the constant was known it would return
"constant".
Check this other one for example:
irb(main):004:0> a = "\n"
=> "\n"
irb(main):005:0> defined? a.chop!
=> "method"
irb(main):006:0> a
=> "\n"
You see? chop! is not being called, we are just told that a responds to chop!.
I'd like to provide a better explanation of defined? but don't have
Flanagan & Matz at hand.
I wrote too soon. I have another blank spot in my knowledge that need
filling.
This construct works:
<ul>
<%- role_list.each do |m| -%>
<li>
<%= "#{m.titlecase}" if respond_to? "#{m.pluralize}_path" %>
<%= link_to "List All #{m.titlecase.pluralize}", \
send("#{m.pluralize}_path") if respond_to?
"#{m.pluralize}_path" %>
<%= link_to "Add New #{m.titlecase}", send("new_#{m}_path") \
if respond_to? "#{m.pluralize}_path" %>
</li>
<%- end -%>
</ul>
and this does not:
<ul>
<%- role_list.each do |m| -%>
<li>
<!-- guard against missing path methods. We assume (that word again)
that if the ms_path exists then the new_m_path does as well.-->
<%= if respond_to? "#{m.pluralize}_path" then
"#{m.titlecase}"
link_to "List All #{m.titlecase.pluralize}",
send("#{m.pluralize}_path")
link_to "Add New #{m.titlecase}", send("new_#{m}_path")
end -%>
</li>
<%- end -%>
</ul>
All I get in the html from this is the output of the last step in the if
block:
link_to "Add New #{m.titlecase}", send("new_#{m}_path")
This indicate that I am only getting the final return value of a Ruby
method as the entire result of the if construct. This is not what I
intend or desire so is there some way of getting each step in the if
block to produce output onto the html page?
Now that I have this working in a view I want to move it all out into a
pair of methods that I can call from multiple views: role_list_head and
role_list_foot. Two questions arise from this:
Where do I put these methods? In application_helper.rb,
application_controller.rb, or somewhere else?
What does the method look like? Something akin to this I expect:
def role_list_head(list=@role_list_default)
link_to 'Main Page', :controller => 'nav_menus'
list.each do |m|
# guard against missing path methods.
if respond_to? "#{m.pluralize}_path" then
link_to "List All #{m.titlecase.pluralize}",
send("#{m.pluralize}_path")
end
end
list.each do |m|
if respond_to? "new_#{m.}_path" then
link_to "Add New #{m.titlecase}", send("new_#{m}_path")
end
end
end
I know that this does not work, because I tried it. But something
somewhat like this has to be the answer.
link_to "List All #{m.titlecase.pluralize}",
send("#{m.pluralize}_path")
end
end
list.each do |m|
if respond_to? "new_#{m.}_path" then
link_to "Add New #{m.titlecase}", send("new_#{m}_path")
end
end
end
I know that this does not work, because I tried it. But something
somewhat like this has to be the answer.
That's view stuff so should go to a helper or to a partial. The helper
would build and return a single string with HTML so that you can use
it like this
That's view stuff so should go to a helper or to a partial. The helper
would build and return a single string with HTML so that you can use
it like this
<%= role_list_header %>
yes, but which helper file exactly? All that I have read about helpers
indicates that they are tied to a specific controller by name. I tried
adding a dummy method to a file called lib/application_helper.rb but
when I called the method from a view I got a missing method error.
Because app/helpers is the directory where helpers are expected to be
by convention. Note that application_helper.rb is generated there by
the rails command, and it already contains a module ApplicationHelper.