SlideShare una empresa de Scribd logo
1 de 70
Descargar para leer sin conexión
Web Development with

Ruby On Rails

Pedro Cunha
Ruby

Yukihiro "Matz" Matsumoto
       Ruby is designed for programmer
                    productivity and fun


                       Created February 1993
Ruby
Everything is an object     Dynamic Typing

 true.class # TrueClass   class Foo

 nil.class # NilClass       def initialize(x, y)

                              @x = x
                              @y = y
                            end
                          end

                          class Foo2
                          end

                          Foo.new(2, Foo2.new)
Ruby
class Foo                        class Bar
  # Parenthesis can be omitted     # Use ! if you change self
  def method                       def method!
    puts "Hello World"             end
  end
                                   # Use ? if you return a boolean
  # Default params                 def method?
  def method2(x = 2)               end
    puts x
  end                              # Only conventions
                                 end
  # Operator overload
  def +(x)
  end
end
Ruby
"hello".class # String
:hello.class # Symbol          a = "Hello"
                               b = "Hello"
# Convention
# Use string if you plan to    a.equal? b # false
compute text
                               x = :hello
# Use symbols if you want to   y = :hello
define or/and set a
behaviour which is not         x.equal? y # true
expected to change
Ruby
a = {}
a[:first] = 2
a[:things] = 3
a[:foo] = "bar"

b = {
        :first => 2,
        :things => 3,
        :foo => "bar"
}

b[:first] # 2
Ruby
x = [1,4,5,2,5,8,10]

x.sort # returns a copy of x sorted
[1,2,4,5,5,8,10]
x.sort! # modifies self

x.map{ |i| i + 4 } # [5,6,8,9,9,12,14]
x.map! do |i|
  i + 4
end # [5,6,8,9,9,12,14]
Ruby
             Monkey Patching

class String
  def +()
    # override string default + operator
  end
end




              “With great power comes great responsability”
                        Uncle Ben, Amazing Spiderman nº1
Ruby on Rails
Ruby on Rails
Created by David Heinemeir Hansson
• CEO at 37th Signals
• Personal Project, 2004
Present
• Rails 3.1
• Growing community
Ruby on Rails

Convention vs Configuration
MVC Architecture
REST routing
Convention
vs Configuration
• Don’t Repeat Yourself
• Increased productivity through
  conventions. Ex.: following a pattern for
  foreign key columns.

• Take advantage of singular and plural word
  meanings
MVC
RoR
REST
Representational State Transfer
CRUD      REST ROUTES

CREATE   POST /posts
READ     GET    /posts/1
UPDATE   PUT    /posts/1
DELETE   DELETE /posts/1
# routes.rb
Blog::Application.routes.draw do
  resources :posts
end
RoR
Starting development
pcunha:prompt$ rails new Blog -d mysql

Blog
 /app
       /controllers
       /mailers
       /models
       /views
 /config
       database.yml
 /db
       /migrate
 Gemfile
 /public
       /javascripts
       /stylesheets
# config/database.yml
development:
  adapter: sqlite3
  database: db/development.sqlite3

test:
  adapter: sqlite3
  database: db/test.sqlite3

production:
  adapter: sqlite3
  database: db/production.sqlite3
development:
  adapter: mysql2
  encoding: utf8
  database: Blog_development
  username: root
  password:

test:
  adapter: mysql2
  encoding: utf8
  database: Blog_test
  username: root
  password:

production:
  adapter: mysql2
  encoding: utf8
  database: Blog_production
  username: root
  password:              rails new with mysql option
pcunha:Blog$ rails server

=> Booting WEBrick
=> Rails 3.0.7 application starting in
development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
localhost:3000
Model
Database Schema
pcunha:Blog$ rails generate scaffold Post title:string body:text

     invoke   active_record
     create     db/migrate/20110715102126_create_posts.rb
     create     app/models/post.rb
     invoke     test_unit
     create       test/unit/post_test.rb
     create       test/fixtures/posts.yml
     invoke   scaffold_controller
     create     app/controllers/posts_controller.rb
     invoke     erb
     create       app/views/posts
     create       app/views/posts/index.html.erb
     create       app/views/posts/edit.html.erb
     create       app/views/posts/show.html.erb
     create       app/views/posts/new.html.erb
     create       app/views/posts/_form.html.erb
# config/db/migrate/20110715102126_create_posts.rb
class CreatePosts < ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.string :title
      t.text :body

      t.timestamps
    end
  end

  def self.down
    drop_table :posts
  end
end
pcunha:Blog$ rake db:create
pcunha:Blog$ rake db:migrate
==    CreatePosts: migrating
-- create_table(:posts)
     -> 0.0015s
==    CreatePosts: migrated (0.0018s)
pcunha:Blog$ rails generate model Comment body:text

 invoke   active_record
 create     db/migrate/20110715103725_create_comments.rb
 create     app/models/comment.rb
 invoke     test_unit
 create       test/unit/comment_test.rb
 create       test/fixtures/comments.yml

pcunha:Blog$ rails generate migration AddPostIdToComments
post_id:integer

 invoke   active_record
 create     db/migrate/20110715103834_add_post_id_to_comments.rb
# 20110715103834_add_post_id_to_comments.rb
class AddPostIdToComments < ActiveRecord::Migration
  def self.up
    add_column :comments, :post_id, :integer
  end

  def self.down
    remove_column :comments, :post_id
  end
end
pcunha:Blog$ rake db:migrate
==    CreateComments: migrating
-- create_table(:comments)
     -> 0.0011s
==    CreateComments: migrated (0.0012s)


==    AddPostIdToComments: migrating
-- add_column(:comments, :post_id, :integer)
     -> 0.0011s
==    AddPostIdToComments: migrated (0.0041s)
rake   db:create
rake   db:migrate
rake   db:migrate:redo
rake   db:rollback




blog_db.schema_migrations
- keeps the version number of all
migrations already runned
Model
 Relations
# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :comments
end


# app/models/comment.rb
class Comment < ActiveRecord::Base
  belongs_to :post
end


Post.all
Post.find(1).comments
Comments.find(1).post
Post.order(:created_at)
Post.limit(5).offset(2)
Model
 Validations
# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :comments

  validates_presence_of :title
  validates_format_of :title, :with => /ASLB.*z/
end



p = Post.new
p.save # false
p.errors.full_messages # ["Title can't be blank", "Title
is invalid"]

p.title = "SLB is the best"
p.save # true
validates_presence_of :nif

validates_format_of :name

validates_acceptance_of :terms_and_conditions, :on => :create

validates_numericality_of :age, :greater_than_or_equal_to => 18

validates_uniqueness_of :model_fk_key, :scope => :model_fk_key2

validates_length_of :minimum => 5
Controllers
  Managing the CRUD
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  # GET /posts
  def index ...

  # GET /posts/1
  def show ...

  # GET /posts/new
  def new ...

  # GET /posts/1/edit
  def edit ...

  # POST /posts
  def create ...

  # PUT /posts/1
  def update ...

  # DELETE /posts/1
  def destroy ...
end
                                    Generated with scaffold
# POST /posts
  # POST /posts.xml
  def create
    @post = Post.new(params[:post])

    respond_to do |format|
      if @post.save
        format.html { redirect_to(@post, :notice => 'Post was
successfully created.') }
        format.xml { render :xml => @post, :status
=> :created, :location => @post }
      else
        format.html { render :action => "new" }
        format.xml { render :xml => @post.errors, :status
=> :unprocessable_entity }
      end
    end
  end
def index
   @posts = Post.all

   respond_to do |format|
     format.html # index.html.erb
     format.xml { render :xml => @posts }
   end
 end

pcunha:Blog$ curl http://localhost:3000/posts.xml
<?xml version="1.0" encoding="UTF-8"?>
<posts type="array">
  <post>
    <created-at type="datetime">2011-07-15T13:39:51Z</created-at>
    <body>This is the body of the first post</body>
    <title>The first very post of this blog</title>
    <updated-at type="datetime">2011-07-15T13:39:51Z</updated-at>
    <id type="integer">1</id>
  </post>
</posts>
Views
# app/views/posts/new.html.erb
                                        <h1>New post</h1>

                                        <%= form_for(@post) do |f| %>
# app/controllers/posts_controller.rb
def new                                   <div class="field">
  @post = Post.new                          <%= f.label :title %><br />
  respond_to do |format|                    <%= f.text_field :title %>
    format.html # new.html.erb}           </div>
  end                                     <div class="field">
                                            <%= f.label :body %><br />
end
                                            <%= f.text_area :body %>
                                          </div>
                                          <div class="actions">
                                            <%= f.submit %>
                                          </div>
                                        <% end %>

                                        <%= link_to 'Back', posts_path %>
# app/views/posts/edit.html.erb
                                        <h1>Edit post</h1>

                                        <%= form_for(@post) do |f| %>

                                          <div class="field">
                                            <%= f.label :title %><br />
# app/controllers/posts_controller.rb
                                            <%= f.text_field :title %>
def edit                                  </div>
  @post = Post.find(params[:id])          <div class="field">
  respond_to do |format|                    <%= f.label :body %><br />
    format.html # edit.html.erb}            <%= f.text_area :body %>
  end                                     </div>
                                          <div class="actions">
end
                                            <%= f.submit %>
                                          </div>
                                        <% end %>

                                        <%= link_to 'Show', @post %> |
                                        <%= link_to 'Back', posts_path %>
Rails builds the route for you

link_to 'Show', @post   # GET posts/@post.id


form_for(@post)

if @post.new_record?
 POST /posts
else
 PUT /posts/@post.id
end
Views
 Partials
# app/views/posts/new.html.erb      # app/views/posts/edit.html.erb
<h1>New post</h1>                   <h1>Edit post</h1>

<%= form_for(@post) do |f| %>       <%= form_for(@post) do |f| %>

  <div class="field">                 <div class="field">
    <%= f.label :title %><br />         <%= f.label :title %><br />
    <%= f.text_field :title %>          <%= f.text_field :title %>
  </div>                              </div>
  <div class="field">                 <div class="field">
    <%= f.label :body %><br />          <%= f.label :body %><br />
    <%= f.text_area :body %>            <%= f.text_area :body %>
  </div>                              </div>
  <div class="actions">               <div class="actions">
    <%= f.submit %>                     <%= f.submit %>
  </div>                              </div>
<% end %>                           <% end %>

<%= link_to 'Back', posts_path %>   <%= link_to 'Show', @post %> |
                                    <%= link_to 'Back', posts_path %>


                           Bad pattern
# app/views/posts/_form.html.erb
# app/views/posts/new.html.erb
                                    <%= form_for(@post) do |f| %>
<h1>New post</h1>

                                      <div class="field">
<%= render "form" %>%>
                                        <%= f.label :title %><br />
<%= link_to 'Back', posts_path %>
                                        <%= f.text_field :title %>
                                      </div>
                                      <div class="field">
                                        <%= f.label :body %><br />
# app/views/posts/edit.html.erb
                                        <%= f.text_area :body %>
<h1>Edit post</h1>
                                      </div>
                                      <div class="actions">
<%= render "form" %>%>
                                        <%= f.submit %>
<%= link_to 'Show', @post %> |
                                      </div>
<%= link_to 'Back', posts_path %>
                                    <% end %>




                          The right way
AJAX
Improve user experience
Improve user experience by not having the
whole page reload when submitting a form
or simple pagination link

Also save resources used (SQL queries,
memory, more bandwidth usage,... etc)
AJAX
Changing default forms to AJAX
# config/routes.rb
Blog::Application.routes.draw do
  resources :posts do
    resources :comments, :only => [:create]
  end
end



POST /posts/:post_id/comments




              Limiting actions is always the best practice
# app/controllers/comments_controller.rb
class CommentsController < ApplicationController

  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.new(params[:comment])

    respond_to do |format|
      if @comment.save
        format.html { redirect_to(@post }
      else
        format.html { render :template => "posts/
show.html.erb" }
      end
    end
  end
end
# app/views/posts/show.html.erb
...
<h1>Comments</h1>
<div id="comments">
  <%= render :partial => "comments/comment",
             :collection => @post.commments %>
</div>

<%= render :partial => "comments/form",
           :locals => {
              :post => @post,
              :comment => @comment || Comment.new } %>
# app/views/comments/_form.html.erb
<%= form_for [post,comment] do |f| %>
  <div class="field">
    <%= f.label :body %><br />
    <%= f.text_area :body %>

    <p><%= f.submit %></p>
  </div>
<% end %>


            Our HTML form
          What needs to change?
# app/views/comments/_form.html.erb
<%= form_for [post,comment], :remote => true do |f| %>
  <div class="field">
    <%= f.label :body %><br />
    <%= f.text_area :body %>

    <p><%= f.submit %></p>
  </div>
<% end %>




                     That’s it? Not yet!
# app/controllers/comments_controller.rb
class CommentsController < ApplicationController

  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.new(params[:comment])

    respond_to do |format|
      if @comment.save
        format.html { redirect_to(@post, :notice => 'Comment was
successfully created.') }
        format.js
      else
        format.html { render :action => "new" }
        format.js
      end
    end
  end
end
# app/views/comments/create.js.erb
//Dump javascript here!
document.getElementById...



Notice:
- create.js.erb
- writing native javascript is not optimal:
    1. You will forget something about IE
    2. We are at 21st Century
    3. Lots of good frameworks
Rails 2.X and 3.0.X

- Prototype JS Framework as default

Rails 3.1 (released 2011)

- jQuery JS Framework as default
# app/views/comments/create.js.erb
<% if @comment.new_record? %>

  <% content = render(:partial => "comments/form",
                       :locals => {
                         :post => @post,
                         :comment => @comment })
     content = escape_javascript(content)
  %>

  $('new_comment').replace("<%= content %>");

<% else %>
  <% comment_content = render(:partial => "comments/comment", :object => @comment)
     comment_content = escape_javascript(comment_content)
  %>

  $('comments').insert({
     bottom : '<%= comment_content %>'
  })

  $('new_comment').reset();
<% end %>
Almost there... but

- Complex code
- We can do better with Rails
RJS
Ruby (to) JavaScript Templates
# app/views/comments/create.js.rjs
if @comment.new_record?
  page.replace :new_comment,
               :partial => "comments/form",
               :locals => {
                    :post => @post,
                    :comment => @comment }
else
  page.insert_html :bottom, :comments, :partial
=> "comments/comment", :object => @comment
  page[:new_comment].reset
end
Gems
Gems
Extend Rails framework

Easy installation and usage

Increasing community

 • Github
 • Gemcutter
Bundler gem
# Gemfile
gem "rails", "2.3.10"
gem "will_paginate"
gem "authlogic"

gem "pg"
gem "postgis_adapter", "0.7.8"
gem "GeoRuby", "1.3.4"

# Sphinx
gem "thinking-sphinx", "1.4.5"

group   :development do
  gem   "capistrano"
  gem   "capistrano-ext"
  gem   "ruby-debug"
  gem   "wirble"
  gem   "mongrel"
end
Questions ?
References

http://rubyonrails.org/
http://railsapi.com/
http://railscasts.com/
http://railsforzombies.org/
References
Thanks :)
pedro.cunha@rupeal.com
        @mryise

Más contenido relacionado

La actualidad más candente

Introdução Ruby On Rails
Introdução Ruby On RailsIntrodução Ruby On Rails
Introdução Ruby On Rails
Lukas Alexandre
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
旻琦 潘
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
Clinton Dreisbach
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
Nerd Tzanetopoulos
 
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
elliando dias
 

La actualidad más candente (20)

What to do when things go wrong
What to do when things go wrongWhat to do when things go wrong
What to do when things go wrong
 
Chef on Python and MongoDB
Chef on Python and MongoDBChef on Python and MongoDB
Chef on Python and MongoDB
 
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
 
Introdução Ruby On Rails
Introdução Ruby On RailsIntrodução Ruby On Rails
Introdução Ruby On Rails
 
Getting Into FLOW3 (DPC12)
Getting Into FLOW3 (DPC12)Getting Into FLOW3 (DPC12)
Getting Into FLOW3 (DPC12)
 
IPCSE12: Getting into FLOW3
IPCSE12: Getting into FLOW3IPCSE12: Getting into FLOW3
IPCSE12: Getting into FLOW3
 
Rails vs Web2py
Rails vs Web2pyRails vs Web2py
Rails vs Web2py
 
Rails for PHP Developers
Rails for PHP DevelopersRails for PHP Developers
Rails for PHP Developers
 
Vim Hacks
Vim HacksVim Hacks
Vim Hacks
 
RubyConf Portugal 2014 - Why ruby must go!
RubyConf Portugal 2014 - Why ruby must go!RubyConf Portugal 2014 - Why ruby must go!
RubyConf Portugal 2014 - Why ruby must go!
 
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
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
 
When To Use Ruby On Rails
When To Use Ruby On RailsWhen To Use Ruby On Rails
When To Use Ruby On Rails
 
Taking Care of The REST - Creating your own RESTful API Server using Restler 2.0
Taking Care of The REST - Creating your own RESTful API Server using Restler 2.0Taking Care of The REST - Creating your own RESTful API Server using Restler 2.0
Taking Care of The REST - Creating your own RESTful API Server using Restler 2.0
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
 
Custom post-framworks
Custom post-framworksCustom post-framworks
Custom post-framworks
 
Ruby On Rails Introduction
Ruby On Rails IntroductionRuby On Rails Introduction
Ruby On Rails Introduction
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
 
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
 
How to build the Web
How to build the WebHow to build the Web
How to build the Web
 

Destacado (7)

Dando os primeiros passos com rails
Dando os primeiros passos com railsDando os primeiros passos com rails
Dando os primeiros passos com rails
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
RubyonRails
RubyonRailsRubyonRails
RubyonRails
 
Creating Android apps
Creating Android appsCreating Android apps
Creating Android apps
 
What is-google-adwords
What is-google-adwordsWhat is-google-adwords
What is-google-adwords
 
Introdução ao Ruby on Rails
Introdução ao Ruby on RailsIntrodução ao Ruby on Rails
Introdução ao Ruby on Rails
 
BRANDING & PERSONAL SELLING
BRANDING & PERSONAL SELLINGBRANDING & PERSONAL SELLING
BRANDING & PERSONAL SELLING
 

Similar a Ruby on Rails at PROMPT ISEL '11

Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
Yehuda Katz
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
Yehuda Katz
 
Decent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivarsDecent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivars
Leonardo Soto
 
Simple restfull app_s
Simple restfull app_sSimple restfull app_s
Simple restfull app_s
netwix
 
浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編
Masakuni Kato
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
Yi-Ting Cheng
 
Presentation.Key
Presentation.KeyPresentation.Key
Presentation.Key
guesta2b31d
 

Similar a Ruby on Rails at PROMPT ISEL '11 (20)

Getting started with Rails (2), Season 2
Getting started with Rails (2), Season 2Getting started with Rails (2), Season 2
Getting started with Rails (2), Season 2
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Introduction à Ruby
Introduction à RubyIntroduction à Ruby
Introduction à Ruby
 
Ruby on Rails
Ruby on RailsRuby on Rails
Ruby on Rails
 
Pourquoi ruby et rails déchirent
Pourquoi ruby et rails déchirentPourquoi ruby et rails déchirent
Pourquoi ruby et rails déchirent
 
More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weibo
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Rails3ハンズオン資料
Rails3ハンズオン資料Rails3ハンズオン資料
Rails3ハンズオン資料
 
Why ruby
Why rubyWhy ruby
Why ruby
 
Decent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivarsDecent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivars
 
Simple restfull app_s
Simple restfull app_sSimple restfull app_s
Simple restfull app_s
 
浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編浜松Rails3道場 其の四 View編
浜松Rails3道場 其の四 View編
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Rails2 Pr
Rails2 PrRails2 Pr
Rails2 Pr
 
Como programar un blog REST
Como programar un blog RESTComo programar un blog REST
Como programar un blog REST
 
Php
PhpPhp
Php
 
Presentation.Key
Presentation.KeyPresentation.Key
Presentation.Key
 

Último

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 

Último (20)

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 

Ruby on Rails at PROMPT ISEL '11

  • 1. Web Development with Ruby On Rails Pedro Cunha
  • 2. Ruby Yukihiro "Matz" Matsumoto Ruby is designed for programmer productivity and fun Created February 1993
  • 3. Ruby Everything is an object Dynamic Typing true.class # TrueClass class Foo
 nil.class # NilClass def initialize(x, y)
 @x = x @y = y end end class Foo2 end Foo.new(2, Foo2.new)
  • 4. Ruby class Foo class Bar # Parenthesis can be omitted # Use ! if you change self def method def method! puts "Hello World" end end # Use ? if you return a boolean # Default params def method? def method2(x = 2) end puts x end # Only conventions end # Operator overload def +(x) end end
  • 5. Ruby "hello".class # String :hello.class # Symbol a = "Hello" b = "Hello" # Convention # Use string if you plan to a.equal? b # false compute text x = :hello # Use symbols if you want to y = :hello define or/and set a behaviour which is not x.equal? y # true expected to change
  • 6. Ruby a = {} a[:first] = 2 a[:things] = 3 a[:foo] = "bar" b = { :first => 2, :things => 3, :foo => "bar" } b[:first] # 2
  • 7. Ruby x = [1,4,5,2,5,8,10] x.sort # returns a copy of x sorted [1,2,4,5,5,8,10] x.sort! # modifies self x.map{ |i| i + 4 } # [5,6,8,9,9,12,14] x.map! do |i| i + 4 end # [5,6,8,9,9,12,14]
  • 8. Ruby Monkey Patching class String def +() # override string default + operator end end “With great power comes great responsability” Uncle Ben, Amazing Spiderman nº1
  • 10. Ruby on Rails Created by David Heinemeir Hansson • CEO at 37th Signals • Personal Project, 2004 Present • Rails 3.1 • Growing community
  • 11. Ruby on Rails Convention vs Configuration MVC Architecture REST routing
  • 13. • Don’t Repeat Yourself • Increased productivity through conventions. Ex.: following a pattern for foreign key columns. • Take advantage of singular and plural word meanings
  • 14. MVC
  • 15. RoR
  • 17. CRUD REST ROUTES CREATE POST /posts READ GET /posts/1 UPDATE PUT /posts/1 DELETE DELETE /posts/1
  • 20. pcunha:prompt$ rails new Blog -d mysql Blog /app /controllers /mailers /models /views /config database.yml /db /migrate Gemfile /public /javascripts /stylesheets
  • 21. # config/database.yml development: adapter: sqlite3 database: db/development.sqlite3 test: adapter: sqlite3 database: db/test.sqlite3 production: adapter: sqlite3 database: db/production.sqlite3
  • 22. development: adapter: mysql2 encoding: utf8 database: Blog_development username: root password: test: adapter: mysql2 encoding: utf8 database: Blog_test username: root password: production: adapter: mysql2 encoding: utf8 database: Blog_production username: root password: rails new with mysql option
  • 23. pcunha:Blog$ rails server => Booting WEBrick => Rails 3.0.7 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server
  • 26. pcunha:Blog$ rails generate scaffold Post title:string body:text invoke active_record create db/migrate/20110715102126_create_posts.rb create app/models/post.rb invoke test_unit create test/unit/post_test.rb create test/fixtures/posts.yml invoke scaffold_controller create app/controllers/posts_controller.rb invoke erb create app/views/posts create app/views/posts/index.html.erb create app/views/posts/edit.html.erb create app/views/posts/show.html.erb create app/views/posts/new.html.erb create app/views/posts/_form.html.erb
  • 27. # config/db/migrate/20110715102126_create_posts.rb class CreatePosts < ActiveRecord::Migration def self.up create_table :posts do |t| t.string :title t.text :body t.timestamps end end def self.down drop_table :posts end end
  • 28. pcunha:Blog$ rake db:create pcunha:Blog$ rake db:migrate == CreatePosts: migrating -- create_table(:posts) -> 0.0015s == CreatePosts: migrated (0.0018s)
  • 29. pcunha:Blog$ rails generate model Comment body:text invoke active_record create db/migrate/20110715103725_create_comments.rb create app/models/comment.rb invoke test_unit create test/unit/comment_test.rb create test/fixtures/comments.yml pcunha:Blog$ rails generate migration AddPostIdToComments post_id:integer invoke active_record create db/migrate/20110715103834_add_post_id_to_comments.rb
  • 30. # 20110715103834_add_post_id_to_comments.rb class AddPostIdToComments < ActiveRecord::Migration def self.up add_column :comments, :post_id, :integer end def self.down remove_column :comments, :post_id end end
  • 31. pcunha:Blog$ rake db:migrate == CreateComments: migrating -- create_table(:comments) -> 0.0011s == CreateComments: migrated (0.0012s) == AddPostIdToComments: migrating -- add_column(:comments, :post_id, :integer) -> 0.0011s == AddPostIdToComments: migrated (0.0041s)
  • 32. rake db:create rake db:migrate rake db:migrate:redo rake db:rollback blog_db.schema_migrations - keeps the version number of all migrations already runned
  • 34. # app/models/post.rb class Post < ActiveRecord::Base has_many :comments end # app/models/comment.rb class Comment < ActiveRecord::Base belongs_to :post end Post.all Post.find(1).comments Comments.find(1).post Post.order(:created_at) Post.limit(5).offset(2)
  • 36. # app/models/post.rb class Post < ActiveRecord::Base has_many :comments validates_presence_of :title validates_format_of :title, :with => /ASLB.*z/ end p = Post.new p.save # false p.errors.full_messages # ["Title can't be blank", "Title is invalid"] p.title = "SLB is the best" p.save # true
  • 37. validates_presence_of :nif validates_format_of :name validates_acceptance_of :terms_and_conditions, :on => :create validates_numericality_of :age, :greater_than_or_equal_to => 18 validates_uniqueness_of :model_fk_key, :scope => :model_fk_key2 validates_length_of :minimum => 5
  • 39. # app/controllers/posts_controller.rb class PostsController < ApplicationController # GET /posts def index ... # GET /posts/1 def show ... # GET /posts/new def new ... # GET /posts/1/edit def edit ... # POST /posts def create ... # PUT /posts/1 def update ... # DELETE /posts/1 def destroy ... end Generated with scaffold
  • 40. # POST /posts # POST /posts.xml def create @post = Post.new(params[:post]) respond_to do |format| if @post.save format.html { redirect_to(@post, :notice => 'Post was successfully created.') } format.xml { render :xml => @post, :status => :created, :location => @post } else format.html { render :action => "new" } format.xml { render :xml => @post.errors, :status => :unprocessable_entity } end end end
  • 41. def index @posts = Post.all respond_to do |format| format.html # index.html.erb format.xml { render :xml => @posts } end end pcunha:Blog$ curl http://localhost:3000/posts.xml <?xml version="1.0" encoding="UTF-8"?> <posts type="array"> <post> <created-at type="datetime">2011-07-15T13:39:51Z</created-at> <body>This is the body of the first post</body> <title>The first very post of this blog</title> <updated-at type="datetime">2011-07-15T13:39:51Z</updated-at> <id type="integer">1</id> </post> </posts>
  • 42. Views
  • 43. # app/views/posts/new.html.erb <h1>New post</h1> <%= form_for(@post) do |f| %> # app/controllers/posts_controller.rb def new <div class="field"> @post = Post.new <%= f.label :title %><br /> respond_to do |format| <%= f.text_field :title %> format.html # new.html.erb} </div> end <div class="field"> <%= f.label :body %><br /> end <%= f.text_area :body %> </div> <div class="actions"> <%= f.submit %> </div> <% end %> <%= link_to 'Back', posts_path %>
  • 44. # app/views/posts/edit.html.erb <h1>Edit post</h1> <%= form_for(@post) do |f| %> <div class="field"> <%= f.label :title %><br /> # app/controllers/posts_controller.rb <%= f.text_field :title %> def edit </div> @post = Post.find(params[:id]) <div class="field"> respond_to do |format| <%= f.label :body %><br /> format.html # edit.html.erb} <%= f.text_area :body %> end </div> <div class="actions"> end <%= f.submit %> </div> <% end %> <%= link_to 'Show', @post %> | <%= link_to 'Back', posts_path %>
  • 45. Rails builds the route for you link_to 'Show', @post # GET posts/@post.id form_for(@post) if @post.new_record? POST /posts else PUT /posts/@post.id end
  • 47. # app/views/posts/new.html.erb # app/views/posts/edit.html.erb <h1>New post</h1> <h1>Edit post</h1> <%= form_for(@post) do |f| %> <%= form_for(@post) do |f| %> <div class="field"> <div class="field"> <%= f.label :title %><br /> <%= f.label :title %><br /> <%= f.text_field :title %> <%= f.text_field :title %> </div> </div> <div class="field"> <div class="field"> <%= f.label :body %><br /> <%= f.label :body %><br /> <%= f.text_area :body %> <%= f.text_area :body %> </div> </div> <div class="actions"> <div class="actions"> <%= f.submit %> <%= f.submit %> </div> </div> <% end %> <% end %> <%= link_to 'Back', posts_path %> <%= link_to 'Show', @post %> | <%= link_to 'Back', posts_path %> Bad pattern
  • 48. # app/views/posts/_form.html.erb # app/views/posts/new.html.erb <%= form_for(@post) do |f| %> <h1>New post</h1> <div class="field"> <%= render "form" %>%> <%= f.label :title %><br /> <%= link_to 'Back', posts_path %> <%= f.text_field :title %> </div> <div class="field"> <%= f.label :body %><br /> # app/views/posts/edit.html.erb <%= f.text_area :body %> <h1>Edit post</h1> </div> <div class="actions"> <%= render "form" %>%> <%= f.submit %> <%= link_to 'Show', @post %> | </div> <%= link_to 'Back', posts_path %> <% end %> The right way
  • 50. Improve user experience by not having the whole page reload when submitting a form or simple pagination link Also save resources used (SQL queries, memory, more bandwidth usage,... etc)
  • 52. # config/routes.rb Blog::Application.routes.draw do resources :posts do resources :comments, :only => [:create] end end POST /posts/:post_id/comments Limiting actions is always the best practice
  • 53. # app/controllers/comments_controller.rb class CommentsController < ApplicationController def create @post = Post.find(params[:post_id]) @comment = @post.comments.new(params[:comment]) respond_to do |format| if @comment.save format.html { redirect_to(@post } else format.html { render :template => "posts/ show.html.erb" } end end end end
  • 54. # app/views/posts/show.html.erb ... <h1>Comments</h1> <div id="comments"> <%= render :partial => "comments/comment", :collection => @post.commments %> </div> <%= render :partial => "comments/form", :locals => { :post => @post, :comment => @comment || Comment.new } %>
  • 55. # app/views/comments/_form.html.erb <%= form_for [post,comment] do |f| %> <div class="field"> <%= f.label :body %><br /> <%= f.text_area :body %> <p><%= f.submit %></p> </div> <% end %> Our HTML form What needs to change?
  • 56. # app/views/comments/_form.html.erb <%= form_for [post,comment], :remote => true do |f| %> <div class="field"> <%= f.label :body %><br /> <%= f.text_area :body %> <p><%= f.submit %></p> </div> <% end %> That’s it? Not yet!
  • 57. # app/controllers/comments_controller.rb class CommentsController < ApplicationController def create @post = Post.find(params[:post_id]) @comment = @post.comments.new(params[:comment]) respond_to do |format| if @comment.save format.html { redirect_to(@post, :notice => 'Comment was successfully created.') } format.js else format.html { render :action => "new" } format.js end end end end
  • 58. # app/views/comments/create.js.erb //Dump javascript here! document.getElementById... Notice: - create.js.erb - writing native javascript is not optimal: 1. You will forget something about IE 2. We are at 21st Century 3. Lots of good frameworks
  • 59. Rails 2.X and 3.0.X - Prototype JS Framework as default Rails 3.1 (released 2011) - jQuery JS Framework as default
  • 60. # app/views/comments/create.js.erb <% if @comment.new_record? %> <% content = render(:partial => "comments/form", :locals => { :post => @post, :comment => @comment }) content = escape_javascript(content) %> $('new_comment').replace("<%= content %>"); <% else %> <% comment_content = render(:partial => "comments/comment", :object => @comment) comment_content = escape_javascript(comment_content) %> $('comments').insert({ bottom : '<%= comment_content %>' }) $('new_comment').reset(); <% end %>
  • 61. Almost there... but - Complex code - We can do better with Rails
  • 63. # app/views/comments/create.js.rjs if @comment.new_record? page.replace :new_comment, :partial => "comments/form", :locals => { :post => @post, :comment => @comment } else page.insert_html :bottom, :comments, :partial => "comments/comment", :object => @comment page[:new_comment].reset end
  • 64. Gems
  • 65. Gems Extend Rails framework Easy installation and usage Increasing community • Github • Gemcutter
  • 66. Bundler gem # Gemfile gem "rails", "2.3.10" gem "will_paginate" gem "authlogic" gem "pg" gem "postgis_adapter", "0.7.8" gem "GeoRuby", "1.3.4" # Sphinx gem "thinking-sphinx", "1.4.5" group :development do gem "capistrano" gem "capistrano-ext" gem "ruby-debug" gem "wirble" gem "mongrel" end