Rails new app
rails new appName
# skip bundle from the gemfile
rails new address-book --skip-bundle --skip-turbolinks --database=postgresql
rails new miami-tech-hub --skip-bundle --skip-turbolinks --database=postgresql
--skip-test-unit
# cd to the folder then modify gem and then
bundle install
# create database
rake db:create
# migrate to create tables
rake db:migrate
# run server
rails s
rails server -p 4000
# Create
MVC
# This create a model and controller
rails g resource User name:string email:string
rails g resource Task name:string date_completion:date
# First, route, then controller, and finally view.
# put this on the route
get '/' => 'site#home'
# controllers help
rails generate controller --help
# generate a controller for site
rails g controller site
# generate api controller
rails generate controller api/Matches
# destroy controller
rails destroy controller site
# destroy model or controller
rails d model task
# create an action to render the view on the site_controller.rb
def home
render 'home'
end
# create a view inside views folder call home.html.erb
<h1> Welcome to our Homepage </h1>
# this command line create the controller and the action at the same time
rails g controller project home
#----------#
Model
# It is the intermediate between a controller and persistent data
# Models name should be singular but the table ruby created plural
# Model generate project - table created tables
# Create our project model -create two files
rails g model Project
# 1 rails model file where we can put validate and reltionships
app/models/project.rb
class Project < ActiveRecord::Base
end
# 2 is the migration file contains configurations to apply to our database
db/migrate/20140719003104_create_projects.rb
class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.timestamps
end
end
end
# We want to add name and description to our table before we run the migration
class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
# run rake db:migrate to create Projects table - (rake -T db more db commands)
rake db:migrate
# add colums - check schema
rails g migration add_attributes_to_items
rails g migration add_attributes_to_players email:string password_digest:string
# migrate again
rake db:migrate
# This is a shorthand to create project model with name and description
rails g model Project name:string address:string
# --------
CRUD
# create, read, update, delete
# the four basis functions of persistent storage,
# and let us interact with our database to create dynamic webpages
# Rails Console
rails c
# Create
p = Project.new name="IronHack"
p.save
p = Project.create name "IronHack"
# Read
# One Element
p = Project.find(1)
p = Project.first
p = Project.last
p = Project.find_by name:"IronHack"
# Multiple Elements
p = Project.where "name='IronHack'"
# (string)
p = Project.where name:"IronHack"
# (hash)
p = Project.where["name=?", 'IronHack']
# (string with placeholders)
p = Project.where(name:'IronHack').where("created_at<?", Date.yesterday)
# (concatenation)
p = Project.where.not("id<?", 4)
# (negation)
# Limit the number of retrieved elements
Project.limit(3).where("name like 'Iron%'")
# Offset
Project.limit(3).offset(2).where("name like 'Iron%'")
# Order
Project.limit(10).order("created_at DESC")
# Update
p.name = "IronHack Updated"
p.save
p.update_attribute :name, "IronHack rules"
p.updated_attributes name: "IronHack rules" description: "The most awesome bootcamp"
# Delete
p.destroy
# ---------
Seed the Database
# Rails have a special way to fill our database to have testing data for development
# add this to the db/seeds.rb file
Project.create name: 'Ironhack', description: 'Ironhack is awesome'
Project.create name: 'SportsApp', description: 'Tracks my sport sessions'
Project.create name: 'Recipes', description: 'List of my favourite recipes'
Project.create name: 'Teacher Assistant rules!', description: 'App to buy icecreams for my TA'
Project.create name: 'Meetup', description:'App to check latest developers meetups and hackathons'
# run
rake db:seed
# To check
rails c
Project.count
# This are the option to start from zero? (delete seed database)
$ rake db:drop db:create db:migrate db:seed
$ rake db:drop db:setup
:setup implies :create, :migrate, and :seed
$ rake db:reset
:reset implies :drop and :setup
# ----------
A request using the DB
# Now we know create models, interact with our database[CRUD], and
# fill it with testing values(seeds).
# Let's do our first request using the database
# open routes.rb
AppExample::Aplication.routes.draw do
get '/' => 'site#home'
get '/projects' => 'projects#index'
end
# As we type 'projects#index',
# we need a project controller
# with an index action.
# run
rails g controller projects
# app/controllers/projects_controller.rb (check the last 10 projects)
class ProjectsController < ApplicationController
def index
@projects = Project.order(created_at: :desc).limit(10)
end
end
# create and html called index.html.erb
<ul>
<% @projects.each do |project| %>
<h3><%= project.name %></h3>
<li><%= project.description %></li>
<% end %>
</ul>
# erb, Embedded RuBy, a templating system that embeds Ruby
# <% RubyCode %> Executed but not displayed
# <%= RubyCode %> Executed and displayed
# ERB also let us use variables in our html, as @project for example,
# but to use them, they must be instance variables in our controller
def index
@projects = # ...
end
# --------
A request with parameters
# How to load a single project? How do we identify it in an URL?
# We use parameters!
/projects/384 [id attribute]
/projects/ironhack-introduction [name attribute]
twitter.com/theironhack [login attribute]
# so
/projects => Get all the projects [#INDEX Action]
/projects/484 => Get projects with id=484 [#SHOW Action]
# MVC First, route, then controller, and finally view.
# Route
AppExample::Aplication.routes.draw do
get '/' => 'site#home'
get '/projects' => 'projects#index'
get '/projects/:id' => 'projects#show'
end
# Controller
# The params object is where every request with dynamic parameters stores them.
# It's a HASH, where the key is the name of the parameter and the value is the value of the parameter.
#/projects/484 => params[:id] = 482
#/projects/27 => params[:id] = 27
class ProjectsController < ApplicationController
def index
@projects = Project.order(created_at: :desc).limit(10)
end
def show
@project = Project.find params[:id]
end
end
# View
# Create views/projects/show.html.erb (remember the naming rules)
<h1><%= @project.name %></h1>
<p><%= @project.description %></p>
# -------
Exceptions #(404)
# Exceptions are errors if the project doesn't exist
# Rescuing exceptions - (There are two ways to do it)
# Using rescue
def show
@project = Project.find params[:id]
rescue ActiveRecord::RecordNotFound
render 'no_projects_found'
end
#or
# Avoiding the exception
def show
if @project = Project.find_by (id: params[:id])
render 'home'
else
render 'no_projects_found'
end
# ---------
Views and layouts
# This file will include the html structure with a
# <%=yield%> that insert our views
layouts/application.html.erb
# It can be ovewritten at control level and at action level
# Controller level
class ProjectController < ApplicationController
layout 'admin'
def index
@projects = Project.order('created_at DESC').limit(10)
end
def show
@project = Project.find params[:id]
end
end
# Action level
class ProjectController < ApplicationController
def index
@projects = Project.order('created_at DESC').limit(10)
render 'index', layout 'admin'
end
def show
@project = Project.find params[:id]
end
end
# Changing template and layout
class ProjectController < ApplicationController
def index
@projects = Project.order('created_at DESC').limit(10)
render 'projects', layout 'admin'
end
def show
@project = Project.find params[:id]
end
end
# ---------
# ActiveRecord Associations
# Why do we need associations between models?
# Because they make common operations simpler and easier in your code.
# consider a simple Rails application that includes a model for
# customers and a model for orders. Each customer can have many orders
# With Active Record associations we can tell Rails that there is a connection between the two models
class Customer < ActiveRecord::Base
has_many :orders, dependent: :destroy
end
class Order < ActiveRecord::Base
belongs_to :customer
end
# creating a new order for a particular customer is easier
@order = @customer.orders.create(order_date: Time.now)
# Deleting a customer and all of its orders is much easier:
@customer.destroy
# Types of asscociations
# In Rails, an association is a connection between two Active Record models.
# Rails supports six types of associations:
belongs_to
has_one
has_many
has_many :through
has_one :through
has_and_belongs_to_many
belongs_to association
# sets up a one-to-one connection with another model
# such that each instance of the declaring model "belongs to" one instance of the other model.
# If your application includes customers and orders,
# and each order can be assigned to exactly one customer
class Order < ActiveRecord::Base
belongs_to :customer
end
# The corresponding migration might look like this:
class CreateOrders < ActiveRecord::Migration
def change
create_table :customers do |t|
t.string :name
t.timestamps
end
create_table :orders do |t|
t.belongs_to :customer
t.datetime :order_date
t.timestamps
end
end
end
has_one association
# also sets up a one-to-one connection with another model
# but with somewhat different semantics (and consequences).
# This association indicates that each instance of a model contains one instance of another model.
# If each supplier in your application has only one account, you'd declare the supplier model like this:
class Supplier < ActiveRecord::Base
has_one :account
end
# The corresponding migration might look like this:
class CreateSuppliers < ActiveRecord::Migration
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier
t.string :account_number
t.timestamps
end
end
end
has_many association
# indicates a one-to-many connection with another model.
# You'll often find this association on the "other side" of a belongs_to association.
# This association indicates that each instance of the model has zero or more instances of another model.
# In an application containing customers and orders, the customer model could be declared like this:
class Customer < ActiveRecord::Base
has_many :orders
end
# The corresponding migration might look like this:
class CreateCustomers < ActiveRecord::Migration
def change
create_table :customers do |t|
t.string :name
t.timestamps
end
create_table :orders do |t|
t.belongs_to :customer
t.datetime :order_date
t.timestamps
end
end
end
has_many :through association
# Is often used to set up a many-to-many connection with another model.
# This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model.
# For example, consider a medical practice where patients make appointments to see physicians.
# The relevant association declarations could look like this:
class Physician < ActiveRecord::Base
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, through: :appointments
end
# The corresponding migration might look like this:
class CreateAppointments < ActiveRecord::Migration
def change
create_table :physicians do |t|
t.string :name
t.timestamps
end
create_table :patients do |t|
t.string :name
t.timestamps
end
create_table :appointments do |t|
t.belongs_to :physician
t.belongs_to :patient
t.datetime :appointment_date
t.timestamps
end
end
end
# another example with collection of all paragraphs in the document
class Document < ActiveRecord::Base
has_many :sections
has_many :paragraphs, through: :sections
end
class Section < ActiveRecord::Base
belongs_to :document
has_many :paragraphs
end
class Paragraph < ActiveRecord::Base
belongs_to :section
end
# With through: :sections specified, Rails will now understand: @document.paragraphs
has_one :through association
# sets up a one-to-one connection with another model.
# This association indicates that the declaring model can be matched with one instance of another model by proceeding through a third model.
# If each supplier has one account, and each account is associated with one account history
class Supplier < ActiveRecord::Base
has_one :account
has_one :account_history, through: :account
end
class Account < ActiveRecord::Base
belongs_to :supplier
has_one :account_history
end
class AccountHistory < ActiveRecord::Base
belongs_to :account
end
# The corresponding migration might look like this:
class CreateAccountHistories < ActiveRecord::Migration
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier
t.string :account_number
t.timestamps
end
create_table :account_histories do |t|
t.belongs_to :account
t.integer :credit_rating
t.timestamps
end
end
end
# Now we're going to implement a new feature to our projects list app that tells us
# how much time we spent developing each of them. It will be our TimeTracking tool.
# To do this we need to implement a new model, the entries model.
Entry model:
project_id
hours
minutes
comment
date
# It will be linked to our Projects model with N-1 relationship.
# A project could have many entries, but an entry only have a project.
# First generate an entry model
rails g model Entry
# Generate Entry model
rails g model Entry project:references hours:integer minutes:integer comment:text
# On its migration, add the list of above fields:
# Migration is the field created on the db 28873482749734939
class CreateEntries < ActiveRecord::Migration
def change
create_table :entries do |t|
t.integer :project_id
t.integer :hours
t.integer :minutes
t.text :comments
t.datetime :date
t.timestamps
end
end
end
# run
rake db:migrate
# relationship between Projects and Entries will be N-1 relationship
# so our models should look like this:
class Project < ActiveRecord::Base
has_many :entries
end
class Entry < ActiveRecord::Base
belongs_to :project
end
# To check if our code works
rails c
# project = Project.first - project.entries - project.entries.empty?
project = Project.first
Project Load (62.5ms) SELECT "projects".* FROM "projects" ORDER BY "projects"."id" ASC LIMIT 1
=> #<Project id: 1, name: "Ironhack", description: "Ironhack is awesome", created_at: "2014-07-19 03:05:33",
updated_at: "2014-07-19 03:05:33">
project.entries
Entry Load (21.6ms) SELECT "entries".* FROM "entries" WHERE "entries"."project_id" = $1 [["project_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy []>
project.entries.empty?
=> true
#-
Create our first entry on rails console
# entry = Entry.new
# entry.hours = 0
# entry.minutes = 45
# entry.project = project
# entry.save
# project.entries.count
entry = Entry.new
=> #<Entry id: nil, project_id: nil, hours: nil, minutes: nil, comments: nil, date: nil, created_at: nil, updated_at: nil>
entry.hours = 0
=> 0
entry.minutes = 45
=> 45
entry.project = project
=> #<Project id: 1, name: "Ironhack", description: "Ironhack is awesome", created_at: "2014-07-19 03:05:33", updated_at: "2014-07-19 03:05:33">
entry.save
(1.1ms) BEGIN
SQL (55.0ms) INSERT INTO "entries" ("created_at", "hours", "minutes", "project_id", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", Mon, 21 Jul 2014 00:56:56 UTC +00:00], ["hours", 0], ["minutes", 45], ["project_id", 1], ["updated_at", Mon, 21 Jul 2014 00:56:56 UTC +00:00]]
(0.6ms) COMMIT
=> true
#And now, check again:
project.entries.count
(2.2ms) SELECT COUNT(*) FROM "entries" WHERE "entries"."project_id" = $1 [["project_id", 1]]
=> 1
# Our project-entries association works and now you can select entries from project and vice versa.
# -------
Displaying ActiveRecord Associations
# Imagine you want to display the entries of a project
# How do you identify it in an URL? Using params!
# the use of params let us routing a single project from its [:id]
projects/1
# Now its the same, just adding entries after
projects/1/entries
# Now follow the MVC pattern, it is: Routing-Controller-View
Route
# Open config/routes.rb and add it
AppExample::Aplication.routes.draw do
get '/' => 'site#home'
get '/projects' => 'projects#index'
get '/projects/:id' => 'projects#show'
get '/projects/:id/entries' => 'entries#index'
end
Controller
# Why a new controller?
# It’s a good practice to leave controllers the CRUD responsibility of only one resource
# Although the path of request is in the projects resource,
# it’s representing a nested relation Controller
# create a new controller running
rails g controller entries
# Open app/controllers/entries_controller.rb and first write the code to identify our project
class EntriesController < ApplicationController
def index
@project = Project.find params[:id]
@entries = @project.entries
end
end
View
# create a new file app/views/entries/index.html.erb and display project with entries
<h1><%= @project.name %></h1>
<ul>
<% @entries.each do |entry| %>
<li>
<%= entry.hours %> h
<%= entry.minutes %> m
</li>
<% end %>
</ul>
# Ironhack
# 0 h 45 m
# 2 h 33 m
---------
Devise
git clone git@github.com:khalifenizar/bbq.git
cd directory
bundle install
rails generate devise:install
# to change devise views
rails g devise:views
rake db:create
rails g devise User
rake db:migrate
rake db:seed
rake db:migrate
# add name attribute
rails g migration add_attributes_to_users name:string