简体   繁体   中英

Why can't form_tag and form_for be used in helper functions [Rails]

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM