Ruby on Rails – ODIN Project – 2

odinRoutes, Views, Controllers and Assets

We will start looking carefully into the foundational pieces of the Rails framework. We’ll cover the path of an HTTP request from entering your application to returning as an HTML page to the browser.


Step 1: Routing

The router is the switchboard of your app, telling requests which controller action they’re supposed to run.

Introduction

The router is the doorman of your application. When an HTTP request arrives from the user’s browser, it needs to know which controller action (method) should be run. Should we display the “new user” webpage? Should we edit an existing user with whatever data got sent along?

The Router is basically just a matching service. It looks at the HTTP verb (GET, POST, PUT, DELETE) and the URL that it being requested and matches it with the appropriate controller action to run. It’s a pretty simple function but an essential one. If it can’t find a route that matches the request, your application will throw an error.

The other handy thing that goes on when a request enters your application is that Rails grabs all the parameters that came with it and makes them available for you in a special hash called params that you can later use in your controller. That’s good for things like form submissions so that you later can use that form data to create or modify objects.

If you open the routes file in your Rails app (located in config/routes.rb), you’ll see a huge mass of comments that do a pretty good job of explaining how it works, so you’re never in much danger of losing your way.

Lots of training courses and tutorials kind of gloss over routes, and they seem quite easy in hindsight.  Luckily, typing $ rake routes into the command line will give you an output of all the routes that are available to your application. In this section we’ll go into what’s actually happening with this file.

Points to Ponder

Look through these now and then use them to test yourself after doing the tasks

  • What is the “Root” route?
  • What are the seven RESTful routes for a resource?
  • Which RESTful routes share the same URL but use different verbs?
  • How do you specify an ID or other variable in a route?
  • How can you easily write all seven RESTful routes in Rails?
  • What is the Rails helper method that creates the HTML for links?

Root

The most important (and simplest) route in your file is the root url… where should users be deposited when they land on http://supercutekittenphotos.com? Just tell Rails which controller and action to map that route to, and it is so:

    root :to => "kittens#index"  #kittens controller, index action (method)

Remember, when we say “action” we really mean “the method inside the controller that is called that”, ie. the index action is just the index method that’s defined in the KittensController


 RESTful Routes

If you recall our earlier discussion about REST, there are basically seven main types of actions that you can (and should) do to a “resource”, or an object like a blog post or user – something with its own database model. From that discussion, they are:

  1. GET all the posts (aka “index” the posts)
  2. GET just one specific post (aka “show” that post)
  3. GET the page that lets you create a new post (aka view the “new” post page)
  4. POST the data you just filled out for a new post back to the server so it can create that post (aka “create” the post)
  5. GET the page that lets you edit an existing post (aka view the “edit” post page)
  6. PUT the data you just filled out to edit the post back to the server so it can actually perform the update (aka “update” the post)
  7. DELETE one specific post by sending a delete request to the server (aka “destroy” the post)

The highlighted words correspond to standard Rails controller actions.

Each of these represents a “RESTful” route, and so it makes sense that you’ll need a way to write these in your Router file so the requests they represent are actually routed to the proper action of your controller (in this case, the “Posts” controller). One way to write them out would be the long way:

get "/posts" => "posts#index"
get "/posts/:id" => "posts#show"
get "/posts/new" => "posts#new"
post "/posts" => "posts#create"  # usually a submitted form
get "/posts/:id/edit" => "posts#edit"
put "/posts/:id" => "posts#update" # usually a submitted form
delete "/posts/:id" => "posts#destroy"

Each of these routes is basically a Ruby method that matches that particular URL and HTTP verb with the correct controller action. Two things to notice:

1. The first key thing to notice is that several of those routes submit to the SAME URL. They just use different HTTP verbs, so Rails can send them to a different controller action. That trips up a lot of beginners.

2. The other thing to notice is that the “id” field is prepended by a colon. That just tells Rails “Look for anything here and save it as the ID in the params hash”. It lets you submit a GET request for the first post and the fifth post to the same route, just a different ID:

/posts/1  # going to the #show action of the Posts controller
/posts/5  # also going to the #show action of PostsController

You will be able to access that ID directly from the controller by tapping into the params hash where it got stored.


 The Rails Way to Write Restful Routes

Rails knows you want to use those seven actions all the time so they came up with a handy helper method which lets you do in one line what we just wrote in seven lines in our resources file:

# in config/routes.rb
  ...
  resources :posts
  ...

That is a Ruby method which basically just outputs those seven routes we talked about before.


Rake Routes and Route Helpers

With that above line in my routes file, what do my routes look like? If you type $ rake routes on the command line, it’ll output all the routes your application knows, which look like:

    edit_post  GET  /posts/:id/edit(.:format)  posts#edit

You can see the incoming HTTP verb and URL in the middle columns, then the controller action they map to on the right, which should all be quite familiar because you just wrote it in the routes file. The (.:format) just means that it’s OK but not required to specify a file extension like .doc at the end of the route. It will just get saved in the params hash for later anyway. But what’s on the leftmost column? That’s the “name” of the route.

There are a lot of situations where you want to be able to retrieve the URL for a particular route, like when you want to show navigation links on your webpage (do NOT hard code the URLS, because you’ll be out of luck when you decide to change the URLs and have to manually go in and change them yourself). Rails gives you a helper method that lets you create links called link_to, but you’ll need to supply it with the text that you want to show and the URL to link it to.

    link_to "Edit this post", edit_post_path(3) # don't hardcode 3!

We’re jumping a little bit ahead, but in this case, the second argument is supposed to be a path or a URL, so we use the path helper method to generate that. edit_post_path(3) will generate the path /posts/3/edit.

Rails automatically generates helper methods for you which correspond to the names of all your routes. These methods end with _path and _url. path, as in edit_post_path(3), will generate just the path portion of the URL, which is sufficient for most applications. url will generate the full URL.

Any routes which require you to specify an ID or other parameters will need you to supply those to the helper methods as well (like we did above for edit). You can also put in a query string by adding an additional parameter:

    post_path(3, :referral_link => "/some/path/or/something")

Now the :referral_link parameter would be available in your params hash in your controller in addition to the normal set of parameters.


 Routes go to Controller Actions!

Just to emphasise that routes correspond directly to controller actions, a very simple sample controller which would fulfill the above routes generated by resources :posts might look like:

    # in app/controllers/posts
    class PostsController < ApplicationController

      def index
        # very simple code to grab all posts so they can be
        # displayed in the Index view (index.html.erb)
      end

      def show
        # very simple code to grab the proper Post so it can be
        # displayed in the Show view (show.html.erb)
      end

      def new
        # very simple code to create an empty post and send the user
        # to the New view for it (new.html.erb), which will have a
        # form for creating the post
      end

      def create
        # code to create a new post based on the parameters that
        # were submitted with the form (and are now available in the
        # params hash)
      end

      def edit
        # very simple code to find the post we want and send the
        # user to the Edit view for it(edit.html.erb), which has a
        # form for editing the post
      end

      def update
        # code to figure out which post we're trying to update, then
        # actually update the attributes of that post.  Once that's
        # done, redirect us to somewhere like the Show page for that
        # post
      end

      def destroy
        # very simple code to find the post we're referring to and
        # destroy it.  Once that's done, redirect us to somewhere fun.
      end

    end

 I Don’t Want All Seven Routes!

Sometimes you just don’t want all seven of the RESTful routes that resources provides. Easy, either specify just the ones you want using only or just the ones you DON’T want using except:

    resources :posts, :only => [:index, :show]
    resources :users, :except => [:index]

 Non-RESTful Routes

Of course, you don’t have to do everything the RESTful way. You probably should, but there are times that you want to make up your own route and map it to your own controller action. Just follow the examples we gave at the top for RESTful routes:

    get '/somepath' => 'somecontroller#someaction'

Of course, the config/routes.rb comments should be helpful to you here as well.


 Task

You should have a good sense of what’s going on in the routes file by now but probably also have plenty of questions. The Rails Guides to the rescue!

1. Read Rails Guides Rails Routing from the Outside In (http://guides.rubyonrails.org/routing.html). Look at Sections 1-2.5, 3.1-3.4, and 4.6


 Additional Resources


Step 2: Controllers

Controllers are the middle managers of the whole process. They tell everyone else what to do and take all the credit.

Introduction

The controller’s job is really to act as the ultimate middleman. It knows which questions it wants to ask the Model, but lets the model do all the heavy lifting for actually solving those questions. It knows which view it wants to render and send back to the browser, but lets the view itself take care of putting all that HTML together. That’s why it’s a “controller” – smart enough to know what to do and then delegate all the hard work. All it does is collect the proper batch of instance variables for sending over to the view.

When does the controller get used? After an HTTP request comes into your application and the router decides which controller and action to map it to, Rails packages up all the parameters that were associated with that request and runs the specified method in the specified controller. Once that method is done, Rails will take any instance variables you’ve given it in that controller method and ship them over to the appropriate view file so they can be inserted into your HTML template (“View”) and ultimately sent back to the browser.

Typical controllers are pretty lightweight and don’t have a whole lot of code but are able to do a lot of work with that code. What if you want to show all your blog posts in your site’s index page? Run the #index action of your Posts controller and it will grab all your posts and send them over to the index.html.erb view file, which figures out how you actually want them displayed.

The controller’s #index action would actually look as simple as:

    PostsController < ApplicationController
      ...
      def index
        @posts = Post.all
      end
      ...
    end

In this simple action, we have the controller asking the model for something (“Hey, give me all the posts!”), packaging them up in an instance variable @posts so the view can use them, then will automatically render the view at app/views/posts/index.html.erb.

Points to Ponder

Look through these now and then use them to test yourself after doing the tasks

  • Why is it important what you name your models, controllers, and views?
  • Where is the view file located that’s rendered by default for a given controller?
  • What’s the difference between a #render and a #redirect_to?
  • What happens to the controller’s instance variables in each case?
  • What is a shortcut for redirecting to a specific Post (tip: this works in all kinds of places like #link_to and #*_path)
  • Does a method finish executing or get interrupted when it hits a #render or #redirect_to?
  • What happens if you have multiple renders or redirects?
  • What are Strong Parameters?
  • When can you just use the params hash directly and when do you need to specifically “whitelist” its contents?
  • What are “scalar” values?
  • What does #require do? #permit?
  • What’s the #flash?
  • What’s the difference between #flash and #flash.now?

Naming Matters

One way that Rails makes your life a bit easier is that it assumes things are named a certain way and then executes them behind the scenes based on those names. For instance, your controller and its action have to be named whatever you called them in your routes.rb file when you mapped a specific type of HTTP request to them.

The other end of the process is what the controller does when it’s done. Once rails gets to the end of that controller action, it grabs all the instance variables from the controller and sends them over the view file which is named the same thing as the controller action and which lives in a folder named after the controller, ie. app/views/posts/index.html.erb. This isn’t arbitrary, this is intentional to make your life a lot easier when looking for files later. If you save your files in a different folder or hierarchy, you’ll have to explicitly specify which ones you want rendered.


 Rendering and Redirecting

Although Rails will implicitly render a view file that is named the same thing as your controller action, there are plenty of situations when you might want to override it. A main case for this is when you actually want to completely redirect the user to a new page instead of rendering the result of your controller action.

Redirects typically occur after controller actions where you’ve submitted information like to create a new Post. There’s no reason to have a create.html.erb view file that gets displayed once a post has been created… we usually just want to see the post we created and so we’ll redirect over to the Show page for that post. The distinction here is that your application treats a redirect as a completely new HTTP request so it would enter through the router again, look for the Show page corresponding to that post, and render it normally. That also means that any instance variables you set in your original #create controller action are wiped out along the way.

If that’s the common way to deal with successfully creating an object, how about when it fails for some reason (like the user entered a too-short post title)? In that case, you can just render the view for another controller action, often the same action that created the form you just submitted (so the #new action).

The trick here is that the view page gets passed the instance variables from your current controller action. So let’s say that you tried to #create a Post and stored it to @post but it failed to save. You then rendered the #new action’s view and that view will receive the @post you were just working with in the #create action. This is great because you don’t have to wipe the form completely clean (which is really annoying as a user) — you can just identify the fields that failed and have the user resubmit. It may sound a bit abstract now but you’ll see the difference quickly when building.

Let’s see it in code:

    # app/controllers/posts_controller.rb
    class PostsController < ApplicationController
      ...
      # Make (but don't save) an empty Post so the form we render
      # knows which fields to use and where to submit the form
      # This action will render app/views/posts/new.html.erb once
      # it's done
      def new
        @post = Post.new
      end

      # We know this will get run once we receive the submitted
      # form from our NEW action above (remember your REST actions??)
      # We'll just use pseudo-code for now to illustrate the point
      def create
        ... code here to set up a new @post based on form info ...
        if @post.save
          ... code to set up congratulations message ...
          redirect_to post_path(@post.id) # go to show page for @post
        else
          ... code to set up error message ...
          render :new
        end
      end
    end

So the thing to pay attention to is that, if we successfully are able to save our new post in the database, we redirect to that post’s show page. Note that a shortcut you’ll see plenty of times is, instead of writing redirect_to post_path(@post.id), just write redirect_to @post because Rails knows people did that so often that they gave you the option of writing it shorthand. We’ll use this in the example as we develop it further.

The error condition in the #create action above is going to render the same form that we rendered in the #new action, though this time @post will be the Post object that we tried and failed to save, so it will also have some errors attached to it which can be used to highlight in red which form fields were the culprits.


 Multiple Render/Redirects

It’s important to note that render and redirect_to do NOT immediately stop your controller action like a return statement would. So you have to be really careful that your logic doesn’t result in you running more than one of those statements. If you do, you’ll get hit with an error. They’re usually pretty straightforward to debug.

If you write something like:

    def show
      @user = User.find(params[:id])
      if @user.is_male?
        render "show-boy"
      end
      render "show-girl"
    end

In any case where the user is male, you’ll get hit with a multiple render error because you’ve told Rails to render both “show-boy” and “show-girl”.


 Params and Strong Parameters

In the example above, we saw ... code here to set up a new @post based on form info .... We keep saying that the router packages up all the parameters that were sent with the original HTTP request, but how do we access them?

With the params hash! It acts just like a normal Ruby hash and contains the parameters of the request, stored as :key => value pairs. So how do we get the ID of the post we’re asking for? params[:id]. You can access any parameters this way which have “scalar values”, ie. strings, numbers, booleans, nil… anything that’s “flat”.

Some forms will submit every field as a top level scalar entry in the params hash, ie. params[:post_title] might be “test post” and params[:post_body] might be “body of post” etc and these you can access with no issues. You have control over this, as you’ll learn in the lessons on forms.


 Strong Parameters

Often, though, you want to send parameters from the browser that are all packaged nicely into a hash or nested into an array. It can make your life a lot easier because you can just pass that hash straight into Post.new(your_hash_of_attributes_here) because that’s what Post.new expects anyway! You should be aware that the structure of the data you’re being sent from a form depends entirely on how you choose to set up that form (it’s really based on how you choose to name your fields using the HTML name='' attribute).

In our example, we will assume that our params[:post] is giving us a hash of Post attributes like { :title => "test post", :body => "this post rocks", :author_id => "1"}, which is exactly what Post.new is expecting. Whether you get the parameters packaged up in a hash or all on the top level as individual attributes (like params[:id]), again, is up to you and how you create your form. But know it’s usually easier for you to handle receiving a nicely packaged hash of Post attributes in your controller.

The important distinction between the “scalar” parameter values like strings and more complex parameters like hashes and arrays is that Rails 4 implemented some protections in the controller, called “Strong Parameters”. This is so the user can’t send you harmful data (like automatically setting themselves as an admin user when they create an account). To do this, Rails makes you explicitly verify that you are willing to accept certain items of a hash or array.

Note: This used to be done in Rails 3 by setting attr_accessible in the model to whitelist attributes, so you will probably see that in a lot of Stack Overflow posts and earlier applications.

To “whitelist”, or explicitly allow, parameters, you use the methods require and permit. Basically, you require the name of your array or hash to be in Params (otherwise it’ll throw an error), and then you permit the individual attributes inside that hash to be used. For example:

    def whitelisted_post_params
      params.require(:post).permit(:title,:body,:author_id)
    end

This will whitelist and return the hash of only those params that you specified (e.g. {:title => "your title", :body => "your body", :author_id => "1"} ). If you didn’t do this, when you tried to access params[:post] nothing would show up! Also, if there were any additional fields submitted inside the hash, these will be stripped away and made inaccessible (to protect you).

It can be inconvenient, but it’s Rails protecting you from bad users. You’ll usually package these strong parameter helpers up in their own private method at the bottom of your controllers, then call that method where you need to get those specific params.

So our #create action above can now be filled out a bit more:

    # app/controllers/posts_controller.rb
    class PostsController < ApplicationController
      ...
      # We know this will get run once we've received the submitted
      # form from our new action above (remember your REST actions??)
      def create
        @post = Post.new(whitelisted_post_params) # see method below
        if @post.save
          ... code to set up congratulations message ...
          redirect_to post_path(@post.id) # go to show page for @post
        else
          ... code to set up error message ...
          render :new
        end
      end

      private  # Best to make helper methods like this one private

      # gives us back just the hash containing the params we need to
      # to create or update a post
      def whitelisted_post_params
        params.require(:post).permit(:title,:body,:author_id)
      end
    end

 Flash

The last piece of code we need to write there is how to set our special messages for the user. Rails gives you a neat tool for sending success and error messages (like the little green message that briefly appears at the top of an application to congratulate you for signing up) called the “flash”. It acts just like a hash. You can set its keys to a specific message and then that will be available for you to access if you want to display it in your views.

You can use any keys you want for the flash, but it’s conventional to just stick to three, :success, :error, and :notify. So the success message above might look like flash[:success] = "Great! Your post has been created!".

The reason you can use any key is because you will have to write a snippet of code in your view anyway to display the flash, but sticking to the conventional ones is good practice. The other sneaky trick with the flash is that it automatically erases itself once you’ve used it, so you don’t have to worry about it displaying every time you visit a new page… one time use. Like SnapChat (http://www.snapchat.com/).

One last distinction, though, goes back to the difference between a redirect and a render. Remember, a redirect submits a completely new HTTP request, effectively leaving our application in the dust and starting over from the top. We lose all our data – except for the flash. The flash is specifically designed to travel with that HTTP request so you have access to it when you get redirected to the next page.

Render doesn’t go that far. It just uses a view file that’s part of your application’s normal flow and you have access to all your instance variables in that file. Because the flash is special, you actually have to use flash.now instead of flash when you are just rendering a view instead of submitting a whole new request. That would look like flash.now[:error] = "Rats! Fix your mistakes, please..

The distinction between flash and flash.now just lets Rails know when it will need to make the flash available to you. If you used flash when you should have used flash.now, you’ll just start seeing your messages showing up a “page too late” and it should be obvious what went wrong.

Now the full controller code can be written out for our #create action:

    # app/controllers/posts_controller.rb
    class PostsController < ApplicationController
      ...
      # We know this will get run once we've received the submitted
      # form from our new action above (remember your REST actions??)
      def create
        @post = Post.new(whitelisted_post_params)
        if @post.save
          flash[:success] = "Great! Your post has been created!"
          redirect_to @post # go to show page for @post
        else
          flash.now[:error] = "Rats! Fix your mistakes, please."
          render :new
        end
      end

        private

          def whitelisted_post_params
            params.require(:post).permit(:title,:body,:author_id)
          end 
    end

This code gets the form data, make a new post, try to save the post, set up a success message and redirect you to the post if it works, and handle the case where it doesn’t work by berating you for your foolishness and re-rendering the form. A lot of work for only 10 lines of Ruby.


 Your Tasks

That’s really just a taste of the Rails controller, but you should have a pretty good idea of what’s going on and what tricks you can use.

1. Read Rails Guides Action Controller Overview (http://guides.rubyonrails.org/action_controller_overview.html). Look at Sections 1 – 4.5.3 and 5.2.


 Additional Resources

Published on 28 August 2013
This video will explain how to handle the http response using “render” and will also look at creating partials and rendering them in our kitchenstore application templates.

Step 3: Views

When the controller has figured out which data needs to be displayed, it’s the View’s job to turn that into some half-decent HTML.

Introduction

The view is really the simplest part of the MVC structure. At the basic level, it’s just a bunch of HTML boilerplate into which you insert the variables you’ve received from your controller and which will be sent to the browser. It’s your actual “webpage”. It will often have some snippets of code designed to properly present the variables it has received, for instance a loop that will display each one of the posts on your blog. Views are often called view templates.

Views live in the directory app/views/controller_name/action_name.html.erb, where controller_name is the name of the controller the view is linked to and action_name.html.erb is the corresponding method inside the controller that was run immediately prior to rendering the view.

So the Posts controller running the #index action will implicitly render the app/views/posts/index.html.erb view when it’s done. You can explicitly tell your controller to render a differently named view by passing it as a parameter to the render function in your controller, but why? This directory and naming structure helps you (and Rails) to always know where to find a given view.

To use an instance variable from your controller, just call it the same way you would in the controller: @user.first_name or @posts or @some_other_variable.

As always, in this lesson we’ll cover the high level content then ask you to read the Rails Guide for a more detailed understanding of how things work.

Points to Ponder

Look through these now and then use them to test yourself after doing the tasks

  • What is a layout?
  • What’s the difference between a “view template” and a “layout”?
  • What is a “Preprocessor”?
  • Why are preprocessors useful?
  • How do you make sure a preprocessor runs on your file?
  • What’s the outputted filetype of a preprocessed *.html.erb file? What about a *.css.scss file?
  • What is the difference between the <%= and <% tags?
  • What is a view partial?
  • How do you insert a partial into your view?
  • How can you tell that a view file is a partial?
  • How do you pass a local variable to a partial?
  • What’s the magical Rails shortcut for rendering a User? A bunch of Users?
  • What are asset tags and why are they used?

 Layouts

The first thing to note is that the named view template we render from the controller is actually not the entire webpage. It doesn’t contain the <head> tags or the DOCTYPE declaration or some of the other basic structure that’s present in all pages. Precisely because those things are present in all of your pages, the Rails creators were smart enough to turn that code into its own file called a “layout”. Layouts live in the directory app/views/layouts.

For a brand new Rails application, the application.html.erb layout is pretty basic. It’s got the basic tags you need in all webpages (e.g. <html> and <body>) and a couple snippets of code that load up the javascript and css files your webpage will need. You’ll want to put anything that’s needed across all your webpages into the layout. Usually this is content like navbars and footers and snippets of code for displaying flash messages.

So if a layout is basically just a shell around the individual page, how does the page get inserted? That brings us back to the magic of the #yield method, which you saw when you learned about blocks (http://bedford-computing.co.uk/learning/ruby-on-rails/ruby-programming-odin-project-1/). The view template at app/views/posts/index.html.erb gets inserted where the yield statement is. When you get more advanced, you’ll be able to play around a bit with that statement but for now it’s just that simple.


 Preprocessors

The other thing you’ve undoubtedly noticed is the odd HTML code that goes inside <%= and %> tags. This is Embedded Ruby (ERB). It’s a special way of executing ruby code inside your HTML. HTML is static, so you need to dial in some Ruby if you want to do anything dynamic like looping, if statements or working with variables. ERB (and another similar language you might see called HAML) do exactly that.

What those tags do is execute whatever you see inside them exactly as if it was normal Ruby. So <%= "<em>I am emphasized</em>" %> will output an emphasized piece of text like <em>I am emphasized</em> and <%= @user.first_name %> will output joe.

The difference between <% and <%= is that the <%= version actually displays whatever is returned inside the ERB tags. If you use <%, it will execute the code but, no matter what is returned by that line, it will not actually display anything in your HTML template.

Most of your tags will be <%= because you’ll find yourself often just outputting important pieces of the instance variables that you received from your controller, like in the <%= @user.first_name %> example above. You use the <% for purely code-related stuff like if statements and each loops, where you don’t actually WANT anything displayed (the stuff you display will occur inside the loop).

If this is confusing, here’s an example. Say we want to display the first names of all the users in our application but only if the current user is signed in. This might look something like:

    <% if current_user.signed_in? %>
      <ul>
        <% @users.each do |user| %>
          <li><%= user.first_name %></li>
        <% end %>
      </ul>
    <% else %>
      <strong>You must sign in!</strong>
    <% end %>

Remember to close your statements and loops with <% end %>.

In the code above, if the user is signed in it will actually render to the web something like:

    <ul>
      <li>Bob</li>
      <li>Joe</li>
      <li>Nancy</li>
    </ul>

If the user isn’t signed in, it’ll be the much shorter:

    <strong>You must sign in!</strong>

In the above code, if we had accidentally used <%= in the loop line, e.g. <%= @users.each do |user| %> it would run the code fine, but because each returns the original collection, we’d also see a dump of our @users variable on our page (not very professional). It’ll happen to you several times and you’ll learn quick.


 How Do Preprocessors Work?

The important thing to note about the above code execution is that it is all done on the server BEFORE the final HTML file is shipped over to the browser (part of the Asset Pipeline, covered in the next lesson). That’s because, when you render your template in Rails, it first runs “preprocessors” like ERB. It knows you want to preprocess the file because it has the extension .html.erb.

Rails starts from the outside in with extra extensions. So it first processes the file using ERB, then treats it as regular HTML. That’s fine because ERB by definition outputs good clean HTML, like we saw above.

There are other preprocessors you’ll run into as well. .css.scss files use the SASS preprocessor and become regular CSS files. .js.coffee files, which the Coffeescript preprocessor, become regular Javascript after it is run. In both these cases, the preprocessor’s language makes your life easier by giving you some additional tools you can use (like having loops and working with variables) and compiles back down into a plain vanilla CSS or JavaScript or HTML.

The point is, there are many different preprocessors. They are usually gems that either already come with Rails or can easily be attached to it. Rails then runs them automatically, so all you have to worry about is whether your file has the right extension(s) to tell the preprocessor to run.


 View Partials

Another nice thing you can do in Rails is break apart your views into partials. This helps you on several levels — it makes your code more concise and easier to read, and also lets you reuse certain common patterns. One example is the form for creating or editing users. Both the #new and #edit actions need to render some sort of form for the user, and usually that form is almost exactly the same. So often people will turn that form into a new file called something like _user_form.html.erb and then just call that in both the new.html.erb and edit.html.erb view templates where it’s needed.

Pulling back a bit, partials are just HTML files that aren’t meant to be complete but can be shared by other files. You would call a partial by writing something like:

    # app/views/users/new.html.erb
    <div class="new-user-form">
      <%= render "user_form" %>
    <div>

There are a couple of syntax oddities you need to pay attention to. The view partial file is named with an underscore like _user_form.html.erb but gets called using just the core portion of the name, e.g. user_form in the example above.

If there is no directory specified in partial’s name, Rails will only look in the same folder as whichever view called it, ie. app/views/users. Sometimes it makes sense to share partials across multiple view templates that are in multiple controllers, so you save them in their own folder called app/views/shared and would then render them using the code <%= render "shared/some_partial"%>.


 Passing Local Variables to Partials

There’s a lot you can do with partials and we won’t dive into it all here, but the last thing that you might find yourself doing a lot is passing variables to partials. A partial has access to all the variables that the calling view template does, but do NOT rely on them! What if your partial is used by a different controller that uses a different structure for its instance variables? It’s bad code to expect an instance variable like @user to be there in the partial all the time. That means you’ve got to explicitly pass the partial whichever variables you want it to have access to.

In the example above, you most likely want to pass the @user variable to the partial so your code can render the right kind of form. render is just a regular method and it lets you pass it an options hash. One of those options is the :locals key, which will contain the variables you want to pass. Your code might change to look like:

    <%= render "shared/your_partial", :locals => { :user => @user } %>

To use the variable in your partial file, you drop the @ and call it like a normal variable.


 Implicit Partials

As usual, there are some things you would end up doing so many times that Rails has given you a short cut. One of these is the act of rendering a model object like a User or a Post. If you want a list of all your users, you could write out the HTML and ERB code for displaying a single user’s first name, last name, email etc many times directly in your app/views/users/index.html.erb file or you could keep that code in some sort of each loop.

But it’s usually best to make the User into its own partial called _user.html.erb so you can re-use it in other cases as well. The basic way of calling this might be something just like we saw above, which looks like:

    # app/views/index.html.erb
    <h1>Users</h1>
    <ul>
      <% @users.each do |user| %>
        <%= render "user", :locals => {:user => user} %>
      <% end %>
    </ul>

And in your partial:

    # app/views/_user.html.erb
    <li><%= "#{user.first_name} #{user.last_name}, #{user.email}" %></li>

It may seem strange to have only one line in a partial, but trust me that it usually doesn’t stay that way for long so it’s worth getting the hang of.

So if that’s the basic way, what’s the magical Rails way? Just tell it to render the User object directly, ie.

    # app/views/index.html.erb
    <h1>Users</h1>
    <ul>
      <% @users.each do |user| %>
        <%= render user %>     
      <% end %>
    </ul>

Rails then looks for the _user.html.erb file in the current directory and passes it the user variable automatically.

What if you want to render a whole bunch of users like we just did? Rails also does that for you the same way, saving you the trouble of writing out your own each loop like we did above. Simply write:

    # app/views/index.html.erb
    <h1>Users</h1>
    <ul>
      <%= render @users %>
    </ul>

In that situation, Rails not only finds the _user.html.erb file and passes it the correct user variable to use, it also loops over all the users in your @user collection for you.


 Helper Methods

rendering partials isn’t the only method you can call from within a view. Rails has a bunch of really handy helper methods that are available for you to use in the view. A few of the most common:

#link_to

`link_to’ creates an anchor tag URL. Instead of writing:

    <a href="<%= users_path %>">See All Users</a>

You write:

    <%= link_to "See All Users", users_path %>

It’s the Rails way. And recall that users_path generates a relative URL like /users whereas users_url generates a full URL like http://www.yourapp.com/users. In most cases, it isn’t an important distinction because your browser can handle both but make sure you understand the difference.


 Asset Tags

As you may have seen in the application layout file we talked about above, Rails gives you helper methods that output HTML tags to grab CSS or Javscript files. You can also grab images. These are called Asset Tags. We’ll get into the “Asset Pipeline” a bit later, but basically these tags locate those files for you based on their name and render the proper HTML tag.

    <%= stylesheet_link_tag "your_stylesheet" %>
    <%= javascript_include_tag "your_javascript" %>
    <%= image_tag "happy_cat.jpg" %>

Will render something like:

    <link href="/assets/your_stylesheet.css" media="all" rel="stylesheet">
    <script src="/assets/your_stylesheet.js"></script>
    <img src="/assets/happy_cat.jpg">

Note: in production, your stylesheet and javascripts will all get mashed into one strangely-named file, so don’t be alarmed if it’s named something like /assets/application-485ea683b962efeaa58dd8e32925dadf


 Forms

Rails offers several different helpers that help you create forms, and we’ll go over those in depth later.


 Your Tasks

Now that you’ve got a taste of the high level content, read through the Rails Guides for a more detailed look at things. The chapter below will actually start in the controller, where you need to let it know WHICH view file you want to render. The second half of the chapter gets more into the view side of things.

1. Read the Rails Guides Layouts and Rendering in Rails (http://guides.rubyonrails.org/layouts_and_rendering.html) Sections 1 through 3-4.  You can certainly skim when they start going over all the many different options you can pass to a given function. It’s good to know what they are and where you can find them, but you don’t need to memorize all of them.


 Conclusion

Views in general make up the user-facing side of your app. It can be a bit tricky at first to imagine how you choose which view to render, what to include in that view and how to use partials, but a few iterations of working with Rails will show you the conventions pretty quickly. Views will become second nature to you.


 Additional Resources


Step 4: The Asset Pipeline

This lesson explains how Rails handles all the behind-the-scenes activities to get your CSS, JavaScript and Image files served quickly and efficiently and how you can use that process.


 Introduction

You’ve learned about Models, Views, and Controllers. That’s the nuts and bolts, but we’ve got plenty of material to cover which makes Rails much more useful to you. In this lesson, we’ll talk about the Asset Pipeline and a few other topics that don’t necessarily fit well in other sections but are important.

Points to Ponder

Look through these now and then use them to test yourself after doing the tasks

  • What is the “Asset Pipeline”?
  • What are “Manifest Files”?
  • Why would you namespace your stylesheets?
  • What does it mean to “Escape” HTML?

 The Asset Pipeline

Assets in your application are additional files that get called by the browser after your initial gob of HTML is received. They include things like CSS stylesheets, JavaScript files, images, videos etc. – basically anything that requires an additional request to get it.

Often, it’s easiest to organize your code for development purposes into many different files so you can keep track of them better. But if the browser has to use a dozen different CSS files, each one of those requests is going to slow things down. Too many requests and you’ve harpooned your user’s experience with your application.

A similar organizational issue has to do with storing things like images. It’s easier to keep them separate and separated in your directory but you want them to be really simple to link to so your image tags are robust.

Rails’ solution to these problems is to flatten everything out and mash all your asset files together into one big one for each file type (called “concatenation“). The process used to do this is the Asset Pipeline. For your CSS files, this means that Rails will take all the individual .css files and just stack them on top of each other in one giant asset file. It will then run an “uglifier” or “minifier” program on the file to remove extraneous spaces and make everything nice and small for shipping to the browser.

JavaScript files are the same.  All of them get put together and then uglified before being shipped to the browser as one single file. It’s better to have one slightly larger file than to make several full HTTP requests.


 Manifest Files

Rails needs to know which files to include , so it uses so-called “manifest” files to determine this. Your JavaScript manifest file will be app/assets/javascripts/application.js. It looks commented out, but the lines starting with //= tell Rails which files to go find and include. The comments in the file are pretty useful.  They say:

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

The require_tree helper method just gets everything in the current directory.

Your stylesheet manifest file operates on the same principle. It’s available at app/assets/stylesheets/application.css.scss:

/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
 * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the top of the
 * compiled file, but it's generally better to create a new file per style scope.
 *
 *= require_self
 *= require_tree .
 */

Again, you see the require_tree helper method which brings in all CSS files in the current directory.

Reading the comments, you can also see that a couple other directories are assumed to be a “local directory” and can be easily referenced as well, like the lib/assets and vendor/assets files. Sometimes, if you start using a new gem (like some of the Twitter-Bootstrap gems) you manually need to add the new bootstrap stylesheets and JavaScripts to the manifest files to make sure your application actually includes them in the final output.


 The Output

Speaking of final output, what is it? Well, Rails mashes all the specified files together and creates a new one called something like: application-1fc71ddbb281c144b2ee4af31cf0e308.js. That nonsensical string of characters is meant to differentiate between files if you end up making any changes. If they were just called something like application.js, then your browser would cache it and never know to ask you for the latest version because it’s always named the same thing.

But wait, how does the browser know to go looking for application-1fc71ddbb281c144b2ee4af31cf0e308.js? That’s what the asset tags we talked about in the previous lesson are useful for. When you write in your application layout <%= javascript_include_tag "application" %>, Rails automatically knows which filename to request to get all your JavaScripts properly imported.


 Taking This Into Account in Your Code: Namespacing

This sounds great and wonderful and faster for your application, but does it change anything you do? Oftentimes you can just forget about the manifest files and keep coding along your way. For your initial applications, you might keep all the styles and JavaScripts in one file anyway, so it’s not going to change anything on your end.

It becomes important when, for instance, you have a ton of different pages that likely want to use different stylesheets. What if you want the .container class to do slightly different things in your user login pages versus the checkout pages? With the asset pipeline, Rails will jam all those files together and you can’t be sure which .container styles are going to override which others.

In theory, you could override styles from your stylesheets stored at app/assets/stylesheets with either inline styles or <style> tags, but that gets really messy and totally defeats the purpose of having external stylesheets for keeping code clean.

Let’s also assume that you really like user .container classes to keep your <div> elements neatly organized. The solution is to use “Namespacing“, which means that you basically nest your beneath some sort of variable or function name. This is actually a principle that gets used a LOT, so it’s important to understand it. You’ll see it with stylesheets, JavaScripts, modules of code and more.

The basic idea is to be able to say “all this code/css/whatever inside here only belongs to XYZ”. You sort of fence it off. It’s best explained with an example:

    # app/views/users/show.html.erb
    <div class="user">
      <div class="container">
        
      </div>
    </div>

Now this container and all the code inside of it is also within the .user class. So we can set up our stylesheet to specifically address the .container class that’s inside a .user class:

    # app/assets/stylesheets/user.css.scss
    # Note: I'm not going to use SCSS code because we haven't covered it yet
    .user .container{
      // style stuff
    }

This is good because we’re now specifically targeting containers used by User pages.

The same principle applies to JavaScript, and this will be covered later.

So any time you want to make only a portion of your stylesheets or JavaScript code available to a specific set of views, try namespacing it.


 Rails in Development

The asset pipeline functions a bit differently in development mode. If you look at your Rails server output when you’re working with a webpage in the local environment, it actually sends out many  stylesheets and the like. This is just to give you the ability to debug easier.


 Images

For images, the asset pipeline keeps them in the /assets directory unless you’ve made your own subdirectories. Use image_tag‘s to avoid confusion, e.g. <%= image_tag "fuzzy_slippers.jpg" %>.


 Preprocessors

Remember the preprocessors we talked about in the previous lesson on Views? Filetypes like ERB and SASS and HAML and Coffeescript all get preprocessed as part of the pipeline.


 

Un-Escaping HTML

Let’s say you’re building a blog and you want to be able to write posts that include HTML code. If you just write something like this is the <strong>BODY</strong> of my post and then try to display it in a view later, the <strong>tags will just be regular text… they will literally say ‘<strong>’. That’s called “escaping” the characters.

To get your views to actually render HTML as HTML, you need to let Rails know that the code is safe to run. Otherwise, it’s easy for a malicious attacker to inject code like <script> tags that cause major issues when you try to render them.

To tell Rails a string is safe, just use the method raw in your view template, for example:

<%= raw "<p>hello world!</p>" %>   

If you don’t want to rely on Rails’ native behavior and would like to make absolutely sure the HTML does not get run, use the CGI class’s escapeHTML method, e.g.

    CGI::escapeHTML('usage: foo "bar" <baz>')
    # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"

 Your Tasks

1. Read the Rails Guides The Asset Pipeline (http://guides.rubyonrails.org/asset_pipeline.html ) Sections 1 to 3


 Conclusion

The Asset Pipeline isn’t something that you often think about, especially when just building little toy apps, but it becomes important to understand as soon as you want to deploy your application or work with anything but the vanilla asset structure.

Additional Resources


Project: Basic Routes, Views and Controllers

Project: Basic Routes, Views and Controllers

Warmup: Sending Params with RestClient

In this project, you’ll get a chance to interact with a Rails application from the command line by sending requests manually. You’ll first build a very simple app (to get some practice with the steps involved in creating a new one) and then a simple script which uses the RestClient gem (which you used in the first project) to send some requests and examine the server output.

There are a lot of steps but it’s actually quite straightforward.


Your Task

Application Skeleton

1. First you need to create a simple Rails app:

2. Create a new Rails application “rest-tester” (remember the $ rails new command?). Go (cd) into the application folder and open it up in a text editor.

3. Let’s start from the top – creating the routes necessary to serve up our users. Go to config/routes.rb and add the users resources with resources :users.

4. Quiz: Which routes were just created (there are 7 of them)? More specifically, try to name the 7 actions and what they do. Now try to match these routes to the appropriate HTTP verbs and URLs (remember, some are created by using the same URL but a different HTTP verb).

5. Verify by using $ rake routes


 Test Script

Next create a simple script file which will run RestClient and allow you to start pinging your new app:

1. Create a blank file at app/script/rest_requestor.rb. You’ll probably need to create a new folder. This script folder is just a convenient place to store our scripts, which we’ll be calling explicitly from the command line. There’s nothing special about it.

2. What’s the simplest way to make a request? Just use the #get method of rest-client and #puts that output to the terminal:

# app/script/rest_requestor.rb
require 'rest-client'
url = "http://localhost:3000"
puts RestClient.get(url)

If you want to get creative, use #gets and #chomp to allow you to enter input from the command line.


 Sending Requests

1. Run the script using $ ruby script/rest_requestor.rb. Error! You don’t have anyone waiting for the request.

2. You’ll need to fire up your rails server. Go to a new tab or window (but make sure you’re in your application’s directory still) and run the server using $ rails server

3. Try to run the script again. It should output a whole bunch of HTML which represents the default Rails homepage.

4. Change your script file to go to http://localhost:3000/users instead. Run it again.

5. This time you should receive a different error, something like 404 Resource Not Found. Your application is throwing an error, but why? Go to the tab that is running your server and check the server logs. You should see something saying ActionController::RoutingError (uninitialized constant UsersController): on top of a long stack trace. It’s looking for a controller, that makes sense. We don’t have one.

6. Create a blank controller to serve our users. You can manually create the file at app/controllers/users_controller.rb (just remember to have it inherit from ApplicationController), or you could also create it using one of the Rails generators on the command line (which just plops out a bunch of files). Try $ rails generate controller Users. If you run the generator, it will also give you a bunch of test and javascript/css files, as well as a folder to store the views in at app/views/users. You can avoid generating the test files (it makes no difference for this) by adding --no-test-framework to the end of the generator command.

7. Run your script again. Another error! Back to the server logs and we see: AbstractController::ActionNotFound (The action 'index' could not be found for UsersController):. It sure seems like the request was routed to the controller and, as you’d expect for a GET to the /users URL, it’s looking for the #index action but it couldn’t find the action. That’s because we haven’t created the methods yet in our controller.

8. Create the 4 methods that correspond to GET requests. Each method should set an instance variable to display the method name:

    # app/controllers/users_controller.rb
    ...
    def index
      @name = "I am the Index action!"
    end
    ...

9. Now try running the script again. #$%&! Still an error. This time our server is saying: ActionView::MissingTemplate (Missing template users/index.... That sounds like a view error. You know that the index action would complete and then automatically go looking for the app/views/users/index.html.erb view file to render.

10. Fix this by creating a view file for each of the 4 actions that require it. It should put the action’s name in <h1> tags, ie.:

    # app/views/users/index.html.erb
    <h1><%= @name %></h1>

11. Rerun the script. You should see some HTML. Most of it is generated from your layout file at app/views/layouts/application.html.erb, including lots of turbolinks calls but then, near the bottom, you should see your lonely <h1> tag. Success!

12. Take a look at the layout file at app/views/layouts/application.html.erb file and add some arbitrary HTML tags before and after the <%= yield %> line and rerun your request to see where they pop up in the returned HTML.

13. Change your script file to make each of the remaining 3 GET requests. For the ones that relate to a specific resource (ie. #show), you’ll need to include an ID value in the URL (which we won’t actually be using).


 Non-GET Requests

1. Now create the #create action in your controller, which would be accessed using a POST request. Update your script to make a simple POST #post request sending no data, ie.. RestClient.post(url,""). See the RestClient Docs (https://github.com/rest-client/rest-client) for info on how to structure the non-GET requests.

2. Error! Back to the server: ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):.  Rails doesn’t like it when you try to make POST requests to your application using the command line since POST requests typically represent the submission of form data which may be sensitive. The same is true for DELETE and PATCH requests.

3. We’ll get more into this in the lesson on forms, but basically Rails will send a special token code when it renders a form in the webpage and then it only accepts the response if the form sends back that token with the submission. Since you are operating directly from the command line and never got that original token, Rails won’t accept your request.

4. Hopefully this has been a useful adventure into the request cycle of a Rails app and given you a chance to get a bit familar with basic app creation and setup and routing.


 Project: Ruby on Rails Tutorial

In this chapter of the tutorial you will build out the look and feel of the application using Twitter’s Bootstrap CSS framework.

Bootstrap will do a lot of the heavy lifting for you. Instead of having to figure out how to make your navbar stick to the top of the screen, you just have to put the correct class onto some <div> tags and Bootstrap’s style files will take over for you. It’s a good way to quickly get something half decent up and running. In the course on HTML and CSS, you’ll get the chance to design your own CSS framework, but for now Bootstrap is a good weapon of choice.

If you’re looking for help on Bootstrap, note that the newest version is version 3.0 while the tutorial uses the previous version, 2.3. See Additional Resources for links to the docs. Many classes were renamed for the new Bootstrap so be careful if you’re going around looking for help with Bootstrap. You may be looking at the new version instead.


 Your Task

1. Complete the Ruby on Rails Tutorial Chapter 5 Filling in the Layout (https://www.railstutorial.org/book/filling_in_the_layout)


Additional Resources