Rails Views

Why views?

The Controller is responsible for orchestrating the whole process of handling a request in Rails. But then, when it's time to send a response back to the user, the Controller hands things off to the View.

Create response

  • render
  • redirect_to
  • head

Views rendering

By default, controllers in Rails automatically render views with names that correspond to valid routes.

E.g. implicit way

Views rendering

def index
  @products = Product.all
end
# => render app/views/products/index.html.erb

Manual way

def update
  @product = Product.find(params[:id])
  if @product.update(product_params)
    redirect_to(@product)
  else
    render 'edit'
  end
end

Different way to render

render nothing: true #rendering nothing
render 'products/show' #rendering from another controller
render template: 'products/show' #actually the same
render '/awesome_app/app/views/products/show' #rendering from another file
render file: '/awesome_app/app/views/products/show' #actually the same
render inline: "<% products.each do |p| %><p><%= p.name %></p><% end %>" #rendering ERB directly
render html: '<span>Success</span>'.html_safe #rendering HTML directly
render plain: 'OK' #rendering text
render json: @product #rendering JSON
render xml: @product #rendering XML
render js: "alert('Hello Rails');" #rendering JS

ERB

Embedded RuBy

Within an ERB template, Ruby code can be included using both <% %> and <%= %> tags. The <% %> tags are used to execute Ruby code that does not return anything, such as conditions, loops or blocks, and the <%= %> tags are used when you want output.

Templates, Partials and Layouts

The final HTML output is a composition of three Rails elements: Templates, Partials and Layouts.

Layouts

Layouts can be used to render a common view template around the results of Rails controller actions. Typically, a Rails application will have a couple of layouts that pages will be rendered within. For example, a site might have one layout for a logged in user and another for the marketing or sales side of the site.

Layouts

<!DOCTYPE html>
<html>
  <head>
    <title>MyTitle</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

Layouts

#products/show.html.erb
<%= render partial: 'product', layout: 'box', locals: {product: @product} %>

#product/_box.html.erb
<div class="box">
  <%= yield %>
</div>

Template

<%= form_for(@product) do |f| %>
  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :price %><br>
    <%= f.number_field :price %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Partials

Partial templates - usually just called "partials" - are another device for breaking the rendering process into more manageable chunks. With partials, you can extract pieces of code from your templates to separate files and also reuse them throughout your templates.

Partials

<%= render "shared/menu" %>

That code will pull in the partial from app/views/shared/_menu.html.erb.

Partials

Sharing variables between partials:

<%= render partial: "product", locals: {product: @product} %> <%= render partial: "product", as: "item" %>

Helpers

Helpers

Add code to helpers

module AvatarHelper
  def avatar(account)
    string_for_digest = account.title + account.age + account.gender
    digest = Digest::MD5.hexdigest(string_for_digest)

    gravatar_url = "//www.gravatar.com/avatar/#{digest}"

    image_tag(gravatar_url)
  end
end

Use helpers in view

# in accounts/show.html.erb
<p> <%= avatar(@account) %></p>

Result

helper_result.jpg

FormHelper

Form helpers are designed to make working with models much easier compared to using just standard HTML elements by providing a set of methods for creating forms based on your models. This helper generates the HTML for forms, providing a method for each sort of input (e.g., text, password, select, and so on).

Form helpers

Example

<%= form_for @product, url: {action: "create"} do |f| %>
  <%= f.text_field :title %>
  <%= f.text_field :description %>
  <%= f.number_field :description %>
  <%= submit_tag 'Create' %>
<% end %>

Render to

<form action="/products/create" method="post">
  <input id="product_title" name="product[title]" type="text">
  <input id="product_description" name="product[description]" type="text">
  <input id="product_price" name="product[price]" type="number">
  <input name="commit" type="submit" value="Create">
</form>

FormTagHelper

Provides a number of methods for creating form tags that don't rely on an Active Record object assigned to the template like FormHelper does. Instead, you provide the names and values manually.

FormTagHelper

<%= form_tag '/productss' do %>
  <div><%= submit_tag 'Save' %></div>
<% end %>
# => <form action="/productss" method="post"><div><input type="submit" name="submit" value="Save"></div></form>

check_box_tag 'accept'
# => <input id="accept" name="accept" type="checkbox" value="1">

<%= form_tag({action:"post"}, multipart: true) do %>
  <label for="file">File to Upload</label> <%= file_field_tag "file" %>
  <%= submit_tag %>
<% end %>

hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@'
# => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@">

label_tag 'name'
# => <label for="name">Name</label>

Assets

Assets Pipeline

The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages and pre-processors such as CoffeeScript, Sass and ERB.

Place for assets

Pipeline assets can be placed inside an application in one of three locations:

  • app/assets
  • lib/assets
  • vendor/assets.

Place for assets

  • app/assets is for assets that are owned by the application, such as custom images, JavaScript files or stylesheets;
  • lib/assets is for your own libraries' code that doesn't really fit into the scope of the application or those libraries which are shared across applications;
  • vendor/assets is for assets that are owned by outside entities, such as code for JavaScript plugins and CSS frameworks.

Haml

Haml

# ...
gem 'haml'

Haml

add .haml extension instead of .erb

Haml example

%section.container
  %h1= post.title
  %h2= post.subtitle
  .content
    = post.content

Bootstrap integration

Bootstrap installation

Webpacker

# Gemfile
# ...
gem 'webpacker'

Generates packs

bundle exec rake webpacker:install:{react, vue, angular, elm ...}

Or create new app with

bundle exec rails new --webpack={react, vue, angular, elm ...}

Javascript in your app dir

app
├── assets
├── channels
├── controllers
├── helpers
├── javascript
├── jobs
├── mailers
├── models
└── views

Packs

app/javascript
├── app.vue
└── packs
    └── application.js

Include your pack in layout

<!DOCTYPE html>
<html>
  <head>
    <title>Vueapp</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= stylesheet_pack_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag    'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

SSR and CSR

Server side rendering

Everything that have been discussed

Client side renderind

Client fetch data from api and parse it.

You can use

  • fetch
  • axios

QA