Skip to content

Instantly share code, notes, and snippets.

@DeepNeuralAI
Last active April 23, 2019 22:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DeepNeuralAI/485f3444ed3538eafd8f67bd8f80d241 to your computer and use it in GitHub Desktop.
Save DeepNeuralAI/485f3444ed3538eafd8f67bd8f80d241 to your computer and use it in GitHub Desktop.
Rails - Partials & Render

Render & Redirect

MVC

Rails: "Convention over configuration"

To have a good understanding of partials, I first want you to understand the two primary ways you can create an HTTP response from the controller's point of view.

  1. Call render to send back to the browser
  2. Call redirect_to to send an HTTP redirect status code to the browser

Kind of makes sense. But I think an example explains the two ways better.

Rendering

Controllers, by default, automatically render views, if the name corresponds to a valid route.

Source: Creating Responses

restaurant_controller.rb

class RestaurantController < ApplicationController
end

routes.rb

resources :restaurants

app/views/restaurants/index.html.erb

<h1>Restaurant Coming Soon</h1>

Reminder

Rails provides a mapping between HTTP verbs and URLs to controller actions. We can, with a single entry, create seven different routes in our application.

Source: Routing

HTTP Verb Path Controller#Action Used For
GET /restaurants restaurants#index display a list of all restaurants
GET /restaurants/new restaurants#new return an HTML form for creating a new restaurant
POST /restaurants restaurants#create create a new restaurant
GET /restaurants/:id restaurants#show display a specific restaurant
GET /restaurants/:id/edit restaurants#edit return an HTML form for editing a restaurant
PATCH/PUT /restaurants/:id restaurants#update update a specific restaurant
DELETE /restaurants/:id restaurants#destroy delete a specific restaurant

Order Matters

Rails routes are matched in the order they are specified.

If you put resources at the very top, and then decided to change the path underneath, it would not work. Whatever matches first, will be run.

Convention Over Configuration

Without writing anything in our controller, Rails will automatically render the view located at: app/views/restaurants/index.html.erb when we navigate to the path /restaurants/.

Let's say instead we have this in our controller:

class RestaurantsController < ApplicationController
  def index
    @restaurants = Restaurant.all
  end
end

We don't explictly state that we want to render a view. These kind of assumptions are all based on the 'convention over configuration' principle.

In other words, if we do not explicitly state a view to render, Rails will automatically look for action_name.html.erb template in our view folder.

In this case, it will look for app/views/restaurants/index.html.erb

Using Render

The three ways of using render:

  1. Render another template within the same controller
  2. Render a template within another controller
  3. Render a file somewhere in your project directory (least likely)

Render A Template Within Same Controller

def update
  @restaurant = Restaurant.find(params[:id])
  if @restaurant.update(book_params)
    redirect_to(@restaurant)
  else
    render "edit"
  end
end

OR:

def update
  @restaurant = Restaurant.find(params[:id])
  if @restaurant.update(book_params)
    redirect_to(@restaurant)
  else
    render :edit
  end
end

You can use symbols or strings. The key point is that in the above examples, if the update fails, the controller will render the edit.html.erb file belonging to the controller (Restaurants)

Render A Template From Another Controller

Let's say we have another controller called Orders, located at app/controllers/orders.

In this specific example, if we create a new restaurant, we want immediately to render the app/views/orders/new.html.erb page.

We can do this by instead placing:

def create
  @restaurant = Restaurant.new(restaurant_params)
  if @restaurant.save
    render "orders/new"
  else
    render :new
  end
end

Render a File

render file: "/u/apps/random_app/current/app/views/restaurants/show"

Redirect

The final way of returning responses is with redirect_to.

render tells Rails which view to use.

In contrast, redirect_to tells the browser to send a new request for a different url.

Take a moment to think about that.

Example:

redirect_to(restaurants_path) will ask the browser to send a request for:

get /restaurants, which in turn will look to the restaurants#index for what to do next.

You can also use redirect_back to return the user back to where they came from.

Syntax:

redirect_back(fallback_location: root_path)

Quick Note

Source: redirect_to

redirect_to() and redirect_back() do not halt and return immediately from method execution, but simply set HTTP responses. 

Statements occurring after them in a method will be executed. 

You can halt by an explicit return, if needed.

Difference Between Render & Redirect

Think twice about which action you want to take. It seems trivial, but they do different things altogether.

def index
  @restaurants = Restaurant.all
end
 
def show
  @restaurant = Restaurant.find_by(id: params[:id])
  if @restaurant.nil?
    render "index"
  end
end

What is the problem here? What happens if a restaurant is nil?

From first glance, it makes sense.

If no restaurant, render my index page.

But a render() method does not run any code, it does not go back to the index() method and then finds @restaurants.

It throw an error.

Solution: A better fix is to use redirect_to()

def index
  @restaurants = Restaurant.all
end
 
def show
  @restaurant = Restaurant.find_by(id: params[:id])
  if @restaurant.nil?
    redirect_to :index
  end
end

Partials

Now that we have a better understanding of render, we can talk about partial templates, known as "partials"

We will be able to use partials to DRY up your views.

...are another device for breaking the rendering process into more manageable chunks. 

With a partial, you can move the code for rendering a particular piece of a response to its own file.

Instead of having large pages of code, we want to break up code into files, into components.

For example, we could have partials for:

  1. Navbar
  2. Footer
  3. Sidebar
  4. Forms

The syntax is:

<%= render "shared/navbar" %>

This will pull the code from app/views/shared/_navbar.html.erb

Source: Using Partials

Note the leading underscore character: partials are named with a leading underscore to distinguish them from regular views, even though they are referred to without the underscore.

We can really make our code very organized and easy to debug by using partials effectively:

<%= render "shared/ad_banner" %>
 
<h1>Restaurants</h1>
 
<p>Here are a few of our fine restaurants:</p>
...
 
<%= render "shared/footer" %>

We will create a directory called shared which we will place our partial files in.

Passing in Variables

We have a navbar that contains the following:

<nav>
    <ul>
        <li><%= link_to("Home", root_path) %></li>
        <li><%= link_to("Contact", contact_path) %></li>
    </ul>
</nav>

Usually, we would just put it into a partial named _navbar.html.erb.

<%= render "shared/top_nav"%>

If we want to be a little more interesting, and be more user-centric, we could do the following:

<%= "Hey #{user}" if defined?(user) %>
<navbar>
    <ul>
        <li><%= link_to("Home", root_path) %></li>
        <li><%= link_to("Contact", contact_path) %></li>
    </ul>
</navbar>

We want to greet the user IF the user is defined?

How would we do this though?

Passing in local variables.

<%= render "shared/top_nav", user: @user %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment