Reputation:
I'm doing a rails project and I'm refractoring some code. Because I use the same type of collection_select with a form_tag, I decided to create a helper for it where I just change the path & request.
However, I noticed that when I use form_for in a helper function, it only returns the last line. In the following example, it will only return the submit button and if I remove the submit button, it will only return the select.
def form_select #### Helper Function
form_tag po_path(@pos), method: "get" do
collection_select :po, :category, @pos.categories.order(:id), :id, :name, selected: (@items.empty? ? "" : @items.first.category.id)
submit_tag "Show items"
end
end
end
My question is; why does this not work, but the following does?
<!-- In the view -->
<%= form_tag po_path(@pos), method: "get" do %>
<%= collection_select :po, :category, @pos.categories.order(:id), :id, :name, selected: (@items.empty? ? "" : @items.first.category.id)%>
<%= submit_tag "Show items" %>
<% end %>
It does the same for form_for.
Does anyone know why this happens?
Upvotes: 0
Views: 343
Reputation: 101891
When calling the form helpers (or any other html helpers) in a helper method you need to call concat
(or manually concatenate the strings).
def form_select #### Helper Function
form_tag po_path(@pos), method: "get" do
concat collection_select :po, :category, @pos.categories.order(:id), :id, :name, selected: (@items.empty? ? "" : @items.first.category.id)
concat submit_tag "Show items"
end
end
This is because the helper does not return a concatenated html string as you are expecting. Rather the blocks returns the result of the last expression just like any other Ruby block.
def foo(&block)
yield
end
# returns "baz"
foo do
"bar"
"baz"
end
It works in ERB since the <%= %>
are expressions where the renderer should substitute the code element with the result of the code (as a string) when it renders the template. This is somewhat like puts
but it writes to the template buffer.
<%= foo do %>
<%= "bar" %> <%= "baz" %>
<% end %>
This example will output "bar baz" to the template.
But you should really consider using a partial here instead.
Upvotes: 1