Slide 1

Slide 1 text

Let’s build a webapp With Ruby on Rails

Slide 2

Slide 2 text

I know Rails

Slide 3

Slide 3 text

Creating a new app $ rails new room-reservations

Slide 4

Slide 4 text

What does it do? create create README.rdoc create Rakefile create config.ru create .gitignore create Gemfile create app create app/assets/javascripts/application.js create app/assets/stylesheets/application.css create app/controllers/application_controller.rb create app/helpers/application_helper.rb create app/views/layouts/application.html.erb create app/assets/images/.keep create app/mailers/.keep create app/models/.keep create app/controllers/concerns/.keep create app/models/concerns/.keep create bin create bin/bundle create bin/rails create bin/rake create config create config/routes.rb create config/application.rb create config/environment.rb create config/environments create config/environments/… create config/initializers create config/initializers/… create config/locales create config/locales/en.yml create config/boot.rb create config/database.yml create db create db/seeds.rb create lib create lib/tasks create lib/tasks/.keep create lib/assets create lib/assets/.keep create log create log/.keep create public create public/404.html create public/422.html create public/500.html create public/favicon.ico create public/robots.txt create test/fixtures create test/fixtures/.keep create test/controllers create test/controllers/.keep create test/mailers create test/mailers/.keep create test/models create test/models/.keep create test/helpers create test/helpers/.keep create test/integration create test/integration/.keep create test/test_helper.rb create tmp/cache create tmp/cache/assets create vendor/assets/javascripts create vendor/assets/javascripts/.keep create vendor/assets/stylesheets create vendor/assets/stylesheets/.keep run bundle install Creates A LOT OF files

Slide 5

Slide 5 text

But what do they do?!

Slide 6

Slide 6 text

Web applications client-server architecture thin client HTTP protocol stateless

Slide 7

Slide 7 text

HTTP Request Response

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

HTTP Request Method URL Request headers

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

HTTP Methods GET (show) POST (create) PUT (replace) DELETE (delete) …

Slide 12

Slide 12 text

HTTP Response Status Body Response headers

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

HTTP Status Codes 200 OK 404 Page Not Found 403 Forbidden 422 Unprocessable Entity 500 Internal Server Error

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

REST Architectural style Resources identifiable in request Representation sufficient to allow resource modification State transitions connect resources

Slide 23

Slide 23 text

Identifiable Resources Guess which resource
 the following lists! ! https://gzgv.basecamphq.com/clients

Slide 24

Slide 24 text

Representations HTML JSON

Slide 25

Slide 25 text

Ruby A dynamic programming language designed to make programmers happy

Slide 26

Slide 26 text

REPL Read-Eval-Print-Loop AKA The Console

Slide 27

Slide 27 text

$ irb

Slide 28

Slide 28 text

puts "Hello, world!"

Slide 29

Slide 29 text

13.times { puts "Hi there!" }

Slide 30

Slide 30 text

["Jane", "John"].each do |name|
 puts "Hi there #{name}!" end

Slide 31

Slide 31 text

array = ["Jane", "John"] array[0] # => "Jane"

Slide 32

Slide 32 text

hash = { id: 1, name: "John" } hash[:id] # => 1 hash[:name] # => "John"

Slide 33

Slide 33 text

Ruby on Rails A web framework based on Ruby extracted from Basecamp

Slide 34

Slide 34 text

Ruby on Rails Allows quick prototyping Joyful programming language Friendly community Documentation

Slide 35

Slide 35 text

Ruby on Rails RESTful (somewhat) MVC Convention over configuration

Slide 36

Slide 36 text

"Any sufficiently advanced technology is indistinguishable from magic." ! — Arthur C. Clarke

Slide 37

Slide 37 text

Rails is a magical

Slide 38

Slide 38 text

Model View Controller

Slide 39

Slide 39 text

Model What is this application about? Resources

Slide 40

Slide 40 text

View How do your users see your app? Representations

Slide 41

Slide 41 text

Controller How does your application work? State transitions

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

What does it do? create create README.rdoc create Rakefile create config.ru create .gitignore create Gemfile create app create app/assets/javascripts/application.js create app/assets/stylesheets/application.css create app/controllers/application_controller.rb create app/helpers/application_helper.rb create app/views/layouts/application.html.erb create app/assets/images/.keep create app/mailers/.keep create app/models/.keep create app/controllers/concerns/.keep create app/models/concerns/.keep create bin create bin/bundle create bin/rails create bin/rake create config create config/routes.rb create config/application.rb create config/environment.rb create config/environments create config/environments/… create config/initializers create config/initializers/… create config/locales create config/locales/en.yml create config/boot.rb create config/database.yml create db create db/seeds.rb create lib create lib/tasks create lib/tasks/.keep create lib/assets create lib/assets/.keep create log create log/.keep create public create public/404.html create public/422.html create public/500.html create public/favicon.ico create public/robots.txt create test/fixtures create test/fixtures/.keep create test/controllers create test/controllers/.keep create test/mailers create test/mailers/.keep create test/models create test/models/.keep create test/helpers create test/helpers/.keep create test/integration create test/integration/.keep create test/test_helper.rb create tmp/cache create tmp/cache/assets create vendor/assets/javascripts create vendor/assets/javascripts/.keep create vendor/assets/stylesheets create vendor/assets/stylesheets/.keep run bundle install

Slide 44

Slide 44 text

What does it do? create create README.rdoc create Rakefile create config.ru create .gitignore create Gemfile create app create app/assets/javascripts/application.js create app/assets/stylesheets/application.css create app/controllers/application_controller.rb create app/helpers/application_helper.rb create app/views/layouts/application.html.erb create app/assets/images/.keep create app/mailers/.keep create app/models/.keep create app/controllers/concerns/.keep create app/models/concerns/.keep create bin create bin/bundle create bin/rails create bin/rake create config create config/routes.rb create config/application.rb create config/environment.rb create config/environments create config/environments/… create config/initializers create config/initializers/… create config/locales create config/locales/en.yml create config/boot.rb create config/database.yml create db create db/seeds.rb create lib create lib/tasks create lib/tasks/.keep create lib/assets create lib/assets/.keep create log create log/.keep create public create public/404.html create public/422.html create public/500.html create public/favicon.ico create public/robots.txt create test/fixtures create test/fixtures/.keep create test/controllers create test/controllers/.keep create test/mailers create test/mailers/.keep create test/models create test/models/.keep create test/helpers create test/helpers/.keep create test/integration create test/integration/.keep create test/test_helper.rb create tmp/cache create tmp/cache/assets create vendor/assets/javascripts create vendor/assets/javascripts/.keep create vendor/assets/stylesheets create vendor/assets/stylesheets/.keep

Slide 45

Slide 45 text

$ cd room-reservations $ rails server

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

$ rails generate scaffold \ room name:string description:text

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

$ rake db:migrate

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Let's look at the new files app/assets/javascripts/rooms.js.coffee app/assets/stylesheets/rooms.css.scss app/controllers/rooms_controller.rb app/helpers/rooms_helper.rb app/models/room.rb app/views/rooms/_form.html.erb app/views/rooms/edit.html.erb app/views/rooms/index.html.erb app/views/rooms/index.json.jbuilder app/views/rooms/new.html.erb app/views/rooms/show.html.erb app/views/rooms/show.json.jbuilder config/routes.rb db/migrate/20140311195644_create_rooms.rb db/schema.rb test/controllers/rooms_controller_test.rb test/fixtures/rooms.yml test/helpers/rooms_helper_test.rb test/models/room_test.rb

Slide 58

Slide 58 text

Model app/assets/javascripts/rooms.js.coffee app/assets/stylesheets/rooms.css.scss app/controllers/rooms_controller.rb app/helpers/rooms_helper.rb app/models/room.rb app/views/rooms/_form.html.erb app/views/rooms/edit.html.erb app/views/rooms/index.html.erb app/views/rooms/index.json.jbuilder app/views/rooms/new.html.erb app/views/rooms/show.html.erb app/views/rooms/show.json.jbuilder config/routes.rb db/migrate/20140311195644_create_rooms.rb db/schema.rb test/controllers/rooms_controller_test.rb test/fixtures/rooms.yml test/helpers/rooms_helper_test.rb test/models/room_test.rb

Slide 59

Slide 59 text

class Room < ActiveRecord::Base end Class name Base class name

Slide 60

Slide 60 text

class Room < ActiveRecord::Base end Model name

Slide 61

Slide 61 text

Views app/assets/javascripts/rooms.js.coffee app/assets/stylesheets/rooms.css.scss app/controllers/rooms_controller.rb app/helpers/rooms_helper.rb app/models/room.rb app/views/rooms/_form.html.erb app/views/rooms/edit.html.erb app/views/rooms/index.html.erb app/views/rooms/index.json.jbuilder app/views/rooms/new.html.erb app/views/rooms/show.html.erb app/views/rooms/show.json.jbuilder config/routes.rb db/migrate/20140311195644_create_rooms.rb db/schema.rb test/controllers/rooms_controller_test.rb test/fixtures/rooms.yml test/helpers/rooms_helper_test.rb test/models/room_test.rb

Slide 62

Slide 62 text

Name: <%= @room.name %>

!

Description: <%= @room.description %>

! <%= link_to 'Edit', edit_room_path(@room) %> | <%= link_to 'Back', rooms_path %>

Slide 63

Slide 63 text

Name: <%= @room.name %>

!

Description: <%= @room.description %>

! <%= link_to 'Edit', edit_room_path(@room) %> | <%= link_to 'Back', rooms_path %> Render model! attributes

Slide 64

Slide 64 text

Name: <%= @room.name %>

!

Description: <%= @room.description %>

! <%= link_to 'Edit', edit_room_path(@room) %> | <%= link_to 'Back', rooms_path %> Render links

Slide 65

Slide 65 text

Controller app/assets/javascripts/rooms.js.coffee app/assets/stylesheets/rooms.css.scss app/controllers/rooms_controller.rb app/helpers/rooms_helper.rb app/models/room.rb app/views/rooms/_form.html.erb app/views/rooms/edit.html.erb app/views/rooms/index.html.erb app/views/rooms/index.json.jbuilder app/views/rooms/new.html.erb app/views/rooms/show.html.erb app/views/rooms/show.json.jbuilder config/routes.rb db/migrate/20140311195644_create_rooms.rb db/schema.rb test/controllers/rooms_controller_test.rb test/fixtures/rooms.yml test/helpers/rooms_helper_test.rb test/models/room_test.rb

Slide 66

Slide 66 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end

Slide 67

Slide 67 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Class name Base class name

Slide 68

Slide 68 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Controller name Base controller Controllers are classes

Slide 69

Slide 69 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Instance method Instance variable

Slide 70

Slide 70 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Action Controller actions are methods

Slide 71

Slide 71 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Retrieves all rooms from DB

Slide 72

Slide 72 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end "Macro"! (a class method) Private methods

Slide 73

Slide 73 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Macros are used to! create callbacks Private methods! are not actions

Slide 74

Slide 74 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Macros are used to! create callbacks Finds a single room by ID

Slide 75

Slide 75 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! def index @rooms = Room.all end ! def show end ! def new @room = Room.new end ! private ! def set_room @room = Room.find(params[:id]) end end Macros are used to! create callbacks "params" is a hash with! data submitted by a user

Slide 76

Slide 76 text

def create @room = Room.new(room_params) ! respond_to do |format| if @room.save format.html { redirect_to @room, notice: 'Room was successfully created.' } format.json { render action: 'show', status: :created, location: @room } else format.html { render action: 'new' } format.json { render json: @room.errors, status: :unprocessable_entity } end end end Create new room from what???

Slide 77

Slide 77 text

class RoomsController < ApplicationController before_action :set_room, only: [:show, :edit, :update, :destroy] ! # … ! def create # … end ! # … ! private ! # … ! # Never trust parameters from the scary internet, # only allow the white list through. def room_params params.require(:room).permit(:name, :description) end end

Slide 78

Slide 78 text

def create @room = Room.new(room_params) ! respond_to do |format| if @room.save format.html { redirect_to @room, notice: 'Room was successfully created.' } format.json { render action: 'show', status: :created, location: @room } else format.html { render action: 'new' } format.json { render json: @room.errors, status: :unprocessable_entity } end end end Good, we're safe

Slide 79

Slide 79 text

def create @room = Room.new(room_params) ! respond_to do |format| if @room.save format.html { redirect_to @room, notice: 'Room was successfully created.' } format.json { render action: 'show', status: :created, location: @room } else format.html { render action: 'new' } format.json { render json: @room.errors, status: :unprocessable_entity } end end end

Slide 80

Slide 80 text

def create @room = Room.new(room_params) ! respond_to do |format| if @room.save format.html { redirect_to @room, notice: 'Room was successfully created.' } format.json { render action: 'show', status: :created, location: @room } else format.html { render action: 'new' } format.json { render json: @room.errors, status: :unprocessable_entity } end end end HTML representation JSON representation! (API) Pick a format

Slide 81

Slide 81 text

Router app/assets/javascripts/rooms.js.coffee app/assets/stylesheets/rooms.css.scss app/controllers/rooms_controller.rb app/helpers/rooms_helper.rb app/models/room.rb app/views/rooms/_form.html.erb app/views/rooms/edit.html.erb app/views/rooms/index.html.erb app/views/rooms/index.json.jbuilder app/views/rooms/new.html.erb app/views/rooms/show.html.erb app/views/rooms/show.json.jbuilder config/routes.rb db/migrate/20140311195644_create_rooms.rb db/schema.rb test/controllers/rooms_controller_test.rb test/fixtures/rooms.yml test/helpers/rooms_helper_test.rb test/models/room_test.rb

Slide 82

Slide 82 text

# config/routes.rb ! RoomReservations::Application.routes.draw do resources :rooms end

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

Database migration app/assets/javascripts/rooms.js.coffee app/assets/stylesheets/rooms.css.scss app/controllers/rooms_controller.rb app/helpers/rooms_helper.rb app/models/room.rb app/views/rooms/_form.html.erb app/views/rooms/edit.html.erb app/views/rooms/index.html.erb app/views/rooms/index.json.jbuilder app/views/rooms/new.html.erb app/views/rooms/show.html.erb app/views/rooms/show.json.jbuilder config/routes.rb db/migrate/20140311195644_create_rooms.rb db/schema.rb test/controllers/rooms_controller_test.rb test/fixtures/rooms.yml test/helpers/rooms_helper_test.rb test/models/room_test.rb

Slide 85

Slide 85 text

# db/migrate/201403xxxxxxxx_create_rooms.rb ! class CreateRooms < ActiveRecord::Migration def change create_table :rooms do |t| t.string :name t.text :description ! t.timestamps end end end

Slide 86

Slide 86 text

# db/schema.rb ! ActiveRecord::Schema.define(version: 20140311195644) do ! create_table "rooms", force: true do |t| t.string "name" t.text "description" t.datetime "created_at" t.datetime "updated_at" end ! end

Slide 87

Slide 87 text

Scaffold some more! $ rails generate scaffold team \ name:string

Slide 88

Slide 88 text

Scaffold some more! $ rails generate scaffold reservation \ room:belongs_to team:belongs_to \ from:datetime until:datetime

Slide 89

Slide 89 text

Associations A reservation belongs to a team A reservation belongs to a room A room has many reservations A team has many reservations

Slide 90

Slide 90 text

Associations db/migrate/201403xxxxxxxx_create_reservations.rb ! create_table "reservations" do |t| t.integer "room_id" t.integer "team_id" t.datetime "from" t.datetime "until" t.datetime "created_at" t.datetime "updated_at" end

Slide 91

Slide 91 text

Should a user type numbers here?

Slide 92

Slide 92 text

Select lists
<%= f.label :room %>
<%= f.text_field :room %>
<%= f.label :team %>
<%= f.text_field :team %>
<%= f.label :from %>
<%= f.datetime_select :from %>
<%= f.label :until %>
<%= f.datetime_select :until %>

Slide 93

Slide 93 text

Select lists
<%= f.label :room %>
<%= f.text_field :room %>
<%= f.label :team %>
<%= f.text_field :team %>
<%= f.label :from %>
<%= f.datetime_select :from %>
<%= f.label :until %>
<%= f.datetime_select :until %>

Slide 94

Slide 94 text

Select lists
<%= f.label :room %>
<%= f.collection_select :room_id, Room.all, :id, :name %>
<%= f.label :team %>
<%= f.collection_select :team_id, Team.all, :id, :name %>
<%= f.label :from %>
<%= f.datetime_select :from %>
<%= f.label :until %>
<%= f.datetime_select :until %>

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

Umm?

Slide 97

Slide 97 text

Relation display # app/views/reservations/show.html.erb !

Room: <%= @reservation.room %>

!

Team: <%= @reservation.team %>

!

From: <%= @reservation.from %>

!

Until: <%= @reservation.until %>

Slide 98

Slide 98 text

Relation display # app/views/reservations/show.html.erb !

Room: <%= @reservation.room %>

!

Team: <%= @reservation.team %>

!

From: <%= @reservation.from %>

!

Until: <%= @reservation.until %>

Slide 99

Slide 99 text

Relation display # app/views/reservations/show.html.erb !

Room: <%= @reservation.room.name %>

!

Team: <%= @reservation.team.name %>

!

From: <%= @reservation.from %>

!

Until: <%= @reservation.until %>

Slide 100

Slide 100 text

Not bad, but it can be better

Slide 101

Slide 101 text

Date/time format # app/views/reservations/show.html.erb !

Room: <%= @reservation.room.name %>

!

Team: <%= @reservation.team.name %>

!

From: <%= @reservation.from %>

!

Until: <%= @reservation.until %>

Slide 102

Slide 102 text

Date/time format # app/views/reservations/show.html.erb !

Room: <%= @reservation.room.name %>

!

Team: <%= @reservation.team.name %>

!

From: <%= @reservation.from.to_s(:short) %>

!

Until: <%= @reservation.until.to_s(:short) %>

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

Root route # config/routes.rb ! RoomReservations::Application.routes.draw do resources :reservations resources :teams resources :rooms end

Slide 106

Slide 106 text

Root route # config/routes.rb ! RoomReservations::Application.routes.draw do root 'reservations#index' ! resources :reservations resources :teams resources :rooms end

Slide 107

Slide 107 text

No content

Slide 108

Slide 108 text

Photo upload Where to store images?! Server's hard drive Database Cloud Problematic with! deployments Just… don't

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

Is there a magic solution? CarrierWave gem Cloudinary service

Slide 111

Slide 111 text

Gems # Gemfile ! source 'https://rubygems.org' ! gem 'rails', '4.0.0' gem 'sqlite3' gem 'sass-rails', '~> 4.0.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.0.0' gem 'jquery-rails' gem 'turbolinks' gem 'jbuilder', '~> 1.2' ! group :doc do gem 'sdoc', require: false end

Slide 112

Slide 112 text

Gems # Gemfile ! source 'https://rubygems.org' ! gem 'rails', '4.0.0' gem 'sqlite3' gem 'sass-rails', '~> 4.0.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.0.0' gem 'jquery-rails' gem 'turbolinks' gem 'jbuilder', '~> 1.2' ! gem 'carrierwave' gem 'cloudinary' ! group :doc do gem 'sdoc', require: false end

Slide 113

Slide 113 text

Install new gems $ bundle install

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

No content

Slide 116

Slide 116 text

Generate the uploader $ rails generate uploader RoomPhoto

Slide 117

Slide 117 text

And edit it… # app/uploaders/room_photo_uploader.rb ! class RoomPhotoUploader < CarrierWave::Uploader::Base include Cloudinary::CarrierWave end

Slide 118

Slide 118 text

Generate the migration $ rails generate migration \ add_photo_to_room

Slide 119

Slide 119 text

Edit the last migration # db/migrate/201403xxxxxxxx_add_photo_to_room.rb ! class AddPhotoToRoom < ActiveRecord::Migration def change add_column :rooms, :photo, :string end end

Slide 120

Slide 120 text

And setup the model # app/models/room.rb ! class Room < ActiveRecord::Base mount_uploader :photo, RoomPhotoUploader end

Slide 121

Slide 121 text

Modify the form… # app/views/rooms/_form.html.erb !
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.hidden_field(:photo_cache) %> <%= f.label :photo %>
<%= f.file_field(:photo) %>

Slide 122

Slide 122 text

No content

Slide 123

Slide 123 text

Display the photo… # app/views/rooms/show.html.erb !

Name: <%= @room.name %>

!

Description: <%= @room.description %>

! <% if @room.photo %>

<%= link_to @room.photo.url do %> <%= cl_image_tag(@room.photo, width: 200, height: 200, crop: :fit) %> <% end %>

<% end %>

Slide 124

Slide 124 text

No content

Slide 125

Slide 125 text

User authentication Let's use Devise!

Slide 126

Slide 126 text

WARNING "If you are building your first Rails application, we recommend you to not use Devise. Devise requires a good understanding of the Rails Framework. In such cases, we advise you to start a simple authentication system from scratch."

Slide 127

Slide 127 text

Gems # Gemfile ! source 'https://rubygems.org' ! gem 'rails', '4.0.0' gem 'sqlite3' gem 'sass-rails', '~> 4.0.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.0.0' gem 'jquery-rails' gem 'turbolinks' gem 'jbuilder', '~> 1.2' ! gem 'carrierwave' gem 'cloudinary' gem 'devise' ! group :doc do gem 'sdoc', require: false end

Slide 128

Slide 128 text

Install new gems $ bundle install

Slide 129

Slide 129 text

Setup Devise #1 $ rails generate devise:install

Slide 130

Slide 130 text

Setup Devise #2 $ rails generate devise team $ rake db:migrate

Slide 131

Slide 131 text

Protect the application # app/controllers/application_controller.rb ! class ApplicationController < ActionController::Base protect_from_forgery with: :exception ! before_action :authenticate_team! end

Slide 132

Slide 132 text

No content

Slide 133

Slide 133 text

Where should a user enter team name?

Slide 134

Slide 134 text

Customize signup template $ rails generate devise:views

Slide 135

Slide 135 text

Customize signup template # app/views/devise/registrations/new.html.erb !

Sign up

! <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= devise_error_messages! %> !
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
!
<%= f.label :password %>
<%= f.password_field :password %>
!
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
!
<%= f.submit "Sign up" %>
<% end %> ! <%= render "devise/shared/links" %>

Slide 136

Slide 136 text

Customize signup template # app/views/devise/registrations/new.html.erb !

Sign up

! <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= devise_error_messages! %> !
<%= f.label :name %>
<%= f.text_field :name, autofocus: true %>
!
<%= f.label :email %>
<%= f.email_field :email %>
!
<%= f.label :password %>
<%= f.password_field :password %>
!
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
!
<%= f.submit "Sign up" %>
<% end %> ! <%= render "devise/shared/links" %>

Slide 137

Slide 137 text

Whitelist the attribute # app/controllers/application_controller.rb ! class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :authenticate_team! end

Slide 138

Slide 138 text

Whitelist the attribute # app/controllers/application_controller.rb ! class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :authenticate_team! before_action :configure_permitted_parameters, if: :devise_controller? ! private ! def configure_permitted_parameters devise_parameter_sanitizer.for(:sign_up) << :name end end

Slide 139

Slide 139 text

No content

Slide 140

Slide 140 text

Next steps Prevent other teams to:! edit team info delete teams create new teams change reservations

Slide 141

Slide 141 text

No content

Slide 142

Slide 142 text

Gems # Gemfile ! source 'https://rubygems.org' ! gem 'rails', '4.0.0' gem 'sqlite3' gem 'sass-rails', '~> 4.0.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.0.0' gem 'jquery-rails' gem 'turbolinks' gem 'jbuilder', '~> 1.2' ! gem 'carrierwave' gem 'cloudinary' gem 'devise' gem 'bootstrap-sass', '~> 3.1.1' ! group :doc do gem 'sdoc', require: false end

Slide 143

Slide 143 text

Install new gems $ bundle install

Slide 144

Slide 144 text

Change CSS # app/assets/stylesheets/application.css ! /* * 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 . */

Slide 145

Slide 145 text

Change CSS # app/assets/stylesheets/application.css ! @import "bootstrap"; @import "bootstrap/theme";

Slide 146

Slide 146 text

Rename the file! Sass is a CSS pre-processor application.css → application.css.scss

Slide 147

Slide 147 text

Prettify the app! # app/views/reservations/index.html.erb ! <%= link_to 'Show', reservation %> <% if reservation.team == current_team %> <%= link_to 'Edit', edit_reservation_path(reservation) %> <%= link_to 'Destroy', reservation, method: :delete, data: { confirm: 'Are you sure?' } %> <% end %>

Slide 148

Slide 148 text

Prettify the app! # app/views/reservations/index.html.erb !
<%= link_to 'Show', reservation, class: "btn btn-primary" %> <% if reservation.team == current_team %> <%= link_to 'Edit', edit_reservation_path(reservation), class: "btn btn-default" %> <%= link_to 'Destroy', reservation, method: :delete, class: "btn btn-danger", data: { confirm: 'Are you sure?' } %> <% end %>

Slide 149

Slide 149 text

Add navbar # app/views/layouts/application.html.erb !
!

Slide 150

Slide 150 text

Also modify JS # app/assets/javascripts/application.js ! //= require jquery //= require jquery_ujs //= require turbolinks //= require bootstrap //= require_tree .

Slide 151

Slide 151 text

And now it's up to you!

Slide 152

Slide 152 text

Code for Room Reservation:
 https://github.com/sidonath/room-reservations/ Guides to various Rails-related topics:
 http://guides.rubyonrails.org/ CarrierWave homepage:
 https://github.com/carrierwaveuploader/carrierwave Cloudinary Rails/CarrierWave docs:
 http://cloudinary.com/documentation/rails_carrierwave Devise Readme:
 https://github.com/plataformatec/devise/tree/v3.2.3 Twitter Bootstrap homepage:
 http://getbootstrap.com/

Slide 153

Slide 153 text

When you have more time to study Rails or Ruby http://tutorials.jumpstartlab.com/ http://mislav.uniqpath.com/poignant-guide/ http://pragprog.com/book/rails4/agile-web-development-with-rails-4