SlideShare a Scribd company logo
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

More Related Content

PDF
O que vem por aí com Rails 3
PDF
PDF
Symfony 4 & Flex news
PDF
Symfony internals [english]
PDF
Create a Symfony Application from a Drupal Perspective
PDF
Hands-on with the Symfony2 Framework
PDF
Rails for zombies_2_cheatsheets
PDF
REST in practice with Symfony2
O que vem por aí com Rails 3
Symfony 4 & Flex news
Symfony internals [english]
Create a Symfony Application from a Drupal Perspective
Hands-on with the Symfony2 Framework
Rails for zombies_2_cheatsheets
REST in practice with Symfony2

What's hot (20)

PDF
What to do when things go wrong
PDF
Chef on Python and MongoDB
PPTX
Service approach for development REST API in Symfony2
PDF
Introdução Ruby On Rails
PDF
Getting Into FLOW3 (DPC12)
PDF
IPCSE12: Getting into FLOW3
PDF
Rails vs Web2py
KEY
Rails for PHP Developers
PDF
Vim Hacks
PDF
RubyConf Portugal 2014 - Why ruby must go!
PDF
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
KEY
A tour on ruby and friends
PDF
When To Use Ruby On Rails
PDF
Taking Care of The REST - Creating your own RESTful API Server using Restler 2.0
PDF
Migrating Legacy Rails Apps to Rails 3
PPTX
Custom post-framworks
PDF
Ruby On Rails Introduction
PPTX
Symfony2 Introduction Presentation
PDF
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
PDF
How to build the Web
What to do when things go wrong
Chef on Python and MongoDB
Service approach for development REST API in Symfony2
Introdução Ruby On Rails
Getting Into FLOW3 (DPC12)
IPCSE12: Getting into FLOW3
Rails vs Web2py
Rails for PHP Developers
Vim Hacks
RubyConf Portugal 2014 - Why ruby must go!
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
A tour on ruby and friends
When To Use Ruby On Rails
Taking Care of The REST - Creating your own RESTful API Server using Restler 2.0
Migrating Legacy Rails Apps to Rails 3
Custom post-framworks
Ruby On Rails Introduction
Symfony2 Introduction Presentation
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
How to build the Web
Ad

Viewers also liked (7)

PDF
Dando os primeiros passos com rails
PDF
Ruby On Rails
PPT
RubyonRails
PDF
Creating Android apps
PDF
What is-google-adwords
PDF
Introdução ao Ruby on Rails
PDF
BRANDING & PERSONAL SELLING
Dando os primeiros passos com rails
Ruby On Rails
RubyonRails
Creating Android apps
What is-google-adwords
Introdução ao Ruby on Rails
BRANDING & PERSONAL SELLING
Ad

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

KEY
Getting started with Rails (2), Season 2
KEY
Rails3ハンズオン資料
PDF
Rails 3 Beautiful Code
KEY
Rails by example
PDF
Be happy with Ruby on Rails - CEUNSP Itu
PDF
Ruby on Rails - Introduction
PDF
Rails 3: Dashing to the Finish
ZIP
Rails 3 (beta) Roundup
ZIP
Barcamp Auckland Rails3 presentation
PDF
Rails 3 overview
KEY
Rails Presentation (Anton Dmitriyev)
PDF
Rails workshop for Java people (September 2015)
PDF
Ruby on Rails
KEY
Desarrollando aplicaciones web en minutos
PDF
Rails2 Pr
PDF
Ruby On Rails
PDF
Connecting the Worlds of Java and Ruby with JRuby
KEY
Getting started with Rails (3), Season 2
PDF
浜松Rails3道場 其の四 View編
PDF
Ruby On Rails Starter Kit
Getting started with Rails (2), Season 2
Rails3ハンズオン資料
Rails 3 Beautiful Code
Rails by example
Be happy with Ruby on Rails - CEUNSP Itu
Ruby on Rails - Introduction
Rails 3: Dashing to the Finish
Rails 3 (beta) Roundup
Barcamp Auckland Rails3 presentation
Rails 3 overview
Rails Presentation (Anton Dmitriyev)
Rails workshop for Java people (September 2015)
Ruby on Rails
Desarrollando aplicaciones web en minutos
Rails2 Pr
Ruby On Rails
Connecting the Worlds of Java and Ruby with JRuby
Getting started with Rails (3), Season 2
浜松Rails3道場 其の四 View編
Ruby On Rails Starter Kit

Recently uploaded (20)

PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Electronic commerce courselecture one. Pdf
PPTX
Cloud computing and distributed systems.
PDF
Encapsulation theory and applications.pdf
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Empathic Computing: Creating Shared Understanding
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
Spectroscopy.pptx food analysis technology
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
gpt5_lecture_notes_comprehensive_20250812015547.pdf
NewMind AI Weekly Chronicles - August'25-Week II
Electronic commerce courselecture one. Pdf
Cloud computing and distributed systems.
Encapsulation theory and applications.pdf
Programs and apps: productivity, graphics, security and other tools
The Rise and Fall of 3GPP – Time for a Sabbatical?
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Empathic Computing: Creating Shared Understanding
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Unlocking AI with Model Context Protocol (MCP)
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Agricultural_Statistics_at_a_Glance_2022_0.pdf
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Assigned Numbers - 2025 - Bluetooth® Document
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
MIND Revenue Release Quarter 2 2025 Press Release
20250228 LYD VKU AI Blended-Learning.pptx
Spectroscopy.pptx food analysis technology
Advanced methodologies resolving dimensionality complications for autism neur...

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