- Read Tutorial
- Watch Guide Video
This tutorial will walk through how to implement the link_to method in Rails in order to dynamically generate links to other pages of an application.
Now that we have the ability to create new portfolio items and edit them, let's build the functionality to navigate to those items. So far, we've had to go the browser URL and type something like "localhost:3000/portfolios/new". While that's not very efficient, it becomes difficult when we want to edit an item because we have to find the ID of that particular record and type it in the browser. That is definitely not going to be a good user experience.
Creating a Link
In this guide, we'll create a button that will take us to the edit page of a particular portfolio item automatically. There are a few ways to do this.
We already know what our routes are. So, if you type rake routes | grep portfolio
, this will bring up all the routes associated with portfolio.
There are a couple of ways to work on this. First, I'm going to show you the manual way, then I'll show you the Rails way. I think it's important to understand both of these options.
Start the rails server and then open your views/portfolios/index.html.erb
file in sublime. This file has our list of portfolio items.
<h1>Portfolio Items</h1> <% @portfolio_items.each do |portfolio_item| %> <p><%= portfolio_item.title %></p> <p><%= portfolio_item.subtitle %></p> <p><%= portfolio_item.body %></p> <%= image_tag portfolio_item.thumb_image unless portfolio_item.thumb_image.nil? %> <% end %>
At the top of the page, I'm going to put a link <a href=""></a>
to the new option. This link will take us to the page where we can create a new portfolio item. Since we know what our routes are based on what is returned by rake routes, we can simply put the corresponding route portfolios/new
inside the double quotes of the href
in our anchor tag. You can give the link whatever name you like, but I’m going to use Create New Item
. Your link should look like this:
<h1>Portfolio Items</h1> <a href=“portfolios/new”>Create New Item</a>` <% @portfolio_items.each do |portfolio_item| %> <p><%= portfolio_item.title %></p> <p><%= portfolio_item.subtitle %></p> <p><%= portfolio_item.body %></p> <%= image_tag portfolio_item.thumb_image unless portfolio_item.thumb_image.nil? %> <% end %>
If you save the file and refresh the browser, you'll see the create link at the top of the page.
If we click on this link, it'll take us to the new page. This is the manual way of creating a link.
Using the Link_to Method
Rails provides a much better way of implementing this functionality, and this is through a tool called link_to
. I'm going to use some embedded ruby, so we'll the use the angle bracket, the percent sign, and the equal sign, followed by the link_to method.
<%= link_to %>
Next we pass in the description as a string. We have to use the string format because we are using Ruby right now.
<%= link_to “Create New Item”, %>
Now we pass in the page we actually want to link to. Let’s switch back to the terminal, we want to look at our rake routes table, specifically the Prefix
items. This is an instance where you can use these. Each one of these Prefixes have their own specific purpose in their methods. Specifically, instead of having to hard code our values with something like /portfolios/new
, we can actually use the prefix as a method. So we will use new_portfolio
and the method will generate the URL for us. Notice that portfolio is singular. We also need to add the word path
.
<%= link_to “Create New Item”, new_portfolio_path %>
Make sure you have closed your tag off with the ending bracket. %>
Now save your file and refresh your browser and you will see two links. Both will take us to the same page
Path vs URL
Now, you may be wondering why we added the word path when in the terminal it just listed new_portfolio
. Remember the items in the first column of the routes table are called Prefixes, which means they have an option. Accordingly, they can either end in path
or url
We can test these values by displaying them in the browser. I'm going to create two paragraph tags and have the new_portfolio_path
in one. Next, I'll copy the code and change path
to url
, so we can discern the difference.
<p> <%= new_portfolio_path %> </p> <p> <%= new_portfolio_url %> </p>
Save the file and refresh the browser and this is what you will see.
So the Path
just the portion after the URL, portfolios/new
, the term for this is the relative path
. It means, the path relative to the actual URL. This is what you're usually going to do. I estimate I use this 80% of the time.
However, the url
version can very useful in some specific circumstances. In fact, for DevCamp, I've needed to use the URL version almost exclusively because the URL option takes some other optional values such as a subdomain. For example, here, where I use the URL version I can pass another method called subdomain
<%= link_to “Create New Item”, new_portfolio_url, subdomain: ‘my_subdomain’ %>
If I had a subdomain
configured, then this link would actually go to that sub domain. We don’t, so that wouldn't work for our app.
The other reason to use URL is when sending an email. Imagine you're sending a link in your email. You can’t just use the relative path because the email doesn't know what URL you're referring to.
So, that's how we can use the link_to
method. Let's revert back to our previous code, by removing the subdomain portion. I'm also going to remove the manual portion. So, the only code that'll be present is:
<h1>Portfolio Items</h1> <%= link_to "Create New Item", new_portfolio_url %> <% @portfolio_items.each do |portfolio_item| %> <p><%= portfolio_item.title %></p> <p><%= portfolio_item.subtitle %></p> <p><%= portfolio_item.body %></p> <%= image_tag portfolio_item.thumb_image unless portfolio_item.thumb_image.nil? %> <% end %>
Links for Individual Items
Similar to the ‘Create New Item’ link we just built, we can also add an edit
link for each portfolio item. For creating a new item, it makes sense to have it right at the top of the page because you don't want to have multiple links for creating a new item. However, for edit, you want to have a link for each portfolio. The way we can do that is to create another link_to
tag, and place it inside the loop.
We will start with our link_to tag, then add a string for the link description:
<%= link_to "Edit",
Now we need the path. Let’s be methodical about this and go back and check our routes with the rake routes
command. I'm showing you this step because I want you to know how the process works. Also, when you're no longer using a tutorial, but building out your own application, I want you to know what my process is for referencing which route I need to use. Just so, the first thing I'll do is run rake routes
then look for the route I want in the prefix column. I’m looking for the prefix for the edit action, which will be, edit_portfolio
.
Now, I can come back to the code and type the route path. Here, it'll be
<%= link_to "Edit", edit_portfolio_path %>
An important thing to note here: remember when we looked at the URI string for editing? A sample would be "/portfolios/5/edit". This is important to think about because in the route, we need an id
so that we can let Rails know which incidence of the item we are sending through, so the system knows which portfolio to edit.
We're going to send this id
by way of an argument inside the method, just like this:
<%= link_to "Edit", edit_portfolio_path (portfolio_item.id) %>
The file should read like this:
<h1>Portfolio Items</h1> <%= link_to "Create New Item", new_portfolio_url %> <% @portfolio_items.each do |portfolio_item| %> <p><%= portfolio_item.title %></p> <p><%= portfolio_item.subtitle %></p> <p><%= portfolio_item.body %></p> <%= image_tag portfolio_item.thumb_image unless portfolio_item.thumb_image.nil? %> <%= link_to "Edit", edit_portfolio_path(portfolio_item.id) %> <% end %>
If you save and refresh the browser, you can see that each one of these items has an "edit" link. If you click on the link, it will take you to the correct record. Try a few to verify it is working properly.
Why the ID doesn't match the Title Number
If you're wondering why the ID is one number greater than the number in title, for example, the URL is "/7/edit", but the title displays "Portfolio title:6", this is due to a bit of computer science logic. The number in the title is not the id. It is just the incidence number given by our seeds file where we used the block variable inside our string interpolation. Those instances begin with 0, therefore our first blog is "Portfolio title:0". Alternatively, inside of edit, the system is parsing the id, which begins with the number 1.
So, all of the links are working fine. One last thing I want to note: if you right-click on edit and choose the option called "Inspect", a small pane will open in the browser and will show the code generated.
Incidentally, our browsers don't know to interpret Rails code, they can only read HTML and Javascript. This is why Rails takes a method like link_to
and converts it into an HTML link, or in other words an <a>
tag. Here you can see it converted it with the appropriate URL and the word edit.
Technically, we can manually create these types of links. So, I want to create another one. I can simply put the link and create a string interpolation for the ID. <a href=“/portfolios/#{portfolio_item.id}/edit”>Edit Two</a>
That didn’t work. Sorry, I wasn't passing Ruby code here. I need to use ERB implementation instead of string interpolation.
- <a href=“/portfolios/#{portfolio_item.id}/edit”>Edit Two</a> + <a href=“/portfolios/<%= portfolio_item.id %>/edit”>Edit Two</a>
What I'm doing here is inserting my portfolio ID into the URL, so the link can take you to the right record for editing. If you refresh the browser now, and do another inspect, you'll see that this is generating a link that is identical to the link_to method link.
However, using the link_to
method is a cleaner way of writing code as it much easier to read.
Since it is unnecessary, remove the manual link. Save, and we are ready to commit.
git status
git add .
git commit - m ‘Added new and edit buttons for portfolio items’
git push origin portfolio-feature
In our next guide we will work on a show link!