NOTE: The Rails version for this article is v3.2.17. The content might not be applicable to other Rails version.
NOTE: Before we dig into the Rails routing, if you are not familiar with it, please have a read on Rails Guides: Rails Routing from the Outside In.
In this article, we will talk about three different ways to generate URLs used by Rails among controllers, mailers, views and helpers. There will be examples and some suggestions on when you should use them.
1. Named route path helper
As in most of the Rails app, you might see the following snippet:
<%= link_to edit_post_path(@post, source: 'external'), 'Edit' %>
When it is rendered, it will generate the following HTML:
edit_post_path is a registered helper method and the
edit_post is called a named route. Most Rails devs should be familiar with this as one of the Rails conventions, but especially for beginners, how does it work? We will find out in the next article.
Before that, let's take a look at how to find out all of the named routes. Run the following command in your terminal:
orz $ bundle exec rake routes
It will print a list of named routes that are available inside controllers, mailers, views and helpers.
Prefix Verb URI Pattern Controller#Action posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new edit_post GET /posts/:id/edit(.:format) posts#edit post GET /posts/:id(.:format) posts#show PATCH /posts/:id(.:format) posts#update PUT /posts/:id(.:format) posts#update DELETE /posts/:id(.:format) posts#destroy
OR open this link in the browser to view a similar output from the local rails server http://localhost:3000/rails/info/routes
NOTE: This routes link is ONLY visible in the development environment.
Prefix column lists the unique named routes. Normally, the named route together with a suffix _path or _url forms a helper method, e.g.
NOTE: By appending _url, the named route path helper will generate a full URL, e.g.
http://localhost:3000/posts/new, whereas appending _path will just generate the site-relative URL, e.g.
Verb column specifies the HTTP request method for a route. Generally, the acceptable HTTP request methods for Rails are GET, POST, PATCH, PUT and DELETE. (see constant HTTP_METHODS on ActionDispatch::Request for more details )
URI Pattern column shows the URI pattern that Rails uses to match a route. Symbols will be mapped into the
params helper method. For instance, for URI pattern
json of URI
/posts.json will be stored in
Controller#Action column shows the corresponding controller and action to which Rails will dispatch the HTTP request.
When / Where should I apply this?
If you know exactly what the path or URL is that you are going to generate, you should use the named route path helper methods. By using it, your code will become more readable.
2. URL helper method
ActionDispatch::Routing::UrlFor#url_for is the URL helper method. It generates a URL based on the options supplied. It is pretty flexible in that it accepts either a string, an ActiveRecord object, an options hash, or an argument list array.
Let's take a glimpse at some examples and see how powerful it is.
url_for('/posts') # => /posts url_for(@post) # => http://localhost:3000/posts/1 url_for(controller: :comments, post_id: @post.id) # => http://localhost:3000/posts/1/comments url_for([@post, :comments]) # => http://localhost:3000/posts/1/comments url_for([@post, routing_type: :path]) # => /posts/1 url_for([@post, :comments, slug: 'reinteractive', only_path: true]) # => /posts/1/comments?slug=reinteractive url_for([:admin, :posts, format: :js]) # => http://localhost:3000/admin/posts.js
It accepts the following hash options, you could find this in the API document #url_for:
Options for URL helper method
- :only_path - If true, the relative url is returned. Defaults to false.
- :protocol - The protocol to connect to. Defaults to 'http'.
- :host - Specifies the host the link should be targeted at. If :only_path is false, this option must be provided either explicitly, or via defaulturloptions.
- :subdomain - Specifies the subdomain of the link, using the :tld_length to split the subdomain from the host. If false, removes all subdomains from the host part of the link.
- :domain - Specifies the domain of the link, using the :tld_length to split the domain from the host.
- :tld_length - Number of labels the TLD id composed of, only used if :subdomain or :domain are supplied. Defaults to ActionDispatch::Http::URL.tld_length, which in turn defaults to 1.
- :port - Optionally specify the port to connect to.
- :anchor - An anchor name to be appended to the path, as in "/archive#2009"
- :trailing_slash - If true, adds a trailing slash, as in "/archive/2009/"
- Any other key (:controller, :action, etc.) given to url_for is forwarded to the Routes module.
Additionally, you might come across this option in the source code:
- :routing_type - Specifies which type of URL it should be, relative or full. Value can be :url or :path. Defaults to :url.
When / Where should I apply this?
url_for method is useful when you require flexibility. Consider the following situations:
- Passing variable ActiveRecord objects to the helper, e.g.
- Specifying variable options (:controller, :action, :anchor, etc.), e.g.
- Specifying the URL string, e.g.
You will find this helper very useful.
3. Polymorphic URL helper methods
ActionDispatch::Routing::PolymorphicRoutes#polymorphic_url are the polymorphic URL helpers which can handle either an ActiveRecord object, an options hash, or an Array. Under the hood,
polymorphic_url is called by
url_for, and both
polymorphic_url can be prefixed with new_ and edit_. In other words, the polymorphic URL helpers wrap the
url_for method to provide better object support, although they can't handle plain strings.
polymorphic_path(@post) # => /posts/1 polymorphic_url([@post, @comment]) # => http://localhost:3000/posts/1/comments/1 edit_polymorphic_path(@post) # => /posts/1/edit new_polymorphic_path(:post) # => /posts/new
NOTE: The options for URL helper method are also applicable for polymorphic URL helper methods.
Polymorphic URL helper methods are very powerful and they've been used in a lot of places throughout rails, e.g.
ActionController::Redirecting#redirect_to (see ActionDispatch::Routing::PolymorphicRoutes)
When / Where should I apply this?
url_for, the situations where polymorphic urls are very useful are when you have a dynamic argument. Imagine you had a homepage where you wanted an edit link for the latest post or the latest comment by the current user in a sidebar. You could call the method like this:
edit_polymorphic_url(@post_or_comment). In this case it would also be trivial to check the class of the object, but that approach becomes unwieldy when you have more than just a couple of classes to consider.
When building an engine or a gem that abstracts functionality without necessarily knowing which classes it is working with, helpers like this will help immensely to keep your code clean.
We will continue to explain how the named routes works in next article Part 2
The benefits of code reviews
Strategies to make remote work successful
A holistic approach to your web application
reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.
We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.
Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.
The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.
The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.