In other words I need to put user-defined input in between some
pre-defined content. How can I approach that?
If I understand correctly what you want to do, you don’t need to do
anything
special:
def my_method
puts “predefined text 1”
puts yield
puts “predefined text 2”
end
My method looks like this:
def fields_for_setting(namespace, name, &block)
namespace = namespace.to_s
name = name.to_s
id = “settings_#{namespace}#{name}”
m = Builder::XmlMarkup.new :indent => 2
fields_for “settings[]”, setting =
Setting.find_or_initialize_by_namespace_and_name(namespace, name) do |f|
m.p do
unless setting.new_record?
m << (f.hidden_field :id, :index => nil, :id => id+“id”)
end
m << (f.hidden_field :namespace, :index => nil, :id =>
id+“namespace”)
m << (f.hidden_field :name, :index => nil, :id => id+“name”) #puts yield f???
end
end
end
The problem is, I’m using Builder::XmlMarkup and the fields_for from
Rails. I want to put some hidden fields AND the text fields defined by
the block into a
tag. That means I need to be able to access the f
object provided by fields_for and use it in this method’s block.
Alle Thursday 16 October 2008, David T. ha scritto:
puts yield
fields_for “settings[]”, setting =
end
end
The problem is, I’m using Builder::XmlMarkup and the fields_for from
Rails. I want to put some hidden fields AND the text fields defined by
the block into a
tag. That means I need to be able to access the f
object provided by fields_for and use it in this method’s block.
But how?
I don’t know Rails and Builder::XmlMarkup, so I can be completely wrong.
From
a quick look at Builder::XmlMarkup api, I’d say that, if the block
returns the
string you want to insert in the p element, you only have to insert it
in m
like you did for the texts:
I don’t know Rails and Builder::XmlMarkup, so I can be completely wrong.
From
a quick look at Builder::XmlMarkup api, I’d say that, if the block
returns the
string you want to insert in the p element, you only have to insert it
in m
like you did for the texts:
m << yield f
Yes, that was also my first idea, but that is giving me this syntax
error:
Actually it does, because your block contains a call to puts, and puts
always returns nil. You probably want your block just to contain a
string.
Ah, I see. Let me just explain. Since I’m using Rails I am calling this
method with the block in a view or a template. My template language is
Haml, and this is how it’s called:
The = is a short hand for puts as you pointed out. But I don’t see other
possibilities than using put, otherwise the text field will not show up
in the view.
How can I both use puts and make some content appear around the text
field?
How can I both use puts and make some content appear around the text
field?
I’m not a HAML expert, but in general, you don’t want to use puts for
anything you’re outputting in a template. You just want to insert
strings. I’m not sure how HAML handles string concatenation of this
kind.
Phew, this got a little more complicated than I hoped. To make this
understandable I’ll just explain the problem. I want a method that
accepts a block. Inside the method I’m using the method fields_for that
also accepts a block. I want the f object provided by fields_for passed
over to the block that MY method accepts, like this:
fields_for_setting(“site”, “name”) do |f|
#--------------------------------------^ #This should be the f object that fields_for provides.
= f.text_field :value, :index => nil
I simply want to reuse the f object to make my view shorter and cleaner.
Both in the method where the fields_for is used and in the view, where
it should be reused.
always returns nil. You probably want your block just to contain a
The = is a short hand for puts as you pointed out. But I don’t see other
possibilities than using put, otherwise the text field will not show up
in the view.
How can I both use puts and make some content appear around the text
field?
I’m not a HAML expert, but in general, you don’t want to use puts for
anything you’re outputting in a template. You just want to insert
strings. I’m not sure how HAML handles string concatenation of this
kind.
Actually I think I’m close to a solution now. I made these two methods:
def fields_for_setting(namespace, name)
id = “settings_#{namespace}#{name}”
m = Builder::XmlMarkup.new :indent => 2
fields_for “settings[]”, setting =
Setting.find_or_initialize_by_namespace_and_name(namespace, name) do |f|
m.p do
unless setting.new_record?
m << (f.hidden_field :id, :index => nil, :id => id+“id”)
end
m << (f.hidden_field :namespace, :index => nil, :id =>
id+“namespace”)
m << (f.hidden_field :name, :index => nil, :id => id+“name”)
m << yield(f)
end
end
end
def text_field_for_setting(namespace, name, label=nil)
namespace = namespace.to_s
name = name.to_s
label ||= “#{namespace.capitalize} #{name}”
id = “settings_#{namespace}#{name}”
fields_for_setting(namespace, name) do |f|
f.label :value, label, :index => nil, :for => id+“value”
f.text_field :value, :index => nil, :id => id+“value”
end
end
In my view I’m calling the second method (text_field_for_setting) like
this:
= text_field_for_setting(:site, :owner)
The method that is called here then calls my first method
(fields_for_setting) with a block. This actually works fine, but for
some reason that I can’t figure out (I hope you can help me) It only the
LAST line of the block that is passed to fields_for_setting that shows
up.
In other words, even though I declare both a label and a text field,
only the text field shows up. How comes?
That syntax will work but it would be much more idiomatic to do:
m << f.hidden_field(:name, :index …)
fields_for_setting(namespace, name) do |f|
The method that is called here then calls my first method
(fields_for_setting) with a block. This actually works fine, but for
some reason that I can’t figure out (I hope you can help me) It only the
LAST line of the block that is passed to fields_for_setting that shows
up.
In other words, even though I declare both a label and a text field,
only the text field shows up. How comes?
Because a block, like a method call, evaluates to the last expression
inside it. For example:
def get_string
str = yield
puts str
end
get_string do
“First string”
“Second string”
end
This will print “Second string”. “First string” is just thrown away.
So maybe inside your block you want to concatenate the two strings.
So maybe inside your block you want to concatenate the two strings.
Okay, I’m using #concat instead. It works just fine, thanks!
I must have overseen something. Today it doesn’t work very well. I do
get my label and text field but I don’t get the surrounding
tag and
the hidden fields. My methods looks like this:
def fields_for_setting(namespace, name)
id = “settings_#{namespace}#{name}”
m = Builder::XmlMarkup.new :indent => 2
fields_for “settings[]”, setting =
Setting.find_or_initialize_by_namespace_and_name(namespace, name) do |f|
m.p do
unless setting.new_record?
m << (f.hidden_field :id, :index => nil, :id => id+“id”)
end
m << (f.hidden_field :namespace, :index => nil, :id =>
id+“namespace”)
m << (f.hidden_field :name, :index => nil, :id => id+“name”)
m << yield(f)
end
end
end
def text_field_for_setting(namespace, name, label=nil)
namespace = namespace.to_s
name = name.to_s
label ||= “#{namespace.capitalize} #{name}”
id = “settings_#{namespace}#{name}”
fields_for_setting(namespace, name) do |f|
concat f.label :value, label, :index => nil, :for => id+“value”
concat f.text_field :value, :index => nil, :id => id+“value”
end
end
So, I’m concatenating the label and text field inside the
fields_for_setting block. But the fields_for_setting block doesn’t have
any effect at all! I think it’s because fields_for_setting is only returning the