• Home
  • About
  • Portfolio
  • Contact
CodeCurious
  • Home
  • About
  • Portfolio
  • Contact
Go Back

Rails Link_to Vs Button_to: When Should You Use Each?

Learn the difference between link_to and button_to in Ruby on Rails with real-world examples, code snippets, and beginner tips.

Jean Emmanuel Cadet
By Jean Emmanuel Cadet • Ruby on Rails Developer

Last updated : Jun 06, 2026 • 11 min read

Rails link_to vs button_to: When Should You Use Each?

Last updated : Jun 06, 2026 • 11 min read

Share with friends
It's your third week learning Ruby on Rails. You've built your first blog app, you've got posts showing up on the screen, and now you want to add a "Delete" button. You've seen link_to everywhere in the tutorial, so you write something like this:
<%= link_to "Delete", post_path(@post), method: :delete %>

You click it. Instead of deleting the record, Rails sends a GET request, and your destroy action never runs. You scratch your head. You Google. You read five Stack Overflow answers. You feel like the universe is testing you.

Sound familiar?

You're not alone. Almost every beginner Rails developer hits this exact wall. And the confusion? It almost always comes down to not understanding the difference between link_to and button_to.

Today, we're going to fix that, permanently. By the end of this article, you'll know exactly which one to use, why it matters, and how to avoid the classic mistakes that trip up beginners.

Let's go.


First, The Basics


What is link_to?

link_to is a Rails view helper that generates an HTML anchor tag, the classic <a href="..."> you've probably seen a thousand times. It's designed for navigation. You use it when you want the user to travel from one page to another.

<%= link_to "Go to Blog", posts_path %>

Which renders as:

<a href="/posts">Go to Blog</a>

Simple, clean, and semantically correct. When a user clicks it, the browser sends a GET request to /posts. That's it. It fetches a page.

What is button_to?

button_to is also a Rails view helper, but it works very differently under the hood. Instead of generating a plain anchor tag, it wraps a button inside a mini HTML form.

<%= button_to "Delete Post", post_path(@post), method: :delete %>

Which renders something like:

<form action="/posts/1" method="post">
  <input type="hidden" name="_method" value="delete" />
  <input type="hidden" name="authenticity_token" value="..." />
  <button type="submit">Delete Post</button>
</form>

See that? It's a full form with a hidden _method field and an authenticity token (CSRF protection). When clicked, it submits the form with a DELETE request (or POST, PATCH, whatever you specify). It's built for actions, not navigation.


The Key Differences, Side by Side

Let's break it down clearly so it sticks.


1. HTTP Method — The Big One
This is where most beginners get confused.

Helper      | Default HTTP Method | Can Use Other Methods?
------------|--------------------|--------------------------
link_to     | GET                | Needs JavaScript (data-turbo-method)
button_to   | POST               | Yes — DELETE, PATCH, and PUT via Rails-generated form helpers

A GET request says: "Hey server, give me some data." It's for reading pages.
A DELETE request says: "Hey server, destroy this record." It's for taking action.

When you use link_to with method: :delete, you're fighting against the nature of an anchor tag. In older Rails with jQuery UJS, it sometimes worked, but only because JavaScript was intercepting the click and converting it. In modern Rails with Hotwire/Turbo, you need to use data: { turbo_method: :delete }, or just switch to button_to and stop fighting the current.

<!-- Modern Rails way with link_to for DELETE -->
<%= link_to "Delete", post_path(@post), data: { turbo_method: :delete } %>

<!-- Cleaner, more semantic way -->
<%= button_to "Delete", post_path(@post), method: :delete %>

The second one is almost always the better choice for destructive actions.


2. HTML Output — What Actually Gets Rendered

link_to renders a plain <a> tag:

<a href="/posts/1">Read Post</a>

button_to renders a form with a button inside:

<form action="/posts/1" method="post">
  <input type="hidden" name="_method" value="delete" />
  <input type="hidden" name="authenticity_token" value="xyz..." />
  <button type="submit">Delete Post</button>
</form>

This matters because the form includes CSRF protection by default. Rails is protecting your app from cross-site request forgery attacks without you having to think about it. That's one of the beautiful things about using button_to for actions: security is baked right in.


3. UX & Styling — Look and Feel

By default, link_to looks like a link (underlined text). button_to looks like a button (styled by your browser or CSS framework).

Both are fully styleable with CSS, but it's important to be semantically honest with your UI. If something looks like a button and does something (like deleting a record), it should be a button. If it looks like a link and takes you somewhere, it should be a link.

Your users expect certain visual cues. A blue underlined "Delete" link feels wrong, and it probably is.


When to Use Each One — Real World Examples

Now let's get practical. Here are scenarios you'll encounter in real Rails projects.


Use link_to for Navigation

link_to shines when you're taking the user somewhere, to another page, another resource, an external site.

<!-- Navigate to a blog post -->
<%= link_to "Read More", post_path(@post) %>

<!-- Go to the homepage -->
<%= link_to "Home", root_path %>

<!-- Visit an external link -->
<%= link_to "Visit Rails Docs", "https://rubyonrails.org", target: "_blank", rel: "noopener noreferrer" %>

<!-- Go to a specific user's profile -->
<%= link_to @user.name, user_path(@user) %>

In a blog app, your post index page might look like this:

<% @posts.each do |post| %>
  <div class="post-card">
    <h2><%= link_to post.title, post_path(post) %></h2>
    <p><%= post.excerpt %></p>
    <%= link_to "Read Full Article →", post_path(post), class: "read-more" %>
  </div>
<% end %>

Clean, readable, and semantically correct. Want to build a full blog like this? Check out this step-by-step guide: How to Build a Blog with Ruby on Rails 8,it walks you through the entire process from scratch.


Use button_to for Actions

button_to is your go-to when something happens on the server, a record is created, updated, or destroyed.

<!-- Delete a post -->
<%= button_to "Delete", post_path(@post), method: :delete,
    data: { turbo_confirm: "Are you sure?" } %>

<!-- Add an item to the cart (e-commerce) -->
<%= button_to "Add to Cart", cart_items_path,
    params: { product_id: @product.id }, method: :post %>

<!-- Mark an order as complete (POS system) -->
<%= button_to "Mark as Paid", complete_order_path(@order),
    method: :patch, class: "btn btn-success" %>

<!-- Follow a user (social app) -->
<%= button_to "Follow", follows_path,
    params: { followee_id: @user.id }, method: :post %>

Notice how every one of these examples changes something on the server. That's the pattern. If data is being written, modified, or removed, use button_to.


Real-World Example: A Blog Post Show Page

Here's what a well-structured Rails show page might look like using both helpers correctly:

<!-- app/views/posts/show.html.erb -->

<article>
  <h1><%= @post.title %></h1>
  <p class="meta">By <%= @post.author %> · <%= @post.created_at.strftime("%B %d, %Y") %></p>
  <div class="content"><%= @post.body %></div>
</article>

<div class="post-actions">
  <!-- Navigation → link_to -->
  <%= link_to "← Back to All Posts", posts_path %>
  <%= link_to "Edit Post", edit_post_path(@post) %>

  <!-- Action → button_to -->
  <%= button_to "Delete Post", post_path(@post),
      method: :delete,
      data: { turbo_confirm: "Delete this post forever?" },
      class: "btn btn-danger" %>
</div>

Notice how intuitively it reads:

  • "Back to All Posts", you're going somewhere → link_to
  • "Edit Post", you're navigating to an edit form → link_to
  • "Delete Post", you're destroying a record → button_to

Real-World Example: An E-Commerce Product Page

<!-- app/views/products/show.html.erb -->

<div class="product">
  <h1><%= @product.name %></h1>
  <p class="price">$<%= @product.price %></p>
  <p><%= @product.description %></p>
</div>

<div class="product-actions">
  <!-- Navigation -->
  <%= link_to "View All Products", products_path %>
  <%= link_to "View Reviews", product_reviews_path(@product) %>

  <!-- Actions -->
  <%= button_to "Add to Cart", cart_items_path,
      params: { product_id: @product.id },
      method: :post,
      class: "btn btn-primary btn-lg" %>

  <%= button_to "Add to Wishlist", wishlist_items_path,
      params: { product_id: @product.id },
      method: :post,
      class: "btn btn-outline" %>
</div>

Every button that does something uses button_to. Every link that goes somewhere uses link_to. That's the mental model. Lock it in.


Common Beginner Mistakes (And How to Avoid Them)


Mistake #1: Using link_to for Destructive Actions

This is the classic. You write:

<!-- Don't do this in modern Rails -->
<%= link_to "Delete", post_path(@post), method: :delete %>

In modern Rails, method: :delete on link_to is no longer handled by Rails UJS. Use data: { turbo_method: :delete } or prefer button_to for destructive actions. The anchor tag will fire a GET request by default, and your destroy action won't be triggered. Always use button_to for delete actions.

<!-- Do this instead -->
<%= button_to "Delete", post_path(@post), method: :delete %>


Mistake #2: Confusing Navigation and Actions

Sometimes beginners think: "A link and a button look different, but they do the same thing, they click."

They don't. The browser, search engines, and screen readers all treat them differently.

  • Screen readers announce <a> tags as "link" and <button> as "button"
  • Search engine crawlers follow <a href> links to index pages, they don't click buttons
  • Browsers may prefetch anchor links; they never pre-submit forms

Semantic correctness isn't just about being tidy, it affects accessibility, SEO, and user experience.


Mistake #3: Forgetting the Confirmation Dialog

When using button_to for a delete action, always add a confirmation prompt. Otherwise, one accidental click destroys data.

<!-- Dangerous — no confirmation -->
<%= button_to "Delete", post_path(@post), method: :delete %>

<!-- Safe — user must confirm -->
<%= button_to "Delete", post_path(@post),
    method: :delete,
    data: { turbo_confirm: "Are you sure you want to delete this post?" } %>

One line of code. It can save your users from a lot of heartache and save you from a lot of angry emails.


Mistake #4: Styling button_to Without Accounting for the Form Wrapper

Because button_to wraps its button in a <form> tag, sometimes your CSS layout breaks unexpectedly, especially inside flexbox or grid containers.

<!-- The form wrapper can mess up flex layouts -->
<div class="actions flex gap-2">
  <%= link_to "Edit", edit_post_path(@post), class: "btn" %>
  <%= button_to "Delete", post_path(@post), method: :delete, class: "btn btn-danger" %>
</div>

The link_to is a direct child of the flex container. The button_to button is a grandchild (the form is the direct child). Fix it by passing form_class or wrapping styles on the form:

<%= button_to "Delete", post_path(@post),
    method: :delete,
    class: "btn btn-danger",
    form_class: "inline" %>

Or in Tailwind:

<%= button_to "Delete", post_path(@post),
    method: :delete,
    class: "btn btn-danger",
    form_class: "inline-flex" %>

Small detail, but it matters when pixel-perfect layouts are involved.


Mini Recap — Your Cheat Sheet

Save this. Screenshot it. Tattoo it on your brain. 

✓ Am I taking the user somewhere?
→ Use link_to

✓ Am I doing something on the server?
→ Use button_to

✓ Is it a GET request?
→ Use link_to

✓ Is it POST, PATCH, PUT, or DELETE?
→ Use button_to

✓ Is it navigation (show, index, edit page)?
→ Use link_to

✓ Is it an action (create, update, destroy)?
→ Use button_to

✓ Does SEO or screen reader semantics matter?
→ link_to for links, button_to for buttons

✓ Am I deleting a record?
→ Always button_to with turbo_confirm


Quick Code Reference:

<!-- Navigate to a page -->
<%= link_to "View Post", post_path(@post) %>

<!-- Submit a form-like action -->
<%= button_to "Delete", post_path(@post), method: :delete %>

<!-- Navigate with styling -->
<%= link_to "Edit", edit_post_path(@post), class: "btn btn-secondary" %>

<!-- Action with confirmation -->
<%= button_to "Remove Item", cart_item_path(@item),
    method: :delete,
    data: { turbo_confirm: "Remove from cart?" },
    class: "btn btn-sm btn-outline-danger" %>


Going Deeper: The build vs new Connection

Understanding link_to and button_to is really about understanding HTTP verbs and Rails conventions. Once that clicks, a lot of other Rails concepts start making sense too, like why build and new behave differently in ActiveRecord.

If you're curious about that rabbit hole, this guide dives deep: Rails Build Vs New: Complete Guide (2025). It's the same kind of "they look similar, but they're different" situation, and mastering it will make you a much sharper Rails developer.


The Bigger Picture: Think in HTTP

Here's the mentor advice I wish someone had given me earlier:

Rails is a thin layer on top of HTTP. The more you understand HTTP, the more Rails makes sense.

Every Rails route maps to an HTTP verb:

Action: index, show
HTTP Verb: GET
Use: link_to

Action: new, edit
HTTP Verb: GET
Use: link_to

Action: create
HTTP Verb: POST
Use: button_to (or a form)

Action: update
HTTP Verb: PATCH/PUT
Use: button_to (or a form)

Action: destroy
HTTP Verb: DELETE
Use: button_to

When you start thinking this way, link_to vs button_to stops being a confusing API quirk and starts being obvious. You're not choosing between two similar helpers, you're choosing the right HTTP method for the job, and Rails gives you the right tool for each.


Keep Building

The difference between link_to and button_to might seem small at first, but it teaches an important Rails principle: choose the tool that matches the intent of the action.

If the user is navigating to another page, use link_to. If the user is creating, updating, or deleting data, use button_to (or a form).

As you continue learning Rails, you'll notice this pattern everywhere. Rails isn't just about writing code that works—it's about following conventions that make your applications more predictable, secure, and maintainable.

The next time you're unsure which helper to use, don't think about the HTML element. Think about what the user is trying to do. Navigate? Use link_to. Perform an action? Use button_to.

Mastering small concepts like this is how you gradually build a strong understanding of Rails.

Want to keep the momentum going? Here are two resources that will take you further:

  • How To Build A Blog With Ruby On Rails 8 (Step-by-Step Guide): Put everything you're learning into a real, working project. There's no better teacher than building something end-to-end.
  • Master Ruby And Rails Challenges: From Overwhelmed To Pro: Feeling like there's too much to learn? This one's for you. It's a roadmap for turning the overwhelm into a structured, achievable journey.

You've got this. Rails is one of the most productive, elegant, and joyful frameworks ever built, and every day you spend learning it is an investment that pays off in the projects you'll ship, the problems you'll solve, and the career you'll build.

Now go write some Rails. And this time, use button_to for that delete action.

Found this helpful? Share it with a fellow Rails beginner.

💌 Don’t miss out! Join my newsletter for web development tips, tutorials, and insights delivered straight to your inbox.

Thanks for reading & Happy coding! 🚀

Follow me on:

Code. Learn. Grow.

A friendly newsletter sharing dev tips, lessons, and wins from my journey.

    Services Tailored to Your Needs


    coding

    Web & Mobile Development

    Custom websites and mobile apps built to be fast, modern, and user-friendly. From sleek landing pages to full-scale applications, I deliver solutions that engage your audience and grow your business.

    API development

    Seamlessly connect your systems with secure, scalable APIs. I design and integrate APIs that improve efficiency, reliability, and flexibility for your business processes.

    Database design and management

    Reliable database solutions tailored to your needs. I design, optimize, and maintain databases that ensure performance, security, and scalability for your applications.

    You might also like…

    AI Coding Assistants: How to Use Them Smartly
    Web Development

    AI Coding Assistants: How To Use Them Smartly

    By Jean Emmanuel Cadet
    Published on: Oct 01, 2025
    Monolithic Architecture Explained: A Beginner’s Guide
    Web Development

    Monolithic Architecture Explained: A Beginner’s Guide

    By Jean Emmanuel Cadet
    Published on: May 16, 2025
    Hotwire vs React: Which Should You Pick in 2026?
    Web Development

    Hotwire Vs React: Which Should You Pick In 2026?

    By Jean Emmanuel Cadet
    Published on: Jun 06, 2026
    CodeCurious

    Designed for those who view software as architecture and code as literature.

    Legal
    Terms & Conditions Privacy Policy Disclaimer

    CodeCurious © 2025 - 2026. All rights reserved. | Made with ♥ by @jecode93