Ruby On Rails
Installing
Install Dependencies
sudo apt update
sudo apt install -y curl gnupg2 dirmngr git-core zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common libffi-dev
Install Node
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install -y nodejs
Install Yarn
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install -y yarn
Install Ruby
Takes a while so might want to add --verbose
cd
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL
rbenv install 2.7.1
rbenv global 2.7.1
gem install bundler
Install Rails
gem install rails
Creating a Project
This took a while but did finish on version 6.0.3.2 of rails
# Create
rails new HU
# Start the server http://localhost:3000
rails server # rails s
Basics
Creating a Controller
You pass a name and an action to create a controller
rails generate controller home index
We can not change the content of the page which is found at app/views/home/index.html.erb
<h1>Welcome</h1>
Changing the default route
Lets change the default route page to be the new page. Go app/config/routes.rb
Change from
Rails.application.routes.draw do
get 'home#index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
Change to
Rails.application.routes.draw do
root 'home#index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
Adding a new route
Add Route
In app/config/routes.rb add a new route by adding a get with route name and a controller and action
get '/about' => 'home#about'
Add View
You will need a new view under app/views called about.html.erb
<h1>Abouty<h1>
Add Action
You will need a new action under app/controller/home_controller.rb
class HomeController < ApplicationController
...
def about
end
end
Layouts
Adding Bootstrap To Rails
Install Packages
yarn add bootstrap jquery popper.js
Environment.js
Next, to setup Bootstrap the first thing we want to do is to go into the webpack directory’s environment.js file located at config/webpack/environment.js and add the new Provide plugin for webpack. Note that the top and bottom lines are already in the file. We just need to add the code block in the middle:
const { environment } = require("@rails/webpacker");
const webpack = require("webpack");
environment.plugins.append(
"Provide",
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
Popper: ["popper.js", "default"],
})
);
module.exports = environment;
application.js
Next we go into app/javascript/packs/application.js and under the require statements we import Bootst
import "bootstrap";
import "../stylesheets/application" // <- Add this line
document.addEventListener("turbolinks:load", () => {
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="popover"]').popover()
})
application.scss
As a next step, we need to create a directory for our stylesheets. This file actually goes in a directory we create under app/javascript/stylesheets directory.
@import "~bootstrap/scss/bootstrap";
Add stylesheet_pack_tag
Next, in our layout file app/views/layouts/application.html.erb we need to add an additional line for the stylesheet link to include the stylesheet_pack_tag. This is going to export the JavaScipt and CSS in a single JS file (which is a bit different than the standard way) but it’s for the Webpack dev server:
<!DOCTYPE html>
<html>
<head>
<title>Bootstrapper</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
...
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track':
...
'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
Adding Bootstrap Components
We can do this by going to the bootstrap page and grab the example https://getbootstrap.com/docs/4.3/components/navbar/. The code at the time was
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
Rendering Partial Views
Putting all of this code in one file is hard to maintain. We can use the render keyword in the layout to reference a form. Slightly odd but the naming convention is _<name>.html.erb for the file and <name> for the render name. So app/views/home/_navbar.html.erb is coded as below.
<%= render 'home/navbar' %>
<%= yield %>
<%= render 'home/new_question_form' %>
Hooking up Bootstrap
We can add bootstrap to our project by going to app/views/layouts/application.html.erb and adding the min to it. Add the link from https://getbootstrap.com/docs/4.0/getting-started/download/ and add the container div around the body
<!DOCTYPE html>
<html>
<head>
<title>HU</title>
...
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
...
</head>
<body>
<div class="container">
<%= yield %>
</div>
</body>
</html>
We can do this by going to the bootstrap page and grab the example https://getbootstrap.com/docs/4.0/components/navbar/. The code at the time was
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
Adding content to the page
Next to go the index page and add a media objects from https://getbootstrap.com/docs/4.0/layout/media-object/. The code at the time was
<ul class="list-unstyled">
<li class="media">
<img class="mr-3" src="..." alt="Generic placeholder image">
<div class="media-body">
<h5 class="mt-0 mb-1">List-based media object</h5>
Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
</div>
</li>
<li class="media my-4">
<img class="mr-3" src="..." alt="Generic placeholder image">
<div class="media-body">
<h5 class="mt-0 mb-1">List-based media object</h5>
Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
</div>
</li>
<li class="media">
<img class="mr-3" src="..." alt="Generic placeholder image">
<div class="media-body">
<h5 class="mt-0 mb-1">List-based media object</h5>
Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
</div>
</li>
</ul>
Add a Modal
Next, in the layout code below the yield, get the code from https://getbootstrap.com/docs/4.0/components/modal/. The code at the time was
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Hook up Modal to Button
Let's add an id to the modal code so it can be attached to a button.
...
<div class="modal" tabindex="-1" role="dialog" id="new-question-modal">
...
By default the NavBar comes with a search button. This can be renamed to the "Ask A Question" button and hooked up to the modal dialog using the data=target attribute
Before
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
After
<form class="form-inline my-2 my-lg-0">
<button class="btn btn-outline-success my-2 my-sm-0" data-target="#new-question-modal" type="submit">Ask A Question</button>
</form>
Rendering Partial Views
Putting all of this code in one file is hard to maintain. We can use the render keyword in the layout to reference a form. Slightly odd but the naming convention is _<name>.html.erb for the file and <name> for the render name. So app/views/home/_navbar.html.erb is coded as below.
<%= render 'home/navbar' %>
<%= yield %>
<%= render 'home/new_question_form' %>
Adding a Modal Body
Off to bootstrap to get a