Reputation: 40473
This bit of haml works:
%select{ :name => 'color', :value => @p.color}
- Person.color.options[:flags].each do |colors|
- if @p.color == colors
%option{:value => colors, :selected => "selected"}= colors
- else
%option{:value => colors}= colors
I'm trying to create a helper out of it so I can reuse it:
helpers do
def options(prop, p)
Person.prop.options[:flags].each do |x|
if p.prop == x
"%option{:value => #{x}, :selected => 'selected'}= #{x}"
else
"%option{:value => #{x}}= #{x}"
end
end
end
end
And then calling it with:
%select{ :name => 'color', :value => @p.color}
- options(color, @p)
But I'm getting this error: undefined local variable or method 'color'
Am I far off?
EDIT 2:
Something funky is going on with the loop.
Even a simple example such as this:
helpers do
def options(prop, p)
Person.send(prop).options[:flags].each do |x|
"<p>test</p>"
end
end
end
and = options(:color, @p)
prints an array of the options ( in my case [:red, :blue, :yellow]
) and does not insert any html. However, if I do puts <p>test</p>
it does go through the loop three times and prints them correctly—they just don't show up in the html.
Upvotes: 2
Views: 902
Reputation: 79733
There are a couple of things going on here. First, the message undefined local variable or method 'color'
is caused by the line
- options(color, @p)
in your Haml. Here color
is the undefined local variable. If I understand correctly you have a Person
class that has various properties, each of which has several possible options and you want to be able to choose which one to use without hardcoding it and needing several helpers method. One way to do that would be to change the line
Person.prop.options[:flags].each do |x|
in your helper to
Person.send(prop).options[:flags].each do |x|
and then pass a symbol specifying the property to use when you call the helper:
- options(:color, @p)
The next problem is writing the generated code to the output. Your helper can either return a string which you can include with =
, or it can write directly to the output using helpers like haml_tag
and haml_concat
. Note that you shouldn’t use the return value of haml_tag
or haml_concat
, it will generate an error.
So here you can either create the HTML in the helper:
if p.prop == x
"<option value='#{x}' selected='selected'>#{x}</option>"
else
"<option value='#{x}' />#{x}</option>"
end
and then use it with =
(if you use -
the output will get ignored):
= options(:color, @p)
If you do this you need to make sure the helper returns the string you want to embed in your Haml. In this case the helper returns the value the call to each
, which is the array itself. You need to use something like map
and join
to create the desired string:
def options(prop, p)
Person.send(prop).options[:flags].map do |x|
if p.prop == x
"<option value='#{x}' selected='selected'>#{x}</option>"
else
"<option value='#{x}' />#{x}</option>"
end
end.join("\n")
end
The alternative is to use haml_tag
to write the output directly.
if p.prop == x
haml_tag :option, x, :value=>x, :selected => true
else
haml_tag :option, x, :value =>x
end
Note that in Haml, any entry in an attribute hash that has a boolean value will only be output if the value is true
, and it will be formatted correctly depending on the output, e.g. selected='selected'
got XHTML and just selected
for HTML. So this last example can be simplified to
haml_tag :option, x, :value=>x, :selected => (p.prop == x)
(You could always simplify the other example (returning a string) in a similar manner, with something like #{"selected='selected'" if p.prop == x}
, but Haml has it built in.)
Upvotes: 1
Reputation:
Use a symbol instead of undefined method:
options(:color, @p)
instead of:
options(color, @p)
and on helper method use send
:
if p.send(prop) == x
instead of
if p.prop == x
as well as:
Person.send(prop)
instead of:
Person.prop
Also, i'm in doubt HAML will accept a string like "%option{:value => #{x}"
as a tag.
You can use HTML instead or just find another way to DRY, like render a partial or use haml_tag
:
def options(prop, p)
Person.send(prop).options[:flags].each do |x|
haml_tag :option, "#{x}", :value=>x
end
end
If you use haml_tag
call it with - options(:color, @p)
Upvotes: 1