SlideShare a Scribd company logo
Rails MVC
1
Model-View-Controller
Trygve Reenskaug. 1978
● Separation of business logic
● Reusing of code
● Separation of responsibility
● Flexible application
BENEFITS
● Doesn’t have a strict implementation
● No one place for busines logic
● No one place for validations
● No one place for views
PROPERTIES
Rails MVC
in the context
of user
MVC is an Architectural Pattern
8
My Banana
Stuart, give me
the banana
Ostap, are
you here?
I’m coming
put on a suit
Farewell !!!
Rails MVC
in the context
of components
10
Router
Controller ModelResponse
Views DataBase
Rails MVC
in the context
of Rails libraries
12
ROUTES
13
resource :profile, only: %i[show edit update], controller: :profile
14
RESOURCE
1 Rails.application.routes.draw do
2 root 'home#index'
3
4 resources :events, only: %i[index show] do
5 resources :visit_requests, only: %i[show create destroy]
6 end
15
RESOURCES
CUSTOM ROUTES WITHIN RESOURCES
1 resources :orders do
2 collection do
3 post :search
4 end
5 member do
6 post :accept
7 post :reject
8 post :ship
9 get :despatch_note
10 end
11 end
16
get '/:page_url', to: 'pages#show'
authenticate :user, ->(u) { u.admin? } do
namespace :admin do
get '/', to: 'home#index'
resources :accounts
17
CUSTOM ROUTES, NAMESPACE
1 # api
2 namespace :api, path: '/', constraints: { subdomain: 'api' }, defaults: { format: :json } do
3 namespace :v1 do
4 post 'sign_up' => 'registrations#create'
5 post 'sign_in' => 'sessions#create'
6 delete 'sign_out' => 'sessions#destroy'
7 end
8 end
18
NAMESPACES
api_v1_sign_up POST /v1/sign_up(.:format) api/v1/registrations#create
{:subdomain=>"api", :format=>:json}
api_v1_sign_in POST /v1/sign_in(.:format) api/v1/sessions#create
{:subdomain=>"api", :format=>:json}
api_v1_sign_out DELETE /v1/sign_out(.:format) api/v1/sessions#destroy
{:subdomain=>"api", :format=>:json}
1 # api
2 scope :api, constraints: { subdomain: 'api' }, module: :api, defaults: { format: :json }, as: :api do
3 scope '/v1', module: :v1, as: :v1 do
4 post 'sign_up' => 'registrations#create'
5 post 'sign_in' => 'sessions#create'
6 delete 'sign_out' => 'sessions#destroy'
7 end
8 end
19
SCOPES
api_v1_sign_up POST /v1/sign_up(.:format) api/v1/registrations#create
{:subdomain=>"api", :format=>:json}
api_v1_sign_in POST /v1/sign_in(.:format) api/v1/sessions#create
{:subdomain=>"api", :format=>:json}
api_v1_sign_out DELETE /v1/sign_out(.:format) api/v1/sessions#destroy
{:subdomain=>"api", :format=>:json}
20
Wait!
Aren’t namespaces and scopes essentially the same?
1 # api
2 scope :api do
3 scope :v1 do
4 post 'sign_up' => 'registrations#create'
5 post 'sign_in' => 'sessions#create'
6 delete 'sign_out' => 'sessions#destroy'
7 end
8 end
21
SCOPES WITHOUT ANY OPTIONS
sign_up POST /sign_up(.:format) registrations#create
sign_in POST /sign_in(.:format) sessions#create
sign_out DELETE /sign_out(.:format) sessions#destroy
22
NAMESPACE vs SCOPE
Namespace Scope
By default, adds the name of the
namespace to the name of the path,
prefixes actual request path, and expects
the controller to belong to appropriately
named module.
No defaults. All options are explicit.
A shortcut method when you need to
quickly nest a set of routes and controllers
under some name.
A powerful, customizable method to apply
defaults to a group of routes.
1 namespace :admin do
2 root "admin#index"
3 end
4
5 root "home#index"
23
MULTIPLE ROOT ROUTES
1 constraints(id: /[A-Z][A-Z][0-9]+/) do
2 resources :photos
3 resources :accounts
4 end
24
CONSTRAINTS
CONTROLLERS
25
1 def create
2 @product = Product.new(safe_params)
3 if @product.save
4 redirect_to :products, flash: { notice: t('shopr.products.create_notice') }
5 else
6 render action: 'new'
7 end
8 end
9
10 def update
11 if @product.update(safe_params)
12 redirect_to [:edit, @product], flash: { notice: t('products.update_notice') }
13 else
14 render action: 'edit'
15 end
16 end
26
DEFAULT ACTIONS
1 class ApplicationController < ActionController::Base
2 protect_from_forgery with: :exception
3 before_action :auth, only: :admin
4 helper_method :admin?, :about_page, :contacts_page
6 delegate :admin?, to: :current_user, allow_nil: true
7 skip_authorization_check
8 skip_before_action :authenticate_user!
27
HELPERS, BEFORE ACTIONS, ...
1 def create
2 @protocol = Protocol.create(protocol_params)
3 end
4
5 private
6
7 def protocol_params
8 params.require(:protocol).permit(
9 :competition_id,
10 :first_name,
11 :last_name,
12 :total_result,
13 :place
14 )
15 end
28
PERMITTED PARAMS
1 def create
2 @product = Product.new(safe_params)
3 if @product.save
4 redirect_to :products, flash: { notice: t('shopr.products.create_notice') }
5 else
6 render action: 'new'
7 end
8 end
29
REDIRECT VS RENDER
render :edit
render action: :edit
render "edit"
render "edit.html.erb"
render action: "edit"
render action: "edit.html.erb"
render "books/edit"
render "books/edit.html.erb"
30
RENDER
render template: "books/edit"
render template: "books/edit.html.erb"
render "/path/to/rails/app/views/books/edit"
render "/path/to/rails/app/views/books/edit.html.erb"
render file: "/path/to/rails/app/views/books/edit"
render file: "/path/to/rails/app/views/books/edit.html.erb"
1 def create
2 Shopr::Order.transaction do
3 @order = Shopr::Order.new(safe_params)
4 @order.status = 'confirming'
5 if safe_params[:customer_id]
6 @customer = Shopr::Customer.find safe_params[:customer_id]
7 @order.first_name = @customer.first_name
8 @order.last_name = @customer.last_name
9 @order.company = @customer.company
10 @order.email_address = @customer.email
11 @order.phone_number = @customer.phone
12 if @customer.addresses.billing.present?
13 billing = @customer.addresses.billing.first
14 @order.billing_address1 = billing.address1
15 @order.billing_address2 = billing.address2
16 @order.billing_address3 = billing.address3
17 @order.billing_address4 = billing.address4
18 @order.billing_postcode = billing.postcode
19 @order.billing_country_id = billing.country_id
31
FAT CONTROLLERS
1 class VisitRequestsController < ApplicationController
2 before_action :authenticate_user!, only: %i[create destroy]
3
4 def show
5 VisitRequest::FinalConfirmation.call(visit_request, params)
6 flash_success(visit_request.status) and default_redirect
7 end
8
9 def create
10 VisitRequest::Create.call(current_user, event)
11 flash_success and default_redirect
12 end
13
14 def destroy
15 visit_request.destroy
16 flash_success and default_redirect
17 end
32
THIN CONTROLLERS
MODELS
33
1 class Goal < ApplicationRecord
2 has_many :donations, dependent: :destroy
3
4 validates :title, presence: true
5 validates :amount, presence: true, numericality: true
6
7 def achieved?
8 donations_total >= amount
9 end
10
11 def donations_total
12 donations.sum(:amount)
13 end
14 end
34
MODELS
class Goal < ApplicationRecord
has_many :donations, dependent: :destroy
end
class Donation < ApplicationRecord
belongs_to :goal
end
35
ONE TO MANY/ONE RELATIONS
Goal
id:integer
title:string
Donation
id:integer
goal_id:integer
title:string
...
...
36
MANY TO MANY RELATIONS
Goal
id:integer
title:string
Donation
id:integer
title:string
... ...
class Goal < ApplicationRecord
has_and_belongs_to_many :donations
end
class Donation < ApplicationRecord
has_and_belongs_to_many :goal
end
donations_goals
goal_id:integer
donation_id:integer
37
ASSOCIATION RELATIONS
Goal
id:integer
title:string
Donation
id:integer
goal_id:integer
...
...
class Goal < ApplicationRecord
has_many :donations
has_many :users, through: :donations
end
class Donation < ApplicationRecord
belongs_to :goal
belongs_to :user
end
class User < ApplicationRecord
has_many :donations
end
User
id:integer
email:string
...
user_id:integer
38
POLYMORPHIC RELATIONS
User
id:integer
email:string
Company
id:integer
name:string
... ...
Address
id:integer
address:string
addressable_id:integer
addressable_type:string
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
class User < ApplicationRecord
has_many :address, as: :assressable
end
class Company < ApplicationRecord
has_many :address, as: :assressable
end
1 class Goal < ApplicationRecord
2 validates :title, presence: true
3 end
4
5 goal = Goal.create(title: “Buying a motocycle”).valid? # => true
6 goal = Goal.create(title: nil).valid? # => false
7 goal.errors.messages # => {title:["can't be blank"]}
39
VALIDATES
1 class Goal < ApplicationRecord
2 validates_associated :donations #(only in one of related model)
3 validates_with GoalValidator #class GoalValidator < ActiveModel::Validator
4 validate :expiration_date_cannot_be_in_the_past
5
6 def expiration_date_cannot_be_in_the_past
7 if expiration_date.present? && expiration_date < Date.today
8 errors.add(:expiration_date, "can't be in the past")
9 end
10 end
11 end
40
VALIDATES
VIEWS
41
1 <h2> <%= t 'goals.singular'> </h1>
2
3 < div class="col-md-12" >
4 <%= goal.title >
5 < /div>
6 < div class="col-md-12" >
7 <%= goal.description >
8 < /div>
9 < div class="col-md-12" >
10 <%= "Amount to reach: #{goal.amount}" >
11 < /div>
12 < div class="col-md-12" >
13 <%= "Current sum: #{goal.donations_total}" >
14 < /div>
42
TEMPLATES
1 <h2> <%= t 'goals.singular'> </h1>
2
3 < div class="col-md-12" >
4 <%= goal.title >
5 < /div>
6 < div class="col-md-12" >
7 <%= goal.description >
8 < /div>
9 < div class="col-md-12" >
10 <%= "Amount to reach: #{goal.amount}" >
11 < /div>
12 < div class="col-md-12" >
13 <%= "Current sum: #{goal.donations_total}" >
14 < /div>
43
.html.erb (ERB - Embedded Ruby)
1 h2 = t 'goals.singular'
2
3 .col-md-12
4 = goal.title
5 .col-md-12
6 = goal.description
7 .col-md-12
8 = "Amount to reach: #{goal.amount}"
9 .col-md-12
10 = "Current sum: #{goal.donations_total}"
11 .col-md-12
12 - unless goal.achieved?
13 = render 'shared/donations/form', path: donate_goal_path(goal)
44
.html.slim
1 $('#notifications_list').html(
2 "<%= escape_javascript(render('notifications/list', notifications: @notifications)) %>"
3 );
4
5 $('.container-fluid .flash-msg').html(
6 "<%= escape_javascript(render 'layouts/alerts') %>"
7 );
8
9 $("#send-notification-modal").modal("hide");
45
.js.erb
1 json.extract! ticket, :id,
:uid,
:manager_id,
:customer_name,
:customer_email,
:title,
:body,
:status_id
2 json.url ticket_url(ticket, format: :json)
46
.json.jbuilder
new.html.slim
1 = render 'shared/donations/form',
path: donate_goal_path(goal)
edit.html.slim
1 = render 'shared/donations/form',
path: donate_goal_path(goal)
47
PARTIALS
_form.html.slim
= simple_form_for :credit_card, url: path do |f|
.form-inputs
.row
.col-md-6
= f.input :number, as: :string
= f.input :cvc, as: :string
= f.input :exp_month, as: :string
= f.input :exp_year, as: :string
1 <h1>Listing Books</h1>
2 <table>
3 <tr>
4 <th>Title</th>
5 <th>Summary</th>
6 <th></th>
7 <th></th>
8 <th></th>
9 </tr>
10 <% @books.each do |book| %>
11 <tr>
12 <td><%= book.title %></td>
13 <td><%= book.content %></td>
14 <td><%= link_to "Show", book %></td>
15 <td><%= link_to "Edit", edit_book_path(book) %></td>
16 <td><%= link_to "Remove", book, method: :delete, data: { confirm: "Are you sure?" } %></td>
17 </tr>
18 <% end %>
19 </table>
48
PARTIALS. MAGIC
/views/books/index.html.erb
1 <h1>Listing Books</h1>
2 <table>
3 <tr>
4 <th>Title</th>
5 <th>Summary</th>
6 <th></th>
7 <th></th>
8 <th></th>
9 </tr>
10 <%= render @books %>
11 </table> 49
PARTIALS. MAGIC
/views/books/_book.html.erb
1 <tr>
2 <td><%= book.title %></td>
3 <td><%= book.content %></td>
4 <td><%= link_to "Show", book %></td>
5 <td><%= link_to "Edit", edit_book_path(book) %></td>
16 <td><%= link_to "Remove", book, method: :delete, data:
{ confirm: "Are you sure?" } %></td>
17 </tr>
50
LAYOUTS
class HomeController < ApplicationController
def index
render 'events/show'
end
end
51
LAYOUTS
class TalksController < ApplicationController
helper_method :talks, :talk, :tags
private
def talks
scope = Talk.published.includes(:event).order('events.finished_at desc')
@talks ||= params[:tag] ? scope.tagged_with(params[:tag]) : scope
@talks.page(params[:page]).per(12)
end
end
class PagesController < ApplicationController
helper_method :page
def show
page ? render(:show) : not_found
end
private
def page
@page ||= Page.find_by(url: params[:page_url])
end
end
class AuthController < ActionController::Base
layout "devise"
end
doctype html
html
head
title
= content_for?(:title) ? yield(:title) : t('default_title')
= stylesheet_link_tag 'app/application'
meta name="theme-color" content="#ffffff"
== render 'layouts/ga/head'
body class="#{yield(:main_body_class)}"
= yield(:before_header)
== render 'layouts/app/flash'
== render 'layouts/app/header'
main
= yield
52
application.slim vs admin.slim
doctype html
html
head
title
= content_for?(:title) ? yield(:title) : t('default_admin_title')
= stylesheet_link_tag 'admin/application'
meta name="viewport" content="width=device-width,
initial-scale=1, shrink-to-fit=no"
body
.ui.sidebar.inverted.vertical.menu
== render 'layouts/admin/navigation'
.pusher
.ui.container#container
== render 'layouts/admin/header'
= yield
== render 'layouts/admin/footer'
views/events/index.slim
...
tbody
- events.each do |event|
tr
th = event.id
td = resource_link(event)
td = format_timestamp(event.started_at)
td = format_timestamp(event.finished_at)
53
HELPERS
helpers/...
module TalksHelper
def talk_link(talk, text = "", options = {})
link_to text, polymorphic_path(talk), options
end
end
module ApplicationHelper
def format_timestamp(timestamp, time: true, delimiter: '-')
return unless timestamp
formatted_date = timestamp.strftime('%Y %b %d')
formatted_time = timestamp.strftime('%H:%M')
return formatted_date if !time
"#{formatted_date} #{delimiter} #{formatted_time}"
end
● Fat model and Skinny controller
● Business logic should always be in the
model
● The view should have minimal code
● Use helpers!
● Use models
● DRY (Don't Repeat Yourself)
54
BEST
PRACTICES
https://github.com/rails/rails
http://api.rubyonrails.org/
http://guides.rubyonrails.org/
https://github.com/bbatsov/rails-style-guide
55
RESOURCES

More Related Content

What's hot

Service approach for development Rest API in Symfony2
Service approach for development Rest API in Symfony2Service approach for development Rest API in Symfony2
Service approach for development Rest API in Symfony2
Sumy PHP User Grpoup
 
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Antonio Peric-Mazar
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4
Javier Eguiluz
 
Resource and view
Resource and viewResource and view
Resource and viewPapp Laszlo
 
Single Page Web Apps with Backbone.js and Rails
Single Page Web Apps with Backbone.js and RailsSingle Page Web Apps with Backbone.js and Rails
Single Page Web Apps with Backbone.js and Rails
Prateek Dayal
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2
Javier Eguiluz
 
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - WisemblySymfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
Guillaume POTIER
 
CRUD with Dojo
CRUD with DojoCRUD with Dojo
CRUD with Dojo
Eugene Lazutkin
 
JavaServer Faces 2.0 - JavaOne India 2011
JavaServer Faces 2.0 - JavaOne India 2011JavaServer Faces 2.0 - JavaOne India 2011
JavaServer Faces 2.0 - JavaOne India 2011
Arun Gupta
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
Antonio Peric-Mazar
 
Send, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script codeSend, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script code
Noushadur Shoukhin
 
Drupal 8 simple page: Mi primer proyecto en Drupal 8.
Drupal 8 simple page: Mi primer proyecto en Drupal 8.Drupal 8 simple page: Mi primer proyecto en Drupal 8.
Drupal 8 simple page: Mi primer proyecto en Drupal 8.
Samuel Solís Fuentes
 
Spring Surf 101
Spring Surf 101Spring Surf 101
Spring Surf 101
Alfresco Software
 
Empowering users: modifying the admin experience
Empowering users: modifying the admin experienceEmpowering users: modifying the admin experience
Empowering users: modifying the admin experience
Beth Soderberg
 
SAVIA
SAVIASAVIA
2012.sandiego.wordcamp
2012.sandiego.wordcamp2012.sandiego.wordcamp
2012.sandiego.wordcampBrandon Dove
 
AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFaces
Ankara JUG
 
Custom post-framworks
Custom post-framworksCustom post-framworks
Custom post-framworks
Kiera Howe
 

What's hot (19)

Service approach for development Rest API in Symfony2
Service approach for development Rest API in Symfony2Service approach for development Rest API in Symfony2
Service approach for development Rest API in Symfony2
 
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4
 
Resource and view
Resource and viewResource and view
Resource and view
 
Single Page Web Apps with Backbone.js and Rails
Single Page Web Apps with Backbone.js and RailsSingle Page Web Apps with Backbone.js and Rails
Single Page Web Apps with Backbone.js and Rails
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2
 
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - WisemblySymfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
 
CRUD with Dojo
CRUD with DojoCRUD with Dojo
CRUD with Dojo
 
JavaServer Faces 2.0 - JavaOne India 2011
JavaServer Faces 2.0 - JavaOne India 2011JavaServer Faces 2.0 - JavaOne India 2011
JavaServer Faces 2.0 - JavaOne India 2011
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
Send, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script codeSend, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script code
 
Drupal 8 simple page: Mi primer proyecto en Drupal 8.
Drupal 8 simple page: Mi primer proyecto en Drupal 8.Drupal 8 simple page: Mi primer proyecto en Drupal 8.
Drupal 8 simple page: Mi primer proyecto en Drupal 8.
 
Layout
LayoutLayout
Layout
 
Spring Surf 101
Spring Surf 101Spring Surf 101
Spring Surf 101
 
Empowering users: modifying the admin experience
Empowering users: modifying the admin experienceEmpowering users: modifying the admin experience
Empowering users: modifying the admin experience
 
SAVIA
SAVIASAVIA
SAVIA
 
2012.sandiego.wordcamp
2012.sandiego.wordcamp2012.sandiego.wordcamp
2012.sandiego.wordcamp
 
AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFaces
 
Custom post-framworks
Custom post-framworksCustom post-framworks
Custom post-framworks
 

Similar to Rails MVC by Sergiy Koshovyi

Ruby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter BootstrapRuby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter Bootstrap
Marcio Marinho
 
Angular.js Fundamentals
Angular.js FundamentalsAngular.js Fundamentals
Angular.js Fundamentals
Mark
 
Rails antipattern-public
Rails antipattern-publicRails antipattern-public
Rails antipattern-public
Chul Ju Hong
 
Rails antipatterns
Rails antipatternsRails antipatterns
Rails antipatterns
Chul Ju Hong
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
Mike Subelsky
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
Ben Scofield
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
Viget Labs
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
rstankov
 
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Coupa Software
 
Rails::Engine
Rails::EngineRails::Engine
Rails::Engine
Flavian Missi
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.js
Mark
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperfNew Relic
 
RoR 101: Session 2
RoR 101: Session 2RoR 101: Session 2
RoR 101: Session 2
Rory Gianni
 
Presenters in Rails
Presenters in RailsPresenters in Rails
Presenters in Rails
Mike Desjardins
 
Api development with rails
Api development with railsApi development with rails
Api development with rails
Edwin Cruz
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
Vagmi Mudumbai
 
Building Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsBuilding Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in Rails
Jim Jeffers
 
Be happy with Ruby on Rails - CEUNSP Itu
Be happy with Ruby on Rails - CEUNSP ItuBe happy with Ruby on Rails - CEUNSP Itu
Be happy with Ruby on Rails - CEUNSP Itu
Lucas Renan
 
Template rendering in rails
Template rendering in rails Template rendering in rails
Template rendering in rails
Hung Wu Lo
 

Similar to Rails MVC by Sergiy Koshovyi (20)

The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
Ruby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter BootstrapRuby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter Bootstrap
 
Angular.js Fundamentals
Angular.js FundamentalsAngular.js Fundamentals
Angular.js Fundamentals
 
Rails antipattern-public
Rails antipattern-publicRails antipattern-public
Rails antipattern-public
 
Rails antipatterns
Rails antipatternsRails antipatterns
Rails antipatterns
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
 
Rails::Engine
Rails::EngineRails::Engine
Rails::Engine
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.js
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
 
RoR 101: Session 2
RoR 101: Session 2RoR 101: Session 2
RoR 101: Session 2
 
Presenters in Rails
Presenters in RailsPresenters in Rails
Presenters in Rails
 
Api development with rails
Api development with railsApi development with rails
Api development with rails
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
Building Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsBuilding Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in Rails
 
Be happy with Ruby on Rails - CEUNSP Itu
Be happy with Ruby on Rails - CEUNSP ItuBe happy with Ruby on Rails - CEUNSP Itu
Be happy with Ruby on Rails - CEUNSP Itu
 
Template rendering in rails
Template rendering in rails Template rendering in rails
Template rendering in rails
 

More from Pivorak MeetUp

Lisp(Lots of Irritating Superfluous Parentheses)
Lisp(Lots of Irritating Superfluous Parentheses)Lisp(Lots of Irritating Superfluous Parentheses)
Lisp(Lots of Irritating Superfluous Parentheses)
Pivorak MeetUp
 
Some strange stories about mocks.
Some strange stories about mocks.Some strange stories about mocks.
Some strange stories about mocks.
Pivorak MeetUp
 
Business-friendly library for inter-service communication
Business-friendly library for inter-service communicationBusiness-friendly library for inter-service communication
Business-friendly library for inter-service communication
Pivorak MeetUp
 
How i was a team leader once
How i was a team leader onceHow i was a team leader once
How i was a team leader once
Pivorak MeetUp
 
Introduction to Rails by Evgeniy Hinyuk
Introduction to Rails by Evgeniy HinyukIntroduction to Rails by Evgeniy Hinyuk
Introduction to Rails by Evgeniy Hinyuk
Pivorak MeetUp
 
Ruby OOP (in Ukrainian)
Ruby OOP (in Ukrainian)Ruby OOP (in Ukrainian)
Ruby OOP (in Ukrainian)
Pivorak MeetUp
 
Testing in Ruby
Testing in RubyTesting in Ruby
Testing in Ruby
Pivorak MeetUp
 
Ruby Summer Course by #pivorak & OnApp - OOP Basics in Ruby
Ruby Summer Course by #pivorak & OnApp - OOP Basics in RubyRuby Summer Course by #pivorak & OnApp - OOP Basics in Ruby
Ruby Summer Course by #pivorak & OnApp - OOP Basics in Ruby
Pivorak MeetUp
 
The Saga Pattern: 2 years later by Robert Pankowecki
The Saga Pattern: 2 years later by Robert PankoweckiThe Saga Pattern: 2 years later by Robert Pankowecki
The Saga Pattern: 2 years later by Robert Pankowecki
Pivorak MeetUp
 
Data and Bounded Contexts by Volodymyr Byno
Data and Bounded Contexts by Volodymyr BynoData and Bounded Contexts by Volodymyr Byno
Data and Bounded Contexts by Volodymyr Byno
Pivorak MeetUp
 
Successful Remote Development by Alex Rozumii
Successful Remote Development by Alex RozumiiSuccessful Remote Development by Alex Rozumii
Successful Remote Development by Alex Rozumii
Pivorak MeetUp
 
Origins of Elixir programming language
Origins of Elixir programming languageOrigins of Elixir programming language
Origins of Elixir programming language
Pivorak MeetUp
 
Functional Immutable CSS
Functional Immutable CSS Functional Immutable CSS
Functional Immutable CSS
Pivorak MeetUp
 
Multi language FBP with Flowex by Anton Mishchuk
Multi language FBP with Flowex by Anton Mishchuk Multi language FBP with Flowex by Anton Mishchuk
Multi language FBP with Flowex by Anton Mishchuk
Pivorak MeetUp
 
Detective story of one clever user - Lightning Talk By Sergiy Kukunin
Detective story of one clever user - Lightning Talk By Sergiy KukuninDetective story of one clever user - Lightning Talk By Sergiy Kukunin
Detective story of one clever user - Lightning Talk By Sergiy Kukunin
Pivorak MeetUp
 
CryptoParty: Introduction by Olexii Markovets
CryptoParty: Introduction by Olexii MarkovetsCryptoParty: Introduction by Olexii Markovets
CryptoParty: Introduction by Olexii Markovets
Pivorak MeetUp
 
How to make first million by 30 (or not, but tryin') - by Marek Piasecki
How to make first million by 30 (or not, but tryin') - by Marek PiaseckiHow to make first million by 30 (or not, but tryin') - by Marek Piasecki
How to make first million by 30 (or not, but tryin') - by Marek Piasecki
Pivorak MeetUp
 
GIS on Rails by Oleksandr Kychun
GIS on Rails by Oleksandr Kychun GIS on Rails by Oleksandr Kychun
GIS on Rails by Oleksandr Kychun
Pivorak MeetUp
 
Unikernels - Keep It Simple to the Bare Metal
Unikernels - Keep It Simple to the Bare MetalUnikernels - Keep It Simple to the Bare Metal
Unikernels - Keep It Simple to the Bare Metal
Pivorak MeetUp
 
HTML Canvas tips & tricks - Lightning Talk by Roman Rodych
 HTML Canvas tips & tricks - Lightning Talk by Roman Rodych HTML Canvas tips & tricks - Lightning Talk by Roman Rodych
HTML Canvas tips & tricks - Lightning Talk by Roman Rodych
Pivorak MeetUp
 

More from Pivorak MeetUp (20)

Lisp(Lots of Irritating Superfluous Parentheses)
Lisp(Lots of Irritating Superfluous Parentheses)Lisp(Lots of Irritating Superfluous Parentheses)
Lisp(Lots of Irritating Superfluous Parentheses)
 
Some strange stories about mocks.
Some strange stories about mocks.Some strange stories about mocks.
Some strange stories about mocks.
 
Business-friendly library for inter-service communication
Business-friendly library for inter-service communicationBusiness-friendly library for inter-service communication
Business-friendly library for inter-service communication
 
How i was a team leader once
How i was a team leader onceHow i was a team leader once
How i was a team leader once
 
Introduction to Rails by Evgeniy Hinyuk
Introduction to Rails by Evgeniy HinyukIntroduction to Rails by Evgeniy Hinyuk
Introduction to Rails by Evgeniy Hinyuk
 
Ruby OOP (in Ukrainian)
Ruby OOP (in Ukrainian)Ruby OOP (in Ukrainian)
Ruby OOP (in Ukrainian)
 
Testing in Ruby
Testing in RubyTesting in Ruby
Testing in Ruby
 
Ruby Summer Course by #pivorak & OnApp - OOP Basics in Ruby
Ruby Summer Course by #pivorak & OnApp - OOP Basics in RubyRuby Summer Course by #pivorak & OnApp - OOP Basics in Ruby
Ruby Summer Course by #pivorak & OnApp - OOP Basics in Ruby
 
The Saga Pattern: 2 years later by Robert Pankowecki
The Saga Pattern: 2 years later by Robert PankoweckiThe Saga Pattern: 2 years later by Robert Pankowecki
The Saga Pattern: 2 years later by Robert Pankowecki
 
Data and Bounded Contexts by Volodymyr Byno
Data and Bounded Contexts by Volodymyr BynoData and Bounded Contexts by Volodymyr Byno
Data and Bounded Contexts by Volodymyr Byno
 
Successful Remote Development by Alex Rozumii
Successful Remote Development by Alex RozumiiSuccessful Remote Development by Alex Rozumii
Successful Remote Development by Alex Rozumii
 
Origins of Elixir programming language
Origins of Elixir programming languageOrigins of Elixir programming language
Origins of Elixir programming language
 
Functional Immutable CSS
Functional Immutable CSS Functional Immutable CSS
Functional Immutable CSS
 
Multi language FBP with Flowex by Anton Mishchuk
Multi language FBP with Flowex by Anton Mishchuk Multi language FBP with Flowex by Anton Mishchuk
Multi language FBP with Flowex by Anton Mishchuk
 
Detective story of one clever user - Lightning Talk By Sergiy Kukunin
Detective story of one clever user - Lightning Talk By Sergiy KukuninDetective story of one clever user - Lightning Talk By Sergiy Kukunin
Detective story of one clever user - Lightning Talk By Sergiy Kukunin
 
CryptoParty: Introduction by Olexii Markovets
CryptoParty: Introduction by Olexii MarkovetsCryptoParty: Introduction by Olexii Markovets
CryptoParty: Introduction by Olexii Markovets
 
How to make first million by 30 (or not, but tryin') - by Marek Piasecki
How to make first million by 30 (or not, but tryin') - by Marek PiaseckiHow to make first million by 30 (or not, but tryin') - by Marek Piasecki
How to make first million by 30 (or not, but tryin') - by Marek Piasecki
 
GIS on Rails by Oleksandr Kychun
GIS on Rails by Oleksandr Kychun GIS on Rails by Oleksandr Kychun
GIS on Rails by Oleksandr Kychun
 
Unikernels - Keep It Simple to the Bare Metal
Unikernels - Keep It Simple to the Bare MetalUnikernels - Keep It Simple to the Bare Metal
Unikernels - Keep It Simple to the Bare Metal
 
HTML Canvas tips & tricks - Lightning Talk by Roman Rodych
 HTML Canvas tips & tricks - Lightning Talk by Roman Rodych HTML Canvas tips & tricks - Lightning Talk by Roman Rodych
HTML Canvas tips & tricks - Lightning Talk by Roman Rodych
 

Recently uploaded

OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
Fermin Galan
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
timtebeek1
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
Aftab Hussain
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
mz5nrf0n
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 

Recently uploaded (20)

OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 

Rails MVC by Sergiy Koshovyi

  • 2.
  • 4.
  • 5. ● Separation of business logic ● Reusing of code ● Separation of responsibility ● Flexible application BENEFITS
  • 6. ● Doesn’t have a strict implementation ● No one place for busines logic ● No one place for validations ● No one place for views PROPERTIES
  • 7. Rails MVC in the context of user
  • 8. MVC is an Architectural Pattern 8 My Banana Stuart, give me the banana Ostap, are you here? I’m coming put on a suit Farewell !!!
  • 9. Rails MVC in the context of components
  • 11. Rails MVC in the context of Rails libraries
  • 12. 12
  • 14. resource :profile, only: %i[show edit update], controller: :profile 14 RESOURCE
  • 15. 1 Rails.application.routes.draw do 2 root 'home#index' 3 4 resources :events, only: %i[index show] do 5 resources :visit_requests, only: %i[show create destroy] 6 end 15 RESOURCES
  • 16. CUSTOM ROUTES WITHIN RESOURCES 1 resources :orders do 2 collection do 3 post :search 4 end 5 member do 6 post :accept 7 post :reject 8 post :ship 9 get :despatch_note 10 end 11 end 16
  • 17. get '/:page_url', to: 'pages#show' authenticate :user, ->(u) { u.admin? } do namespace :admin do get '/', to: 'home#index' resources :accounts 17 CUSTOM ROUTES, NAMESPACE
  • 18. 1 # api 2 namespace :api, path: '/', constraints: { subdomain: 'api' }, defaults: { format: :json } do 3 namespace :v1 do 4 post 'sign_up' => 'registrations#create' 5 post 'sign_in' => 'sessions#create' 6 delete 'sign_out' => 'sessions#destroy' 7 end 8 end 18 NAMESPACES api_v1_sign_up POST /v1/sign_up(.:format) api/v1/registrations#create {:subdomain=>"api", :format=>:json} api_v1_sign_in POST /v1/sign_in(.:format) api/v1/sessions#create {:subdomain=>"api", :format=>:json} api_v1_sign_out DELETE /v1/sign_out(.:format) api/v1/sessions#destroy {:subdomain=>"api", :format=>:json}
  • 19. 1 # api 2 scope :api, constraints: { subdomain: 'api' }, module: :api, defaults: { format: :json }, as: :api do 3 scope '/v1', module: :v1, as: :v1 do 4 post 'sign_up' => 'registrations#create' 5 post 'sign_in' => 'sessions#create' 6 delete 'sign_out' => 'sessions#destroy' 7 end 8 end 19 SCOPES api_v1_sign_up POST /v1/sign_up(.:format) api/v1/registrations#create {:subdomain=>"api", :format=>:json} api_v1_sign_in POST /v1/sign_in(.:format) api/v1/sessions#create {:subdomain=>"api", :format=>:json} api_v1_sign_out DELETE /v1/sign_out(.:format) api/v1/sessions#destroy {:subdomain=>"api", :format=>:json}
  • 20. 20 Wait! Aren’t namespaces and scopes essentially the same?
  • 21. 1 # api 2 scope :api do 3 scope :v1 do 4 post 'sign_up' => 'registrations#create' 5 post 'sign_in' => 'sessions#create' 6 delete 'sign_out' => 'sessions#destroy' 7 end 8 end 21 SCOPES WITHOUT ANY OPTIONS sign_up POST /sign_up(.:format) registrations#create sign_in POST /sign_in(.:format) sessions#create sign_out DELETE /sign_out(.:format) sessions#destroy
  • 22. 22 NAMESPACE vs SCOPE Namespace Scope By default, adds the name of the namespace to the name of the path, prefixes actual request path, and expects the controller to belong to appropriately named module. No defaults. All options are explicit. A shortcut method when you need to quickly nest a set of routes and controllers under some name. A powerful, customizable method to apply defaults to a group of routes.
  • 23. 1 namespace :admin do 2 root "admin#index" 3 end 4 5 root "home#index" 23 MULTIPLE ROOT ROUTES
  • 24. 1 constraints(id: /[A-Z][A-Z][0-9]+/) do 2 resources :photos 3 resources :accounts 4 end 24 CONSTRAINTS
  • 26. 1 def create 2 @product = Product.new(safe_params) 3 if @product.save 4 redirect_to :products, flash: { notice: t('shopr.products.create_notice') } 5 else 6 render action: 'new' 7 end 8 end 9 10 def update 11 if @product.update(safe_params) 12 redirect_to [:edit, @product], flash: { notice: t('products.update_notice') } 13 else 14 render action: 'edit' 15 end 16 end 26 DEFAULT ACTIONS
  • 27. 1 class ApplicationController < ActionController::Base 2 protect_from_forgery with: :exception 3 before_action :auth, only: :admin 4 helper_method :admin?, :about_page, :contacts_page 6 delegate :admin?, to: :current_user, allow_nil: true 7 skip_authorization_check 8 skip_before_action :authenticate_user! 27 HELPERS, BEFORE ACTIONS, ...
  • 28. 1 def create 2 @protocol = Protocol.create(protocol_params) 3 end 4 5 private 6 7 def protocol_params 8 params.require(:protocol).permit( 9 :competition_id, 10 :first_name, 11 :last_name, 12 :total_result, 13 :place 14 ) 15 end 28 PERMITTED PARAMS
  • 29. 1 def create 2 @product = Product.new(safe_params) 3 if @product.save 4 redirect_to :products, flash: { notice: t('shopr.products.create_notice') } 5 else 6 render action: 'new' 7 end 8 end 29 REDIRECT VS RENDER
  • 30. render :edit render action: :edit render "edit" render "edit.html.erb" render action: "edit" render action: "edit.html.erb" render "books/edit" render "books/edit.html.erb" 30 RENDER render template: "books/edit" render template: "books/edit.html.erb" render "/path/to/rails/app/views/books/edit" render "/path/to/rails/app/views/books/edit.html.erb" render file: "/path/to/rails/app/views/books/edit" render file: "/path/to/rails/app/views/books/edit.html.erb"
  • 31. 1 def create 2 Shopr::Order.transaction do 3 @order = Shopr::Order.new(safe_params) 4 @order.status = 'confirming' 5 if safe_params[:customer_id] 6 @customer = Shopr::Customer.find safe_params[:customer_id] 7 @order.first_name = @customer.first_name 8 @order.last_name = @customer.last_name 9 @order.company = @customer.company 10 @order.email_address = @customer.email 11 @order.phone_number = @customer.phone 12 if @customer.addresses.billing.present? 13 billing = @customer.addresses.billing.first 14 @order.billing_address1 = billing.address1 15 @order.billing_address2 = billing.address2 16 @order.billing_address3 = billing.address3 17 @order.billing_address4 = billing.address4 18 @order.billing_postcode = billing.postcode 19 @order.billing_country_id = billing.country_id 31 FAT CONTROLLERS
  • 32. 1 class VisitRequestsController < ApplicationController 2 before_action :authenticate_user!, only: %i[create destroy] 3 4 def show 5 VisitRequest::FinalConfirmation.call(visit_request, params) 6 flash_success(visit_request.status) and default_redirect 7 end 8 9 def create 10 VisitRequest::Create.call(current_user, event) 11 flash_success and default_redirect 12 end 13 14 def destroy 15 visit_request.destroy 16 flash_success and default_redirect 17 end 32 THIN CONTROLLERS
  • 34. 1 class Goal < ApplicationRecord 2 has_many :donations, dependent: :destroy 3 4 validates :title, presence: true 5 validates :amount, presence: true, numericality: true 6 7 def achieved? 8 donations_total >= amount 9 end 10 11 def donations_total 12 donations.sum(:amount) 13 end 14 end 34 MODELS
  • 35. class Goal < ApplicationRecord has_many :donations, dependent: :destroy end class Donation < ApplicationRecord belongs_to :goal end 35 ONE TO MANY/ONE RELATIONS Goal id:integer title:string Donation id:integer goal_id:integer title:string ... ...
  • 36. 36 MANY TO MANY RELATIONS Goal id:integer title:string Donation id:integer title:string ... ... class Goal < ApplicationRecord has_and_belongs_to_many :donations end class Donation < ApplicationRecord has_and_belongs_to_many :goal end donations_goals goal_id:integer donation_id:integer
  • 37. 37 ASSOCIATION RELATIONS Goal id:integer title:string Donation id:integer goal_id:integer ... ... class Goal < ApplicationRecord has_many :donations has_many :users, through: :donations end class Donation < ApplicationRecord belongs_to :goal belongs_to :user end class User < ApplicationRecord has_many :donations end User id:integer email:string ... user_id:integer
  • 38. 38 POLYMORPHIC RELATIONS User id:integer email:string Company id:integer name:string ... ... Address id:integer address:string addressable_id:integer addressable_type:string class Address < ApplicationRecord belongs_to :addressable, polymorphic: true end class User < ApplicationRecord has_many :address, as: :assressable end class Company < ApplicationRecord has_many :address, as: :assressable end
  • 39. 1 class Goal < ApplicationRecord 2 validates :title, presence: true 3 end 4 5 goal = Goal.create(title: “Buying a motocycle”).valid? # => true 6 goal = Goal.create(title: nil).valid? # => false 7 goal.errors.messages # => {title:["can't be blank"]} 39 VALIDATES
  • 40. 1 class Goal < ApplicationRecord 2 validates_associated :donations #(only in one of related model) 3 validates_with GoalValidator #class GoalValidator < ActiveModel::Validator 4 validate :expiration_date_cannot_be_in_the_past 5 6 def expiration_date_cannot_be_in_the_past 7 if expiration_date.present? && expiration_date < Date.today 8 errors.add(:expiration_date, "can't be in the past") 9 end 10 end 11 end 40 VALIDATES
  • 42. 1 <h2> <%= t 'goals.singular'> </h1> 2 3 < div class="col-md-12" > 4 <%= goal.title > 5 < /div> 6 < div class="col-md-12" > 7 <%= goal.description > 8 < /div> 9 < div class="col-md-12" > 10 <%= "Amount to reach: #{goal.amount}" > 11 < /div> 12 < div class="col-md-12" > 13 <%= "Current sum: #{goal.donations_total}" > 14 < /div> 42 TEMPLATES
  • 43. 1 <h2> <%= t 'goals.singular'> </h1> 2 3 < div class="col-md-12" > 4 <%= goal.title > 5 < /div> 6 < div class="col-md-12" > 7 <%= goal.description > 8 < /div> 9 < div class="col-md-12" > 10 <%= "Amount to reach: #{goal.amount}" > 11 < /div> 12 < div class="col-md-12" > 13 <%= "Current sum: #{goal.donations_total}" > 14 < /div> 43 .html.erb (ERB - Embedded Ruby)
  • 44. 1 h2 = t 'goals.singular' 2 3 .col-md-12 4 = goal.title 5 .col-md-12 6 = goal.description 7 .col-md-12 8 = "Amount to reach: #{goal.amount}" 9 .col-md-12 10 = "Current sum: #{goal.donations_total}" 11 .col-md-12 12 - unless goal.achieved? 13 = render 'shared/donations/form', path: donate_goal_path(goal) 44 .html.slim
  • 45. 1 $('#notifications_list').html( 2 "<%= escape_javascript(render('notifications/list', notifications: @notifications)) %>" 3 ); 4 5 $('.container-fluid .flash-msg').html( 6 "<%= escape_javascript(render 'layouts/alerts') %>" 7 ); 8 9 $("#send-notification-modal").modal("hide"); 45 .js.erb
  • 46. 1 json.extract! ticket, :id, :uid, :manager_id, :customer_name, :customer_email, :title, :body, :status_id 2 json.url ticket_url(ticket, format: :json) 46 .json.jbuilder
  • 47. new.html.slim 1 = render 'shared/donations/form', path: donate_goal_path(goal) edit.html.slim 1 = render 'shared/donations/form', path: donate_goal_path(goal) 47 PARTIALS _form.html.slim = simple_form_for :credit_card, url: path do |f| .form-inputs .row .col-md-6 = f.input :number, as: :string = f.input :cvc, as: :string = f.input :exp_month, as: :string = f.input :exp_year, as: :string
  • 48. 1 <h1>Listing Books</h1> 2 <table> 3 <tr> 4 <th>Title</th> 5 <th>Summary</th> 6 <th></th> 7 <th></th> 8 <th></th> 9 </tr> 10 <% @books.each do |book| %> 11 <tr> 12 <td><%= book.title %></td> 13 <td><%= book.content %></td> 14 <td><%= link_to "Show", book %></td> 15 <td><%= link_to "Edit", edit_book_path(book) %></td> 16 <td><%= link_to "Remove", book, method: :delete, data: { confirm: "Are you sure?" } %></td> 17 </tr> 18 <% end %> 19 </table> 48 PARTIALS. MAGIC
  • 49. /views/books/index.html.erb 1 <h1>Listing Books</h1> 2 <table> 3 <tr> 4 <th>Title</th> 5 <th>Summary</th> 6 <th></th> 7 <th></th> 8 <th></th> 9 </tr> 10 <%= render @books %> 11 </table> 49 PARTIALS. MAGIC /views/books/_book.html.erb 1 <tr> 2 <td><%= book.title %></td> 3 <td><%= book.content %></td> 4 <td><%= link_to "Show", book %></td> 5 <td><%= link_to "Edit", edit_book_path(book) %></td> 16 <td><%= link_to "Remove", book, method: :delete, data: { confirm: "Are you sure?" } %></td> 17 </tr>
  • 51. class HomeController < ApplicationController def index render 'events/show' end end 51 LAYOUTS class TalksController < ApplicationController helper_method :talks, :talk, :tags private def talks scope = Talk.published.includes(:event).order('events.finished_at desc') @talks ||= params[:tag] ? scope.tagged_with(params[:tag]) : scope @talks.page(params[:page]).per(12) end end class PagesController < ApplicationController helper_method :page def show page ? render(:show) : not_found end private def page @page ||= Page.find_by(url: params[:page_url]) end end class AuthController < ActionController::Base layout "devise" end
  • 52. doctype html html head title = content_for?(:title) ? yield(:title) : t('default_title') = stylesheet_link_tag 'app/application' meta name="theme-color" content="#ffffff" == render 'layouts/ga/head' body class="#{yield(:main_body_class)}" = yield(:before_header) == render 'layouts/app/flash' == render 'layouts/app/header' main = yield 52 application.slim vs admin.slim doctype html html head title = content_for?(:title) ? yield(:title) : t('default_admin_title') = stylesheet_link_tag 'admin/application' meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" body .ui.sidebar.inverted.vertical.menu == render 'layouts/admin/navigation' .pusher .ui.container#container == render 'layouts/admin/header' = yield == render 'layouts/admin/footer'
  • 53. views/events/index.slim ... tbody - events.each do |event| tr th = event.id td = resource_link(event) td = format_timestamp(event.started_at) td = format_timestamp(event.finished_at) 53 HELPERS helpers/... module TalksHelper def talk_link(talk, text = "", options = {}) link_to text, polymorphic_path(talk), options end end module ApplicationHelper def format_timestamp(timestamp, time: true, delimiter: '-') return unless timestamp formatted_date = timestamp.strftime('%Y %b %d') formatted_time = timestamp.strftime('%H:%M') return formatted_date if !time "#{formatted_date} #{delimiter} #{formatted_time}" end
  • 54. ● Fat model and Skinny controller ● Business logic should always be in the model ● The view should have minimal code ● Use helpers! ● Use models ● DRY (Don't Repeat Yourself) 54 BEST PRACTICES