Rails 7 now consistently renders button_to


Rails provides many methods that render out HTML tags, allowing for easy customization. However, some of the Rails methods do not offer consistent results. One such example, until recently, was the button_to helper method.

This is how it works,

  <%= button_to "New", new_article_path %>

  # => "<form method="post" action="/articles/new" class="button_to">
  #      <input value="New" type="submit" />
  #    </form>"

Unfortunately, the helper method render <input type="submit"> when passed String contents but renders <button type="submit"> when passed a block.

Before

Though this difference is subtle, it will lead to surprises later. One such quirky behavior is when button_to renders out an input field, it sets the button content as the input’s value. This behavior is not obvious and prevents us from setting custom input values.

In cases where the input value is set to nil, it provides an opportunity for applications to encode their custom values to be sent back to the server for processing. This could cause additional security concerns.

After

With the updated Rails 7, button_to always renders out a consistent output.

Here’s how it works now.

  <%= button_to "New", new_article_path %>

  # => "<form method="/posts/1">
  #       <input type="_method" value="post">
  #       <button type="submit">Delete</button>
  #     </form>"

Since this change could affect many applications running in the real world, the Rails team has decided to make this a configurable option.

To support the original behavior of button_to rendering <input type="submit"> elements when invoked without a block, expose the app.config.button_to_generates_button_tag configuration flag.

By default, it’s set to true and ensures that all button_to calls render <button> elements. To revert to the original behavior, set it to false.