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] (http://guides.rubyonrails.org/routing.html).
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:
erb
<%= link_to edit_post_path(@post, source: 'external'), 'Edit' %>
When it is rendered, it will generate the following HTML:
html
<a href="/posts/1/edit?source=external">Edit</a>
The 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:
sh
orz $ bundle exec rake routes
It will print a list of named routes that are available inside controllers, mailers, views and helpers.
sh
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] (http://localhost:3000/rails/info/routes)
NOTE: This routes link is ONLY visible in the development environment.
Prefix
Prefix column lists the unique named routes. Normally, the named route together with a suffix _path or _url forms a helper method, e.g. new_post_path
NOTE: By appending _url, the named route path helper will generate a full URL, e.g. new_post_url
=> http://localhost:3000/posts/new
, whereas appending _path will just generate the site-relative URL, e.g. new_post_path
=> /posts/new
.
Verb
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] (http://api.rubyonrails.org/v3.2.17/classes/ActionDispatch/Request.html) for more details )
URI Pattern
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 /posts(.:format)
, the json
of URI /posts.json
will be stored in params[:format]
.
Controller#Action
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.
Examples
ruby
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] (http://api.rubyonrails.org/v3.2.17/classes/ActionDispatch/Routing/UrlFor.html#method-i-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 default_url_options.
- :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?
The url_for
method is useful when you require flexibility. Consider the following situations:
- Passing variable ActiveRecord objects to the helper, e.g. url_for(@post_or_comment)
- Specifying variable options (:controller, :action, :anchor, etc.), e.g. url_for(controller: @posts_or_comments_controller)
- Specifying the URL string, e.g. url_for('/posts')
You will find this helper very useful.
3. Polymorphic URL Helper Methods
ActionDispatch::Routing::PolymorphicRoutes#polymorphic_path
and 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_path
and 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.
Examples
ruby
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] (#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. ActionView::Helpers::UrlHelper#link_to
, ActionView::Helpers::FormHelper#form_for
, ActionController::Redirecting#redirect_to
(see [ActionDispatch::Routing::PolymorphicRoutes] (http://api.rubyonrails.org/v3.2.17/classes/ActionDispatch/Routing/PolymorphicRoutes.html))
When / Where should I apply this?
Similar to 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