Welcome to Part 2 (you are reading) of our Rails Web Navigation tutorial!
In Part 1, we embarked on a cosmic journey through the Rails galaxy, exploring the intricacies of the Rails web navigation system. We delved deep into how Rails handles web requests, understanding the celestial dance between ActionController and ActionView. We also navigated the Middleware Nebula, gaining insights into the pivotal role middlewares play in processing web requests.
Having laid the groundwork in Part 1, we're now poised to dive into the heart of web navigation in Rails. In this part, we'll focus on the magic of the link_to and button_to helpers, starting with the ever-versatile link_to. These helpers are the unsung heroes that power the seamless navigation experience we often take for granted. So, without further ado, let's dive right in!
Great, let’s get started!
TABLE OF CONTENTS (Part 2)
link_to
link_to
Definition
Let me guess, you found your way to this page by clicking on a link from another page, right? That's the beauty of the anchor element, which creates links between pages, files, and locations or external pages.
In the world of Rails, we have amazing helper methods, including link_to
, that makes navigating through your Rails application a breeze. This helper generates an HTML <a href=" ">...</a>
tag that directs you to a specified URL target. Here's the basic format of a link_to
tag and its corresponding HTML link:
<span><%= link_to "AvoHQ", "https://avohq.io/" %></span>
# => <a href="https://avohq.io/">AvoHQ</a>
# Assuming you have a User model and a corresponding user_path helper.
<p><%= link_to user.name, user_path(user) %></p>
# => <a href="/users/123">Adrian M</a>
<li><%= link_to car.type, car_path(@car) %></li>
# even better
<li><%= link_to car.type, @car %></li>
# => <a href="/cars/1">Tesla</a>
As you can see, with link_to
, all you need is a string of text AvoHQ
for the link's visible name, followed by the path to the destination URL. But that's not all link_to
can do! It's able to recognize instances and generate related paths for them. This is useful when you have a list of items (objects) and you want to redirect the user to the show page of the selected item. In the example given, we are redirecting the user to the page of a car
, where @car
represents a specific instance of a car
.
link_to
Syntax
As we discovered earlier, the link_to
helper method is pretty useful for creating anchor tags that link to specified URL targets. But did you know that the method's full syntax is even more powerful? That's right! The complete method signature includes additional parameters that allow you to customize the link even further. Here's the full signature of the link_to
method:
**link_to**(name = nil, options = nil, html_options = nil, &block)
Let's break it down.
The link_to
method accepts several parameters, with some being mandatory and others optional.
name
: This parameter by default isnil
. It is the text that appears as the link's visible text. It is what you see on the page. Ifname
isnil
, the URL is used as the link visible text.name
can be string, image tag, or a combination of both as we will see soon.
<li><%= link_to 'Home', root_path %></li>
# => <a href="https://avohq.io/">Home/</a>
<span><%= link_to "https://avohq.io/" %></span>
# => <a href="https://avohq.io/">https://avohq.io/</a>
options
: is another parameter thatlink_to
accepts. By default, it isnil
. It is responsible for defining the URL or route for the link. If it is a string, it is represented as the URL of the link. If it is a hash, it follows the defined route. There are two styles of routes: the older-style parameters routes, which no one uses anymore, and the new-style named routes.
The older-style parameters routes use the keys controller
, action
, and id
to specify the controller, action, and ID of the resource being linked to, respectively. It is not recommended to use this style of routing anymore.
link_to "User", controller: "users", action: "show", id: @user
# => <a href="/users/show/1">User</a>
- And there's the current Rails style of RESTful routes, which is considered better practice.
link_to "User", @user
# => <a href="/users/1">User</a>
html_options
is another parameter that thelink_to
accepts. It isnil
by default, and it is used to define HTML attributes that will be added to the link'sa
tag. You can use this parameter to addclass
,id
,target
,rel
,type
, anddata
attributes to the link, among others. By doing this, you can customize the link's behaviour and appearance.
link_to 'AvoHQ', 'https://avohq.io', class: 'to_home', target: '_blank'
# => <a href="https://avohq.io" class="to_home" target="_blank">AvoHQ</a>
# Adding a class and id to the link
link_to "AvoHQ", "https://avohq.io/", class: "btn btn-primary", id: "avohq-link"
# => <a href="https://avohq.io/" class="btn btn-primary" id="avohq-link">AvoHQ</a>
Here we create a link to AvoHQ's homepage with the visible text AvoHQ
. Additionally, it includes CSS class
and target
attributes that are added to the a
tag of the link.
link_to "Avo Blog", posts_path, id: "blog", class: "avo_blog"
# => <a href="/posts" class="avo_blog" id="blog">Avo Blog</a>
This code generates a link to AvoHQ's blog page with the text Avo Blog
and a CSS
and id
attributes added to the link's a
tag.
link_to "Comment section", user_path(@user, anchor: "section")
# => <a href="/users/1#section">Comment section</a>
This code generates a link to the comment section on the same user show page with the text Comment section
and an anchor
attribute added to the link to target that specific section.
link_to "Avo Home", "http://www.avohq.io/", target: "_blank", rel: "nofollow"
# => <a href="http://www.avohq.io/" target="_blank" rel="nofollow">Avo Home</a>
This code generates a link to the Avo home page with the text Avo Home
, and it also adds the target
and rel
attributes to the link's a
tag.
link_to "Avo search", controller: "searches", query: "ruby on rails admin panel"
# => <a href="/searches?query=ruby+on+rails+admin+panel">Avo search</a>
This code generates a link to the search page with the text Avo search
. In addition, a controller
with the name 'searches' and a query
attribute with the value 'ruby on rails admin panel' are added to the link's a
tag.
&block
parameter is optional and isnil
by default. It's not used often but can be useful for making the code more readable and easier to understand. Imagine you have a long text that is hard to fit into thename
parameter. In this case, you can pass the link text inside a block of code that generates the content of the link.
<%= link_to(@car) do %>
<strong><%= @car.name %></strong> -- <span>Check this car!</span>
<% end %>
<a href="/cars/1">
<strong>Tesla</strong> -- <span>Check this car!</span>
</a>
<%= link_to "https://avohq.io/" do %>
<strong>AvoHQ</strong> - The Best Rails Guide
<% end %>
<a href="https://avohq.io/">
<strong>AvoHQ</strong> - The Best Rails Guide
</a>
Another example:
<%= link_to blog_path(@blog) do %>
<i class="fa fa-pencil"></i> # fontawesome icons
Edit
<% end %>
# =>
<a href="/blogs/1">
<i class="fa fa-pencil"></i>
Edit
</a>
As you can see, this code generates a link to the show
action of the BlogController
, passing the @blog
ID as a parameter. The link's content will consist of a Font Awesome icon and the text Edit
.
So far, we learned how link_to
works in its default mode, which is the GET request. To refresh your memory, do you remember our fancy diagram from earlier? It illustrated the communication between the browser and the server, where a method was used to deliver the message of what the browser wants the server to do. If you don't recall, don't worry, it's normal to forget things. In this case, the localhost/jobs
URL is clicked by a user, and a successful request with a 200/OK
response takes the user to the Jobs
page, which uses the GET
request method.
Delete with link_to
Did you know that there's another way link_to
can navigate? Yes, it's true! This method uses a DELETE request to delete a record or a specific instance. Let's say you have a @post
instance and you want to delete it. In order to call the destroy
action on the PostController
, you need to use the DELETE
request method. You can achieve this by passing the method: :delete
hash as an option to the link_to
helper. For example:
%%On the same token, you will be able to pass any method defined in your controllers to the link_to
helper. Here is how to use delete
method:%%
<%= link_to "Delete post", post_path(@post), method: "delete" %>
# => <a rel="nofollow" data-method="delete" href="/posts/1">Remove</a>
It is worth noting that the rel="nofollow"
attribute is automatically added by Rails 'magic' as an added benefit for Search Engine Optimization (SEO).
Delete Link With Confirmation
Deleting a record is a necessary action, but it can be harsh and irreversible. To ensure that the user agrees to such a drastic action, we developers might want to prompt them with a message asking for confirmation and to prevent accidental deletion using confirm
method { confirm: "Are you sure?" }
. The easiest way to add this feature is with a simple JavaScript alert box that will ask the user to confirm their delete request. Guess what, Rails magic does it for you, again. The alert can be implemented as shown below:
<%= link_to "Delete post", post_path(@post), method: "delete", { confirm: "Are you sure?" } %>
# => <a data-confirm="Are you sure?" rel="nofollow" data-method="delete" href="/jobs/1">Delete Post</a>
Ajax links with remote
Ajax links, the superheroes of asynchronous requests that allow you to dynamically update your page content without the irritating full-page reloads. To create an Ajax link, all you need to do is use the link_to
method with the remote: true
. For instance, the following code creates an Ajax link that sends a GET request to the server when clicked:
<%= link_to "Load More", "https://avohq.com/more", remote: true %>
When clicked, this link triggers an Ajax request to the specified URL, allowing your web page to update without any hiccups. With the power of JavaScript or other client-side technologies such as Hotwire as we will discover soon, you can even process and display the server's response on your page.
Variants
Rails not only empowers you with the link_to
magic implementation, but it has more variations up its sleeve! Oh, yeah! Each of these variants helps you avoid complex code and makes your code clean by doing a specific communication job. These variants are:
link_to_unless_current(name, options = {}, html_options = {}, &block)
Want to create a link only if it's not the current page? Trylink_to_unless_current
! It creates a link but returns the name instead if it's the current page.
<ul>
<li><%= link_to_unless_current "Cars", cars_path %></li>
<li><%= link_to_unless_current "Dashboard", dashboard_path %></li>
</ul>
# When you are on `/cars`, this template will output:
# =>
<ul>
<li>Cars</li>
<li><a href="/dashboard">Dashboard</a></li>
</nav>
link_to_if(condition, name, options = {}, html_options = {}, &block)
Want to create a link only under certain conditions? Uselink_to_if
! It creates a link using options if a condition is true, otherwise it returns the name.
<li>
<%= link_to_unless(@current_user.nil?, 'Log In', new_user_registration_path %>
</li>
# If the user is NOT logged in...
# =>
<li><a href="/users/signin/">Log In</a></li>
link_to_unless(condition, name, options = {}, html_options = {}, &block)
Looking for a way to create a link only when a certain condition is false? Trylink_to_unless
! It creates a link tag using a URL from options unless the condition is true, otherwise, only the name is returned.
<li>
<%= link_to_unless(@current_user.nil?, 'Log In', new_user_registration_path %>
</li>
# If the user is logged in...
# =>
<li><a href="/users/signin/">Log In</a></li>
Hotwire with link_to
If you think you have seen enough Rails magic, you are mistaken my friend. Rails have a new trick up its sleeve: Hotwire. And with the magical Turbo tool that comes with it, you can create modern, interactive web applications with minimal, or sometimes no JavaScript at all, providing users with an incredibly smooth experience.
One of Turbo's key instruments is Drive, which enhances page-level navigation. It watches for link clicks and form submissions, performs them in the background, and updates the page without doing a full reload. And let me tell you, that's pretty darn amazing.
link_to
default uses Turbo Drive for non-GET
(POST
, DELETE
) requests, making it simple to create links that update the page content without a full reload. Perfect for actions like deleting, creating/updating records and displaying more content.
For example, let's say you want to create a link that uses Hotwire to submit a DELETE
request to the server, with a confirmation dialog for the user to approve. Well, look no further:
<%= link_to
"Delete Post",
post_path(post),
method: :delete,
data: { turbo_confirm: "Are you sure?" }
%>
When clicked, this link sends a DELETE
request to the server and displays a confirmation dialog for the user, (we have seen this before, nothing new here, right)! Turbo then processes the server response, and the page content is updated without a full page reload (That's magic). This feature makes it easy to create interactive web applications with minimal or no JavaScript and a smooth user experience. Why not give it a try and see the magic for yourself?
link_to
Conclusion
Phew, it has been a journey. We've navigated our way through the astonishing Rails web navigation system. link_to
is one of the powerful tools in Rails world. Effortlessly, you can generate HTML tags that glide you to pages, files, and beyond. Its signature is versatile that you can add blocks, instance variables, media, confirmation messages, and even delete objects. Additionally, it offers seamless variants, making link creation clutter-free, logical and magical.
button_to
button_to
Definition
Similar to link_to
, button_to
is another handy helper method in Rails that creates a button element with a specified action. This helper generates a nifty HTML form <form action=" "><button>...</button></form>
tag that performs the specified action submit
when clicked. Here's the basic format of a button_to
tag and its corresponding HTML form:
<%= button_to "Delete", post_path(@post), method: :delete %>
# =>
<form action="/posts/1" method="post">
<input type="hidden" name="_method" value="delete" />
<input type="submit" value="Delete" />
</form>
As you can see, with button_to
, you need to specify the action (in this case, Delete
), followed by the path to the destination URL (post_path(@post)
), and the method used for the action (method: :delete
). When clicked, this button sends a DELETE
request to the specified URL. button_to
. And that's not all! button_to
accepts other options such as :class
, :disabled
, and :form_class
to customize the form element and its children.
It's particularly useful for actions that require more than a simple link, such as creating or deleting records in a database. By default, button_to
generates a form element with a hidden
input for the method and a submit button with the specified label, making it easy to perform complex actions without having to write a lot of HTML and JavaScript code.
button_to
Syntax
Ah, button_to
- another gem in the Rails toolbox! As we discovered earlier, button_to
is a helper method that generates a form element with a specified action, which is executed when the button is clicked. By now you would know that the method's full syntax is even more powerful. The complete method signature includes additional parameters that allow you to customize button_to
even further. Here's the full signature of the button_to
method:
**button_to**(name = nil, options = nil, html_options = nil, &block)
Let's break it down.
name
: This parameter is optional and represents the text that appears on the button. If noname
is provided, thebutton_to
method will use the URL as the button text. You can use a string, an image tag, or a combination of both as thename
argument.
<li><%= button_to "Delete", post_path(@post), method: :delete %></li>
# =>
<form action="/posts/1" method="post">
<input type="hidden" name="_method" value="delete" />
<input type="submit" value="Delete" />
</form>
options
: This parameter is optional and can take several forms. If it is a string, it is interpreted as the URL of the button's destination. If it is a hash, it can include a:controller
,:action
, and:id
keys to specify the controller, action, and ID of the resource being linked to, respectively (Similar tolink_to
). Other options include:method
to specify the HTTP method used for the action (e.g.,:post
,:put
,:delete
), and:data
to specify additional data to be sent with the request.
The options
parameter of button_to
can take a hash with additional options, like :params
, which specifies any additional parameters to be sent with the request. Here's an example:
button_to "New Article", new_article_path, params: { time: Time.now }
# =>
<form action="/articles/new" method="post">
<input type="hidden" name="authenticity_token" value="[AUTH_TOKEN]" />
<input type="hidden" name="time" value="[CURRENT_TIME]" />
<button type="submit">New Article</button>
</form>
Here, a form element is generated with an action of /articles/new
and a method of post
. The params
option is used to add a hidden input field named time
with the value of the current time. When the button is clicked, the form is submitted and the specified action is performed on the server.
html_options
is an optional parameter of thebutton_to
, Isnil
by default and used to add HTML attributes to the button'sform
andbutton
tags. Here are some examples of using the varioushtml_options
:
:method
: This option specifies the HTTP verb (delete
) to be used for the form submission. Here's an example:button_to "Delete", post_path(@post), method: :delete # => <form action="/posts/:id" method="post"> <input type="hidden" name="_method" value="delete" /> <input type="submit" name="commit" value="Delete" data-disable-with="Delete" /> <input type="hidden" name="authenticity_token" value="[AUTH_TOKEN]" /> </form>
:disabled
: This option generates a disabled button. Here's an example:button_to "Save", save_path, disabled: true # => <form action="/save" method="post"> <input type="hidden" name="authenticity_token" value="[AUTH_TOKEN]" /> <button type="submit" disabled="disabled">Save</button> </form>
:data
: This option is used to add custom data attributes. Here's an example:button_to "Submit", submit_path, data: { confirm: "Are you sure you want to submit?" } # => <form class="button_to" method="post" action="/submit"> <input type="hidden" name="_method" value="post"> <input type="hidden" name="authenticity_token" value="[AUTH_TOKEN]"> <button data-confirm="Are you sure you want to submit?" type="submit">Submit</button> </form>
:remote
: This option allows the unnoticeable JavaScript drivers to control the form's submission behaviour. By default, this is an AJAX submit. Here's an example:button_to "Delete", post_path(@post), method: :delete, remote: true # => <form class="button_to" method="post" action="/posts/1" data-remote="true"> <input type="hidden" name="_method" value="delete" /> <input type="hidden" name="authenticity_token" value="[AUTH_TOKEN]" /> <button>Delete</button> </form>
:form
: This option is a hash of attributes to be added to theform
tag. Here's an example:button_to "Create", create_path, form: { id: "create-form", class: "create-form" } # => <form accept-charset="UTF-8" action="/create" class="create-form" id="create-form" method="post"> <input type="hidden" name="authenticity_token" value="[AUTH_TOKEN]" /> <button name="button" type="submit">Create</button> </form>
:form_class
: This option is used to specify the class of the form within which the submit button will be placed. Here's an example:button_to "Save", save_path, form_class: "save-form" # => <form action="/save" class="save-form" method="post"> <input type="hidden" name="authenticity_token" value="[AUTH_TOKEN]" /> <button type="submit"> Save </button> </form>
:params
: This option is a hash of parameters to be rendered as hidden fields within the form. Here's an example:
button_to "New Car", new_car_path, params: { time: Time.now }
# =>
<form action="/cars/new" method="post">
<input type="hidden" name="time" value="[CURRENT_TIME]" />
<button type="submit">New Car</button>
</form>
&block
is an optional parameter of thebutton_to
. It isnil
by default and can be used to generate custom content for the button. This is useful when you want to add an icon or other custom HTML to the button.
<%= button_to post_path(@post) do %>
<i class="fa fa-trash"></i> # fontawesome icons
Delete
<% end %>
# =>
<form action="/posts/1" method="post">
<input type="hidden" name="_method" value="delete" />
<button type="submit">
<i class="fa fa-trash"></i>
Delete
</button>
</form>
This code will generate a delete button with an icon and the text Delete
. The block is used to generate the content of the button, which is then wrapped in a form that sends a DELETE
request to the specified path when clicked. Get creative with your buttons and make them stand out!
<%= button_to user_path(@user) do %>
<%= image_tag("delete.png") %>
<% end %>
# =>
<form action="/users/1" method="post">
<input type="hidden" name="_method" value="delete">
<button type="submit">
<img src="/assets/delete.png">
</button>
</form>
This will create a button with an image of a trash can that, when clicked, sends a DELETE request to the path specified by user_path(@user)
.
Submit with options
Another example of button_to
wtih few options
and html_options
.
So, what we have here is a button_to
method that generates a form with a button inside. This button is used to generate a short summary of a company's description using AI.
<%= button_to "Generate Description Summary",
description_summary_company_path(@company),
method: :patch,
class:'btn bg-indigo-50 disabled:opacity-50',
data: { disable_with: "A short description summary in the making..."}
%>
# =>
<form class="button_to"
method="post"
action="/startups/gamucatex/description_summary">
<input type="hidden" name="_method" value="patch" autocomplete="off">
<button class="btn bg-indigo-50 disabled:opacity-50"
data-disable-with="A short description summary in the making..."
type="submit">
Generate Description Summary
</button>
<input type="hidden"
name="authenticity_token"
value="yTWxr5_58rb_LqRQl36wgQpFh9K7a....."
autocomplete="off">
</form>
The generated HTML code includes a form
tag with a method
of `post`
and an action
attribute set to the description_summary_company_path
route. The method
is overridden by the method
option, which sets it to `patch`
because most browsers don't support methods other than `GET`
and `POST`
when it comes to submitting forms. Amazingly, Rails works around this issue by matching other methods over POST
with a hidden input named "_method"
, which is set to reflect the desired method patch
.
The HTML options include a class
attribute, which sets the CSS class for the button to `btn bg-indigo-50 disabled:opacity-50`
. This will give the button a nice background colour and make it slightly transparent when disabled. I'm using TailwindCSS for styling.
There is a data
attribute with a disable_with
key that sets the text to display when the button is clicked, which is A short description summary in the making...
. This helps to provide feedback to the user that the button is doing something.
Finally, the generated HTML code includes a hidden input tag with a CSRF token authenticity_token
is included to protect against cross-site request forgery (CSRF) attacks.
Hotwire with button_to
Similar to link_to
, Hotwire and it's tools, can enhanced button_to
to create modern, interactive web applications. By default, button_to
generates a form with a button that sends a POST
request to the server when clicked. However, with Hotwire and the Turbo
tool, button_to
can be used to create smooth, fast user experiences without a full page reload.
For example, let's say you want to create a button that sends a DELETE
request to the server, with a confirmation dialog for the user to approve. With Hotwire, you can use the data-turbo-confirm
attribute to display a confirmation dialog to the user, just like with link_to
. Here's an example:
<%= button_to
"Delete Post",
post_path(post),
method: :delete,
data: { turbo_confirm: "Are you sure?" }
%>
When you click the button created with button_to
, it will submit a DELETE
request to the server and show a confirmation dialog, similar to link_to
. Then Turbo comes in, processes the server response, and voila! The page content is updated without any page refresh with little or no JavaScript.
button_to
Conclusion
Well, well, well. We've been exploring the magnificent world of Rails navigation tools, and button_to
is yet another powerful one.
This incredible helper method allows us with minimal effort, you can create buttons that can perform a variety of actions such as submitting forms, sending requests to the server, and updating page content. button_to
also supports various options such as method
, params
, class
, and data
, allowing for even more flexibility and customization. And with the integration of Hotwire, button_to
can provide users with a smooth and fast experience without the need for excessive JavaScript. Overall, button_to
is a valuable addition to any Rails developer's toolkit.
Final Words
After all is said and done, link_to
and button_to
are both amazing helpers in the Rails world. With the help of Hotwire and Turbo, they offer fast and smooth navigation without needing to write tons of JavaScript. Whether you need to generate simple links or complex buttons, these helpers have got you covered. So, go ahead and use them to create your own magical and interactive web applications with ease!
Frequently Asked Questions (FAQs)
What is
link_to
andbutton_to
in Rails?link_to
andbutton_to
are helper methods in Ruby on Rails that generate HTML links and buttons, respectively. They are commonly used in views to create hyperlinks and form submissions that send requests to the server.What is the difference between
link_to
andbutton_to
?The main difference between
link_to
andbutton_to
is thatlink_to
generates a hyperlink that navigates the user to a new page, whilebutton_to
creates a form that submits a request to the server without navigating to a new page. However, both methods can be configured to use Ajax requests with Hotwire Turbo Drive in Rails 7, which is amazing!How do I use
link_to
andbutton_to
in Rails?Both methods accept three required parameters: the link text or button label, the URL to which the request should be sent, and the HTTP method to use (
GET
,POST
,PATCH
,PUT
,DELETE
).link_to
also accepts optional parameters for specifying attributes such asclass
,id
, anddata
.button_to
accepts similar optional parameters, such asmethod
,remote
,form_class
, andparams
.How do I add a confirmation message to
link_to
andbutton_to
?You can add a confirmation message to
link_to
andbutton_to
by including thedata: { confirm: "Are you sure?" }
option. When the link or button is clicked, a confirmation dialog box will be displayed with the specified message.How do I add custom HTML to
link_to
andbutton_to
?
You can use a block to add custom HTML tolink_to
andbutton_to
. Simply wrap the link text or button label in a block and include any additional HTML or Ruby code inside the block. For example:<%= link_to post_path(@post) do %> <i class="fa fa-pencil"></i> Edit Post <% end %>
Can I use
link_to
andbutton_to
with Rails Hotwire?Yes, you can use
link_to
andbutton_to
with Rails Hotwire by adding thedata-turbo="false"
attribute to the link or button. This will disable Turbo Drive for that link or button, and the request will be processed with a full page reload. Alternatively, you can configurelink_to
andbutton_to
to use Turbo Drive for non-GET
requests by default in Rails 7 and later versions.