Link Generation in ERB With Rails

Posted by Flatiron School  /  November 7, 2013

The following is a guest post by Emily Xie and originally appeared on her blog. Emily is currently in the Ruby-003 class at The Flatiron School. You can follow her on Twitter here.

Last lecture, we covered Rails. Our instructor, Avi, mentioned how the level of abstraction with which Rails operates can be a double-edged sword. On one hand, it provides concision and expedition, as it neatly tucks away its complex inner workings in the Rails source code. The end result is a mode of programming that seems almost magical, as Rails’ conventions somehow so mysteriously connect the dots for you.

Conversely, its “magic” is what makes it all too easy for people to use Rails without knowledge of what goes on underneath its hood. This can be problematic, as you can run into trouble the moment you decide to write against its fixed conventions.

So that we ourselves would not become victims of this issue, Avi walked us through a few examples. Notably, he broke down how Rails abstracts the insertion of dynamic URL strings into its ERB files. So that it mentally sticks, I’ve decided to write a play-by-play, peeling away the layers of abstraction.

Old Habits

Let’s imagine that I’m building an index page in ERB, where I list out links for each frog in my database, and let’s say that there’s code that looks like this:

Blog post image: tumblr_inline_mvwhetAp381rtan47.png

On the first line, an instance variable defined in the corresponding controller, @frogs, embodies an array of ActiveRecord objects through which we iterate. On the second, we call upon the .id method for each instance of frog at the end of the path within the <a> tag, thus constructing a different link for every instance. The word “Show” represents the URL display.

So, this is how one might generate dynamic URLs via classic ERB. But let’s refactor this using some DHH magic.

The Rails Way to ERB

In Rails, we can write the second line differently––a bit more clean, like this:

Blog post image: tumblr_inline_mvwhfbyrWX1rtan47.png

The link_to method replaces the <a> tag. The first argument, Show, produces the link display. While this is straightforward enough, we see a multi-layer level of abstraction in the second half of the argument, frog, which summons an implicit method that Rails creates using the _path hook: frog_path. Concretely, it can be written as such:

Blog post image: tumblr_inline_mvwhfuQdxo1rtan47.png

frog_path calls a prefix corresponding to a URI pattern, as defined via config/routes.rb. We’ll see that in our example, it maps to a “get” request to the URI pattern of: /frogs/:id

Blog post image: tumblr_inline_mvwhgeDu6H1rtan47.png

The argument passed through frog_path is piped into the URI pattern where the :id resides. Yet, the argument itself,frog is not what you might immediately think.

Let’s back up a bit. frog is an ActiveRecord Object, which has the following output:

Blog post image: tumblr_inline_mvwhgy1xoD1rtan47.png

Understanding this, one would suspect that frog in the example above abstractly calls upon But it’s a bit more complex. There’s actually an implicit method to_params attached to the Object:

Blog post image: tumblr_inline_mvwhhiOQaP1rtan47.png

In ActiveRecord::Base, the to_params method is defined:

Blog post image: tumblr_inline_mvwhi3R56J1rtan47.png

Now, while the above is its default behavior, one can still overwrite the method to call something other than (e.g. an object’s slug). You can do it this way:

Blog post image: tumblr_inline_mvwhilglky1rtan47.png

Or further abstractly:

Blog post image: tumblr_inline_mvwhj4IiRl1rtan47.png

However, as was noted in lecture, this would open up much possibility for conflict, and would require more work on the developer’s part to ensure consistency––especially in instances with hundreds of links to consider. One can instead change the implicit call to to_params at its source by going into the Frog class, and overwriting the method definition there:

Blog post image: tumblr_inline_mvwhjvvBHl1rtan47.png