SlideShare a Scribd company logo
Ruby on Rails
   Supinfo 2011
A propos

• Martin Catty, fondateur de Synbioz
• Rubyiste depuis 2006

    _fuse       mcatty@synbioz.com
Ruby avant Rails

• Ne partez pas sans vos bagages !
• Rails a aidé à l’essor de Ruby
• Mais pas de framework sans langage
Ruby
     On ne va pas (ou peu) parler de:

        I/O        Test
                                     VM
                          Thread
Implémentations
                  Debugger         Garbage
   Proc / lambda            Exceptions
              Réseau
L’Histoire


• Créé par Yukihiro Matsumoto (Matz)
• Release publique en 2005
Un langage

• Plus objet que python
• Plus puissant que perl
• Fun
Les versions

• Stable actuelle: 1.9.2
• 1.8.7 dans la branche 1.8
• 1.8.7 (p250) fonctionne avec Rails 2 et 3
• < 1.8.7 = Rails 2
• > 1.8.7 = Rails 3
Le fameux hello world
  Java          Ruby
Le fameux hello world
                Java                           Ruby


class Hello {
   public static void main(String [] args) {
         system.out.println(‘Hello’);
      }
}
Le fameux hello world
                Java                                          Ruby


class Hello {
   public static void main(String [] args) {
         system.out.println(‘Hello’);          puts ‘Hello’
      }
}
Le fameux hello world
                Java                                          Ruby


class Hello {
   public static void main(String [] args) {
         system.out.println(‘Hello’);          puts ‘Hello’
      }
}




                                       </troll>
Tout est objet
Tout est objet
  2.times { puts "Bonjour Supinfo." }

=> Bonjour Supinfo
=> Bonjour Supinfo
Tout est objet
  2.times { puts "Bonjour Supinfo." }     3.upto(5) { |i| puts i }

=> Bonjour Supinfo                      => 3
=> Bonjour Supinfo                      => 4
                                        => 5
Tout est objet
  2.times { puts "Bonjour Supinfo." }     3.upto(5) { |i| puts i }

=> Bonjour Supinfo                      => 3
=> Bonjour Supinfo                      => 4
                                        => 5


  p 1.zero?


=> false
Tout est objet
  2.times { puts "Bonjour Supinfo." }     3.upto(5) { |i| puts i }

=> Bonjour Supinfo                      => 3
=> Bonjour Supinfo                      => 4
                                        => 5


  p 1.zero?                               39 + 3


=> false                                => 39.+(3)
Les variables
class A
   MAX = 42
                           A.new("a")
   @@instances = 0         A.new("b")
   def initialize(name)
      @name = name         A.new("c")
      @@instances += 1
   end                     A.new("d")
  def self.instances
                           A.new("e")
     @@instances
  end
end                        p A.instances #=> 5
Itérations
Itérations
a = 1..9
for i in a
   puts i
end
Itérations
 a = 1..9
 for i in a
    puts i
 end
=> 1…9
Itérations
 a = 1..9
 for i in a
    puts i        ou
 end
=> 1…9
Itérations
 a = 1..9
 for i in a            a = 1..9
    puts i        ou   a.each { |i| puts i }
 end
=> 1…9
Itérations
 a = 1..9
 for i in a             a = 1..9
    puts i        ou    a.each { |i| puts i }
 end
=> 1…9                 => 1…9
Itérations
 a = 1..9
 for i in a                     a = 1..9
    puts i                ou    a.each { |i| puts i }
 end
=> 1…9                         => 1…9

 i=0
 loop do
   i += 1
   puts i
   break if 10 == i
 end
Itérations
 a = 1..9
 for i in a                     a = 1..9
    puts i                ou    a.each { |i| puts i }
 end
=> 1…9                         => 1…9

 i=0
 loop do
   i += 1
   puts i
   break if 10 == i
 end

=> 1…9
Itérations
 a = 1..9
 for i in a                     a = 1..9
    puts i                ou    a.each { |i| puts i }
 end
=> 1…9                         => 1…9

 i=0
 loop do
   i += 1                      1.upto(10) do |i|
   puts i                       next if i.odd? # pas d'impair en ruby
   break if 10 == i             puts i
 end                           end

=> 1…9
Itérations
 a = 1..9
 for i in a                        a = 1..9
    puts i                ou       a.each { |i| puts i }
 end
=> 1…9                          => 1…9

 i=0
 loop do
   i += 1                        1.upto(10) do |i|
   puts i                         next if i.odd? # pas d'impair en ruby
   break if 10 == i               puts i
 end                             end

=> 1…9                         => 2, 4, 6, 8, 10
Itérations
 a = 1..9
 for i in a                        a = 1..9
    puts i                ou       a.each { |i| puts i }
 end
=> 1…9                          => 1…9

 i=0
 loop do
   i += 1                        1.upto(10) do |i|
   puts i                         next if i.odd? # pas d'impair en ruby
   break if 10 == i               puts i
 end                             end

=> 1…9                         => 2, 4, 6, 8, 10

 1.upto(2) do |i|
   v = rand(2)
   retry if v.zero?
 end
Conditions
Conditions
if index == 1
else            puts ‘0’ if index.zero?   puts ‘not 0’ unless index.zero?
end
Conditions
if index == 1
else                       puts ‘0’ if index.zero?     puts ‘not 0’ unless index.zero?
end


def what_is_it?(a)
 case a                                              what_is_it?(1)
 when 1..2                                           # 1 or 2
  puts "1 or 2"                                      what_is_it?(2)
 when 3                                              # 1 or 2
  puts "3"                                           what_is_it?(3)
 when /4.*/ # Regexp                                 #3
  puts "something starting with 4."                  what_is_it?("4004")
 when "foo"                                          # something starting with 4.
  puts "foo"                                         what_is_it?("foo")
 else                                                # foo
  puts "I don't know."                               what_is_it?(5)
 end                                                 # Don't know.
end
Tableaux 1/2
1
Tableaux 1/2
1   lost = [8, 15, 16, 23]
    lost << 42 # push
    lost.unshift(4)
    # [4, 8, 15, 16, 23, 42]
Tableaux 1/2
1   lost = [8, 15, 16, 23]
    lost << 42 # push
    lost.unshift(4)
    # [4, 8, 15, 16, 23, 42]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]
    # [4, 8, 15, 16, 23, 42]      # 42
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]
    # [4, 8, 15, 16, 23, 42]      # 42
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)   lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]     # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42         nil, nil]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)   lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]     # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42         nil, nil]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)   lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]     # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42         nil, nil]



                                               lost.compact!

                                               # [4, 8, 15, 16, 23, 42]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)   lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]     # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42         nil, nil]



                                               lost.compact!

                                               # [4, 8, 15, 16, 23, 42]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)                 lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]                   # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42                       nil, nil]


                                  lost << [4, 8]
                                                             lost.compact!
                                  # [4, 8, 15, 16, 23, 42,
                                                             # [4, 8, 15, 16, 23, 42]
                                  [4, 8]]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)                 lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]                   # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42                       nil, nil]


                                  lost << [4, 8]
                                                             lost.compact!
                                  # [4, 8, 15, 16, 23, 42,
                                                             # [4, 8, 15, 16, 23, 42]
                                  [4, 8]]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)                 lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]                   # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42                       nil, nil]



    lost.flatten!.uniq!            lost << [4, 8]
                                                             lost.compact!

    # [4, 8, 15, 16, 23, 42]      # [4, 8, 15, 16, 23, 42,
                                                             # [4, 8, 15, 16, 23, 42]
                                  [4, 8]]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)                 lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]                   # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42                       nil, nil]



    lost.flatten!.uniq!            lost << [4, 8]
                                                             lost.compact!

    # [4, 8, 15, 16, 23, 42]      # [4, 8, 15, 16, 23, 42,
                                                             # [4, 8, 15, 16, 23, 42]
                                  [4, 8]]



    lost.index(23)

    #4
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)                  lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]                    # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42                        nil, nil]



    lost.flatten!.uniq!            lost << [4, 8]
                                                              lost.compact!

    # [4, 8, 15, 16, 23, 42]      # [4, 8, 15, 16, 23, 42,
                                                              # [4, 8, 15, 16, 23, 42]
                                  [4, 8]]


                                  lost.shuffle
    lost.index(23)
                                  # [16, 23, 42, 4, 15, 8]
                                  [5, 3, 7, 39, 1, 15].sort
    #4
                                  # [1, 3, 5, 7, 15, 39]
Tableaux 1/2
1   lost = [8, 15, 16, 23]        lost.at(0)                  lost << nil << nil
    lost << 42 # push             #4
    lost.unshift(4)               lost[-1]                    # [4, 8, 15, 16, 23, 42,
    # [4, 8, 15, 16, 23, 42]      # 42                        nil, nil]



    lost.flatten!.uniq!            lost << [4, 8]
                                                              lost.compact!

    # [4, 8, 15, 16, 23, 42]      # [4, 8, 15, 16, 23, 42,
                                                              # [4, 8, 15, 16, 23, 42]
                                  [4, 8]]


                                  lost.shuffle
    lost.index(23)
                                  # [16, 23, 42, 4, 15, 8]    ('a'..'z').to_a
                                  [5, 3, 7, 39, 1, 15].sort   ["a", "b", "c", "d"…]
    #4
                                  # [1, 3, 5, 7, 15, 39]
Tableaux 2/2
Tableaux 2/2
double_lost = lost.map { |v| v * 2 }
# => [8, 16, 30, 32, 46, 84]
Tableaux 2/2
                                       # lost: [4, 8, 15, 16, 23, 42]
double_lost = lost.map { |v| v * 2 }
                                       double_lost - lost
# => [8, 16, 30, 32, 46, 84]
                                       # => [30, 32, 46, 84]
Tableaux 2/2
                                       # lost: [4, 8, 15, 16, 23, 42]
double_lost = lost.map { |v| v * 2 }
                                       double_lost - lost
# => [8, 16, 30, 32, 46, 84]
                                       # => [30, 32, 46, 84]




# intersection
double_lost & lost
# [8, 16]
Tableaux 2/2
                                       # lost: [4, 8, 15, 16, 23, 42]
double_lost = lost.map { |v| v * 2 }
                                       double_lost - lost
# => [8, 16, 30, 32, 46, 84]
                                       # => [30, 32, 46, 84]




# intersection                         # jointure
double_lost & lost                     (double_lost | lost).sort
# [8, 16]                              # [4, 8, 15, 16, 23, 30, 32, 42, 46, 84]
String
String
str = "bar"
puts 'foo #{str}'
# => foo #{str}
String
str = "bar"         # Interpolation
puts 'foo #{str}'   puts "foo #{str}"
# => foo #{str}     # => foo bar
String
str = "bar"         # Interpolation
puts 'foo #{str}'   puts "foo #{str}"
# => foo #{str}     # => foo bar



str = "a"
str.succ
# => "b"
String
str = "bar"         # Interpolation
puts 'foo #{str}'   puts "foo #{str}"
# => foo #{str}     # => foo bar



str = "a"           str = "foon"
str.succ            str.chomp
# => "b"            # => "foo"
String
str = "bar"         # Interpolation
puts 'foo #{str}'   puts "foo #{str}"
# => foo #{str}     # => foo bar



str = "a"           str = "foon"
str.succ            str.chomp
# => "b"            # => "foo"



str = "foo"
str.chop
# => "fo"
String
str = "bar"         # Interpolation
puts 'foo #{str}'   puts "foo #{str}"
# => foo #{str}     # => foo bar



str = "a"           str = "foon"
str.succ            str.chomp
# => "b"            # => "foo"



                    "supinfo".capitalize
str = "foo"
                    # => "Supinfo"
str.chop
                    "supinfo".upcase
# => "fo"
                    # => "SUPINFO"
String
str = "bar"         # Interpolation
puts 'foo #{str}'   puts "foo #{str}"
                                           # attention, en 1.8
# => foo #{str}     # => foo bar
                                           str = "éhé"
                                           str.size
                                           # => 5 et non 3
                                           str[0]
str = "a"           str = "foon"
                                           # 195 et non é (code ascii)
str.succ            str.chomp
# => "b"            # => "foo"
                                           # patché dans rails
                                           str.mb_chars[0]
                                           #é
                    "supinfo".capitalize   str.mb_chars.size
str = "foo"                                #3
                    # => "Supinfo"
str.chop
                    "supinfo".upcase
# => "fo"
                    # => "SUPINFO"
Hash
Association clé / valeur
Hash
Association clé / valeur
 h = { :a => 'a', :b => 42, :c => { :d => 'f' } }   h2 = { :a => 'foo' }
                                                    h.merge(h2)
                                                    => {:a=>"foo", :b=>42, :c=>{:d=>"f"}}
Class: les constructeurs
Class: les constructeurs
class A
  def A.new
  end
end

A.new
Class: les constructeurs
class A         class B
  def A.new       def self.new
  end             end
end             end

A.new           B.new
Class: les constructeurs
class A            class B
  def A.new          def self.new
  end                end
end                end

A.new              B.new



class C
  def initialize
  end
end

C.new
Class: les constructeurs
class A            class B
  def A.new          def self.new
  end                end
end                end

A.new              B.new

                   class D
                     # pas de constructeur multiple
class C
                     def initialize; end
  def initialize
  end
                    def initialize(*args)
end
                    end
                   end
C.new
                   D.new # => KO
                   D.new(1) # => OK
Class: les accesseurs
Class: les accesseurs
class Product
   def initialize(name, description, price)
      @name = name
      @description = description
      @price = price
   end

   def name
      @name
   end

   def name=(name)
      @name = name
   end
   …

end
Class: les accesseurs
class Product
   def initialize(name, description, price)
      @name = name
      @description = description              class Product
      @price = price                             attr_accessor :name
   end                                           attr_reader: description
                                                 attr_writer :price
   def name
      @name                                     def initialize(name, description, price)
   end                                             @name = name
                                                   @description = description
   def name=(name)                                 @price = price
      @name = name                              end
   end                                        end
   …

end
Class: portée & héritage
Class: portée & héritage
class Animal
  def initialize
   puts "Born to be alive."
  end

 protected
 def breathe?
  puts "inhale, exhale"
  true
 end

 private
 def speak; end
end

# Animal.new.speak
# => fail with private method `speak'
Class: portée & héritage
class Animal                            class Dog < Animal
  def initialize                          def alive?
   puts "Born to be alive."                puts "I'm alive" if breathe?
  end                                     end

 protected                               def speak
 def breathe?                             puts "woff."
  puts "inhale, exhale"                  end
  true                                  end
 end
                                        snoopy = Dog.new
 private                                # Born to be alive.
 def speak; end                         snoopy.speak
end                                     # woff.
                                        snoopy.alive?
# Animal.new.speak                      # inhale, exhale
# => fail with private method `speak'   # I'm alive
Class: étendre
Class: étendre

# Etendre un objet
str = "foo"

class << str
  def blank?
   self !~ /S/
  end
end

str.blank?
# => false
Class: étendre

# Etendre un objet           # Etendre une classe
str = "foo"                  class String
                               def blank?
class << str                    self !~ /S/
  def blank?                   end
   self !~ /S/              end
  end
end                          "     ".blank?
                             # => true
str.blank?                   "foo".blank?
# => false                   # => false
Class: ce qui n’existe pas

• Pas d’héritage multiple
• Basé sur les mixins
• Pas d’interface
• Pas de classe abstraite native
Les outils
irb : votre shell ruby
 [17:59:57] fuse@h [~]$ irb
 ruby-1.8.7-p302 :001 > puts ‘foo’
 foo
  => nil
 ruby-1.8.7-p302 :002 > 21 * 2
  => 42
 ruby-1.8.7-p302 :008 > String.methods.sort
  => ["<", "<=", "<=>", "==", "===", "=~", ">", …]



rvm : gérer plusieurs versions de ruby
Documentation
• http://www.ruby-doc.org/
• http://www.ruby-lang.org/
• http://apidock.com/ruby
• Le pickAxe: LA référence
• http://tryruby.org/
• http://groups.google.com/group/rubyfr-
  public
Rails
On ne va pas (ou peu) parler de:

           Copieurs
  Test                   I18n
           Rake
 Cache                  Rails 3
         ActionMailer
                        Déploiement
 ActiveSupport
L’Histoire

• Créé par DHH (David Heinemeier Hansson)
• Version 1 en décembre 2005
• Pragmatique dès le début: basecamp
Rails en entreprise

• Plus un jouet
• Présent en entreprise, grandes et petites
• Opportunités en temps que développeur
Les versions

• Stable actuelle: 3.0.7
 • Rails 3 issue du merge avec merb (08/10)
 • Framework agnostic
• Stable actuelle: 2.3.11
 • La plus rencontrée en entreprise
Des conventions
Quelques noms barbares:


• Convention over configuration
• DRY
• MVC
Convention over
      configuration
• Votre passion est de customiser Tomcat ?
  Désolé !
• 0 conf pour commencer à développer
 • Serveur web embarqué
 • BDD embarquée
Don’t repeat yourself

• - de code = - de bug
• - de code = - de maintenance
• - de code = + de temps
Modèle - Vue - Contrôleur

     Modèle     Contrôleur      Vue



    Métier    Fonctionnel    Affichage
Rails en vrai


• Pas de hello world, c’est trop simple…
• La classique liste de produits plutôt.
Créons notre application

 $ rails app



3 environnements
Ruby on rails presentation
class Product < ActiveRecord::Base   Modèle
end
                                     app/models/product.rb
class Product < ActiveRecord::Base                 Modèle
end
                                                   app/models/product.rb

class ProductsController < ApplicationController   Contrôleur
    def index
       @products = Product.all                     app/controllers/
    end
 end                                               products_controller.rb
class Product < ActiveRecord::Base                 Modèle
end
                                                   app/models/product.rb

class ProductsController < ApplicationController   Contrôleur
    def index
       @products = Product.all                     app/controllers/
    end
 end                                               products_controller.rb

 <html><body>                                      Vue
 <% for product in @products %>
 <p><%= product.name %></p>                        app/views/products/
 <% end %>
 </body></html>                                    index.html.erb
class Product < ActiveRecord::Base                 Modèle
end
                                                   app/models/product.rb

class ProductsController < ApplicationController   Contrôleur
    def index
       @products = Product.all                     app/controllers/
    end
 end                                               products_controller.rb

 <html><body>                                      Vue
 <% for product in @products %>
 <p><%= product.name %></p>                        app/views/products/
 <% end %>
 </body></html>                                    index.html.erb
Que vient on de faire ?

• Créer une classe product qui hérite de AR::Base
  Model

• Créer un contrôleur qui gère les actions (ex: index)
  Contrôleur

• Créer des vues pour afficher la liste et les formulaires
   Vue
Le modèle avec
      Active Record
• S’interface avec la base de données
• SQLite par défaut
• Plus de SQL manuel
• Plus de risque d’injections
Créer un modèle
Créer un modèle
$ ruby script/generate model Product name:string description:text price:float
category_id:integer
Créer un modèle
$ ruby script/generate model Product name:string description:text price:float
category_id:integer


  class CreateProducts < ActiveRecord::Migration
    def self.up
     create_table :products do |t|                     db/migrate/
       t.string :name
       t.text :description
                                                       20110322113407_
       t.float :price                                   create_products.rb
       t.integer :category_id

     t.timestamps
    end                                                 rake db:migrate
   end

   def self.down
    drop_table :products
   end
  end
Configuration & log
Configuration & log
config/database.yml
    development:
     adapter: sqlite3
     database: db/        Adaptateurs pour MySQL,
    development.sqlite3
     pool: 5
                          Postgresql, oracle…
     timeout: 5000
Configuration & log
config/database.yml
    development:
     adapter: sqlite3
     database: db/            Adaptateurs pour MySQL,
    development.sqlite3
     pool: 5
                              Postgresql, oracle…
     timeout: 5000

Dans le contrôleur                log/development.log

                                      Product Load (0.3ms)
    @products = Product.all
                                      SELECT * FROM "products"
Créer un produit
Créer un produit
c = Category.first
Product.create({
   :name => "Ruby 'on Rails", # injection SQL
   :description => "First book on RoR",
   :price => 10.0,
   :category => c })
Créer un produit
   c = Category.first
   Product.create({
      :name => "Ruby 'on Rails", # injection SQL
      :description => "First book on RoR",
      :price => 10.0,
      :category => c })


log/development.log
  Product Create (0.8ms) INSERT INTO "products"
("name", "price", "created_at", "updated_at", "category_id", "description")
VALUES
('Ruby ''on Rails', 10.0, '2011-03-22 18:13:07', '2011-03-22 18:13:07', 1, 'First
book on RoR')
Encore trop complexe ?
Besoin d’un outil qui gère le CRUD en 1 commande:

  • Create
  • Read
  • Update
  • Delete
Scaffold
Scaffold
Plus qu’une migration

• Et vous pouvez:
 • Créer des produits (Create)
 • Les lister et afficher (Read)
 • Les mettre à jour (Update)
 • Et les supprimer (Delete)
En images
Les relations
Les relations
 class Category < ActiveRecord::Base
   has_many :products
                                       Une catégorie possède
end                                    n produits
Les relations
 class Category < ActiveRecord::Base
   has_many :products
                                       Une catégorie possède
end                                    n produits

 class Product < ActiveRecord::Base    Un produit appartient à
  belongs_to :category
end                                    une catégorie
Les relations
 class Category < ActiveRecord::Base
   has_many :products
                                       Une catégorie possède
end                                    n produits

 class Product < ActiveRecord::Base    Un produit appartient à
  belongs_to :category
end                                    une catégorie
ou
 class Product < ActiveRecord::Base
                                       Une catégorie possède
  has_and_belongs_to_many :category    n produits et un
end
                                       produit n catégories
Les finder
Les finder
Product.find(:all, :conditions => { :price => 18 })
Product.find(:first)
Product.find(:last)
Les finder
 Product.find(:all, :conditions => { :price => 18 })
 Product.find(:first)
 Product.find(:last)


Plusieurs finder dynamiques:

 Product.find_by_name(‘rails’)
 Product.find_all_by_name(‘rails’)
 Product.find_by_name_and_price(‘book’, 18)
Les finder
 Product.find(:all, :conditions => { :price => 18 })
 Product.find(:first)
 Product.find(:last)


Plusieurs finder dynamiques:

 Product.find_by_name(‘rails’)
 Product.find_all_by_name(‘rails’)
 Product.find_by_name_and_price(‘book’, 18)



Jointure:
 Product.find(:all, :joins => :category,
 :conditions => { :categories => { :name => "books" }})
Les scope
Les scope
class Product < ActiveRecord::Base
     named_scope :recent, lambda { { :conditions => ["created_at > ?", 5.days.ago] } }
     named_scope :limit, lambda { |n| { :limit => n } }
     named_scope :ordered_by_name, { :order => "NAME ASC" }
   end
Les scope
 class Product < ActiveRecord::Base
      named_scope :recent, lambda { { :conditions => ["created_at > ?", 5.days.ago] } }
      named_scope :limit, lambda { |n| { :limit => n } }
      named_scope :ordered_by_name, { :order => "NAME ASC" }
    end


Invoquer les scope, de façon chaînable

 Product.recent.ordered_by_name.limit(2)
 Product Load (0.3ms) SELECT * FROM "products" WHERE (created_at > '2011-03-17
 21:08:24') ORDER BY NAME ASC LIMIT 2
Les validations
  class Product < ActiveRecord::Base
     belongs_to :category
     validates_presence_of :name, :category_id
     validates_numericality_of :price



et bien d’autres:

validates_confirmation_of
validates_exclusion_of
validates_format_of
validates_inclusion_of
validates_length_of
…
Le contrôleur avec
    ActionController
• L’interface entre le modèle et la vue
• Association automatique méthode / vue
• @variable directement disponible dans la
  vue
• Possibilité de filtrer des actions
Le routeur
config/routes.rb
ActionController::Routing::Routes.draw do |map|
  # RESTful /categories/1/products/1/
  map.resources :categories do |category|
     category.resources :products
  end
  # route nommée
  map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
  # namespace
  map.namespace :admin do |admin|
     # /admin/products
     admin.resource :products
  end
  # route par défaut
  map.root :controller => 'products'
end
Les routes
 rake routes
   categories GET        /categories(.:format)        {:controller=>"categories", :action=>"index"}
              POST /categories(.:format)               {:controller=>"categories", :action=>"create"}
 new_category GET /categories/new(.:format)           {:controller=>"categories", :action=>"new"}
edit_category GET /categories/:id/edit(.:format) {:controller=>"categories", :action=>"edit"}
    category GET        /categories/:id(.:format)    {:controller=>"categories", :action=>"show"}
          PUT          /categories/:id(.:format)      {:controller=>"categories", :action=>"update"}
          DELETE      /categories/:id(.:format)      {:controller=>"categories", :action=>"destroy"}
    products GET     /products(.:format)             {:controller=>"products", :action=>"index"}
          POST       /products(.:format)             {:controller=>"products", :action=>"create"}
  new_product GET /products/new(.:format)            {:controller=>"products", :action=>"new"}
 edit_product GET /products/:id/edit(.:format)       {:controller=>"products", :action=>"edit"}
     product GET     /products/:id(.:format)         {:controller=>"products", :action=>"show"}
          PUT       /products/:id(.:format)           {:controller=>"products", :action=>"update"}
          DELETE /products/:id(.:format)             {:controller=>"products", :action=>"destroy"}
                  /:controller/:action/:id
                  /:controller/:action/:id(.:format)
       root       /                                   {:controller=>"products", :action=>"index"}
Les contrôleurs
class ProductsController < ApplicationController
   before_filter :authenticate, :only => :index

  def index
    @products = Product.all #disponible dans la vue

     respond_to do |format|
        # GET /products
        format.html # index.html.erb
        # GET /products.xml
        format.xml { render :xml => @products }
     end
  end
  private
  def authenticate
     # do some stuff
  end
end
La vue avec
         ActionView
• Les vues : pas forcément du HTML
• Layout
• Partials
• Helpers
Les types de vues
i18n des vues
 app/views/products/index.fr.html.erb
 app/views/products/index.es.html.erb   Rails >= 2.3
Les types de vues
i18n des vues
 app/views/products/index.fr.html.erb
 app/views/products/index.es.html.erb   Rails >= 2.3

Différents formats
 app/views/products/index.iphone.erb
 app/views/products/index.xml.erb
Le layout
Squelette de base   app/views/layouts/application.html.erb



Modifiable depuis    <!DOCTYPE…>
                    <html>
le contrôleur       <body>
                    <%= yield %>
                    </body>
                    </html>
Les partials
Des morceaux de vue

 <!DOCTYPE…>
 <html>
 <body>                                         app/views/products/_sidebar.html.erb
 <%= render :partial => ‘products/sidebar’ %>
 <%= yield %>
 </body>
 </html>
Exemple de vue: liste
<h1>Listing categories</h1>

<table>
 <tr>
  <th>Name</th>
 </tr>

<% @categories.each do |category| %>
 <tr>
   <td><%=h truncate(category.name, :size => 10) %></td>
   <td><%= link_to 'Show', category %></td>
   <td><%= link_to 'Edit', edit_category_path(category) %></td>
   <td><%= link_to 'Destroy', category, :confirm => 'Are you sure?', :method
=> :delete %></td>
 </tr>
<% end %>
</table>

<br />

<%= link_to 'New category', new_category_path %>
Exemple de vue: édition
<% form_for(@product) do |f| %>
 <%= f.error_messages %>

 <p>
  <%= f.label :name %><br />
  <%= f.text_field :name %>
 </p><p>
  <%= f.label :description %><br />
  <%= f.text_area :description %>
 </p><p>
  <%= f.label :available %><br />
  <%= f.check_box :available %>
 </p><p>
  <%= f.label :category_id %><br />
  <%= f.select :category_id, (Category.all.map do |c| [c.name, c.id] end) %>
 </p><p>
  <%= f.submit 'Update' %>
 </p>
<% end %>

<%= link_to 'Show', @product %> |
<%= link_to 'Back', products_path %>
Autour de Rails

•   Communauté active     config/environment.rb
•   Autour de github       Rails::Initializer.run do |config|
                             config.gem ‘hpricot’

•
                           end
    Gems
    •   Authentification
    •   Pagination
    •   …
Documentation

• http://www.rubyonrails.org/
• http://guides.rubyonrails.org/
• http://apidock.com/rails
• http://railsforzombies.org/
• http://groups.google.com/group/railsfrance
Merci, c’est à vous !


• Des questions ?


    _fuse      mcatty@synbioz.com

More Related Content

PDF
Talk Code
PDF
Beginning Python
PPT
10 Recursion
PPTX
Start Writing Groovy
PDF
Go Java, Go!
PPTX
Go Java, Go!
PDF
Introduction to python
PDF
PythonOOP
Talk Code
Beginning Python
10 Recursion
Start Writing Groovy
Go Java, Go!
Go Java, Go!
Introduction to python
PythonOOP

What's hot (20)

PDF
Pooya Khaloo Presentation on IWMC 2015
PDF
PDF
Python Functions (PyAtl Beginners Night)
PPTX
PDF
Functions in python
PPTX
13 recursion-120712074623-phpapp02
PPTX
Kotlin Collections
PDF
Functional programming in ruby
PDF
Introduction to Erlang
PDF
Introduction to Erlang
ODP
Exact Real Arithmetic for Tcl
PDF
Design Pattern Observations
PDF
Intro To Erlang
PDF
Hammurabi
PDF
learn you some erlang - chap0 to chap2
PDF
A Language Designer’s Workbench. A one-stop shop for implementation and verif...
PDF
Go Java, Go!
KEY
Scala for ruby programmers
PDF
Dynamic Semantics Specification and Interpreter Generation
PDF
Are we ready to Go?
Pooya Khaloo Presentation on IWMC 2015
Python Functions (PyAtl Beginners Night)
Functions in python
13 recursion-120712074623-phpapp02
Kotlin Collections
Functional programming in ruby
Introduction to Erlang
Introduction to Erlang
Exact Real Arithmetic for Tcl
Design Pattern Observations
Intro To Erlang
Hammurabi
learn you some erlang - chap0 to chap2
A Language Designer’s Workbench. A one-stop shop for implementation and verif...
Go Java, Go!
Scala for ruby programmers
Dynamic Semantics Specification and Interpreter Generation
Are we ready to Go?
Ad

Viewers also liked (6)

PPTX
Lean startup
PPSX
Reuters: Pictures of the Year 2016 (Part 2)
PDF
What's Next in Growth? 2016
PDF
The Six Highest Performing B2B Blog Post Formats
PDF
The Outcome Economy
PDF
32 Ways a Digital Marketing Consultant Can Help Grow Your Business
Lean startup
Reuters: Pictures of the Year 2016 (Part 2)
What's Next in Growth? 2016
The Six Highest Performing B2B Blog Post Formats
The Outcome Economy
32 Ways a Digital Marketing Consultant Can Help Grow Your Business
Ad

Similar to Ruby on rails presentation (20)

PPT
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
PDF
CoffeeScript
PDF
Ruby 程式語言綜覽簡介
PDF
Patterns 200711
PDF
Ruby Gotchas
PDF
Ruby Intro {spection}
PDF
Functional Programming with Groovy
KEY
An introduction to Ruby
PDF
Feel of Kotlin (Berlin JUG 16 Apr 2015)
PDF
CoffeeScript
PPTX
Dts x dicoding #2 memulai pemrograman kotlin
PDF
Zhifu Ge - How To Be Weird In Ruby - With Notes
PDF
Por qué Crystal? Why Crystal Language?
PDF
Threequals - Case Equality in Ruby
KEY
PPTX
01 Introduction to Kotlin - Programming in Kotlin.pptx
PPTX
Introduction to Kotlin.pptx
PDF
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
PDF
Ruby Gotchas
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
CoffeeScript
Ruby 程式語言綜覽簡介
Patterns 200711
Ruby Gotchas
Ruby Intro {spection}
Functional Programming with Groovy
An introduction to Ruby
Feel of Kotlin (Berlin JUG 16 Apr 2015)
CoffeeScript
Dts x dicoding #2 memulai pemrograman kotlin
Zhifu Ge - How To Be Weird In Ruby - With Notes
Por qué Crystal? Why Crystal Language?
Threequals - Case Equality in Ruby
01 Introduction to Kotlin - Programming in Kotlin.pptx
Introduction to Kotlin.pptx
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Ruby Gotchas

Recently uploaded (20)

PPTX
A Presentation on Artificial Intelligence
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Encapsulation_ Review paper, used for researhc scholars
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PPTX
Spectroscopy.pptx food analysis technology
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Empathic Computing: Creating Shared Understanding
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Encapsulation theory and applications.pdf
PPTX
Cloud computing and distributed systems.
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Big Data Technologies - Introduction.pptx
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
A Presentation on Artificial Intelligence
Reach Out and Touch Someone: Haptics and Empathic Computing
Encapsulation_ Review paper, used for researhc scholars
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Network Security Unit 5.pdf for BCA BBA.
Diabetes mellitus diagnosis method based random forest with bat algorithm
“AI and Expert System Decision Support & Business Intelligence Systems”
Spectroscopy.pptx food analysis technology
Unlocking AI with Model Context Protocol (MCP)
NewMind AI Weekly Chronicles - August'25-Week II
Empathic Computing: Creating Shared Understanding
The Rise and Fall of 3GPP – Time for a Sabbatical?
Encapsulation theory and applications.pdf
Cloud computing and distributed systems.
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Big Data Technologies - Introduction.pptx
MYSQL Presentation for SQL database connectivity
Mobile App Security Testing_ A Comprehensive Guide.pdf

Ruby on rails presentation

  • 1. Ruby on Rails Supinfo 2011
  • 2. A propos • Martin Catty, fondateur de Synbioz • Rubyiste depuis 2006 _fuse mcatty@synbioz.com
  • 3. Ruby avant Rails • Ne partez pas sans vos bagages ! • Rails a aidé à l’essor de Ruby • Mais pas de framework sans langage
  • 4. Ruby On ne va pas (ou peu) parler de: I/O Test VM Thread Implémentations Debugger Garbage Proc / lambda Exceptions Réseau
  • 5. L’Histoire • Créé par Yukihiro Matsumoto (Matz) • Release publique en 2005
  • 6. Un langage • Plus objet que python • Plus puissant que perl • Fun
  • 7. Les versions • Stable actuelle: 1.9.2 • 1.8.7 dans la branche 1.8 • 1.8.7 (p250) fonctionne avec Rails 2 et 3 • < 1.8.7 = Rails 2 • > 1.8.7 = Rails 3
  • 8. Le fameux hello world Java Ruby
  • 9. Le fameux hello world Java Ruby class Hello { public static void main(String [] args) { system.out.println(‘Hello’); } }
  • 10. Le fameux hello world Java Ruby class Hello { public static void main(String [] args) { system.out.println(‘Hello’); puts ‘Hello’ } }
  • 11. Le fameux hello world Java Ruby class Hello { public static void main(String [] args) { system.out.println(‘Hello’); puts ‘Hello’ } } </troll>
  • 13. Tout est objet 2.times { puts "Bonjour Supinfo." } => Bonjour Supinfo => Bonjour Supinfo
  • 14. Tout est objet 2.times { puts "Bonjour Supinfo." } 3.upto(5) { |i| puts i } => Bonjour Supinfo => 3 => Bonjour Supinfo => 4 => 5
  • 15. Tout est objet 2.times { puts "Bonjour Supinfo." } 3.upto(5) { |i| puts i } => Bonjour Supinfo => 3 => Bonjour Supinfo => 4 => 5 p 1.zero? => false
  • 16. Tout est objet 2.times { puts "Bonjour Supinfo." } 3.upto(5) { |i| puts i } => Bonjour Supinfo => 3 => Bonjour Supinfo => 4 => 5 p 1.zero? 39 + 3 => false => 39.+(3)
  • 17. Les variables class A MAX = 42 A.new("a") @@instances = 0 A.new("b") def initialize(name) @name = name A.new("c") @@instances += 1 end A.new("d") def self.instances A.new("e") @@instances end end p A.instances #=> 5
  • 19. Itérations a = 1..9 for i in a puts i end
  • 20. Itérations a = 1..9 for i in a puts i end => 1…9
  • 21. Itérations a = 1..9 for i in a puts i ou end => 1…9
  • 22. Itérations a = 1..9 for i in a a = 1..9 puts i ou a.each { |i| puts i } end => 1…9
  • 23. Itérations a = 1..9 for i in a a = 1..9 puts i ou a.each { |i| puts i } end => 1…9 => 1…9
  • 24. Itérations a = 1..9 for i in a a = 1..9 puts i ou a.each { |i| puts i } end => 1…9 => 1…9 i=0 loop do i += 1 puts i break if 10 == i end
  • 25. Itérations a = 1..9 for i in a a = 1..9 puts i ou a.each { |i| puts i } end => 1…9 => 1…9 i=0 loop do i += 1 puts i break if 10 == i end => 1…9
  • 26. Itérations a = 1..9 for i in a a = 1..9 puts i ou a.each { |i| puts i } end => 1…9 => 1…9 i=0 loop do i += 1 1.upto(10) do |i| puts i next if i.odd? # pas d'impair en ruby break if 10 == i puts i end end => 1…9
  • 27. Itérations a = 1..9 for i in a a = 1..9 puts i ou a.each { |i| puts i } end => 1…9 => 1…9 i=0 loop do i += 1 1.upto(10) do |i| puts i next if i.odd? # pas d'impair en ruby break if 10 == i puts i end end => 1…9 => 2, 4, 6, 8, 10
  • 28. Itérations a = 1..9 for i in a a = 1..9 puts i ou a.each { |i| puts i } end => 1…9 => 1…9 i=0 loop do i += 1 1.upto(10) do |i| puts i next if i.odd? # pas d'impair en ruby break if 10 == i puts i end end => 1…9 => 2, 4, 6, 8, 10 1.upto(2) do |i| v = rand(2) retry if v.zero? end
  • 30. Conditions if index == 1 else puts ‘0’ if index.zero? puts ‘not 0’ unless index.zero? end
  • 31. Conditions if index == 1 else puts ‘0’ if index.zero? puts ‘not 0’ unless index.zero? end def what_is_it?(a) case a what_is_it?(1) when 1..2 # 1 or 2 puts "1 or 2" what_is_it?(2) when 3 # 1 or 2 puts "3" what_is_it?(3) when /4.*/ # Regexp #3 puts "something starting with 4." what_is_it?("4004") when "foo" # something starting with 4. puts "foo" what_is_it?("foo") else # foo puts "I don't know." what_is_it?(5) end # Don't know. end
  • 33. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost << 42 # push lost.unshift(4) # [4, 8, 15, 16, 23, 42]
  • 34. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost << 42 # push lost.unshift(4) # [4, 8, 15, 16, 23, 42]
  • 35. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42] # 42
  • 36. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42] # 42
  • 37. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil]
  • 38. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil]
  • 39. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost.compact! # [4, 8, 15, 16, 23, 42]
  • 40. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost.compact! # [4, 8, 15, 16, 23, 42]
  • 41. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost << [4, 8] lost.compact! # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] [4, 8]]
  • 42. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost << [4, 8] lost.compact! # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] [4, 8]]
  • 43. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost.flatten!.uniq! lost << [4, 8] lost.compact! # [4, 8, 15, 16, 23, 42] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] [4, 8]]
  • 44. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost.flatten!.uniq! lost << [4, 8] lost.compact! # [4, 8, 15, 16, 23, 42] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] [4, 8]] lost.index(23) #4
  • 45. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost.flatten!.uniq! lost << [4, 8] lost.compact! # [4, 8, 15, 16, 23, 42] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] [4, 8]] lost.shuffle lost.index(23) # [16, 23, 42, 4, 15, 8] [5, 3, 7, 39, 1, 15].sort #4 # [1, 3, 5, 7, 15, 39]
  • 46. Tableaux 1/2 1 lost = [8, 15, 16, 23] lost.at(0) lost << nil << nil lost << 42 # push #4 lost.unshift(4) lost[-1] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] # 42 nil, nil] lost.flatten!.uniq! lost << [4, 8] lost.compact! # [4, 8, 15, 16, 23, 42] # [4, 8, 15, 16, 23, 42, # [4, 8, 15, 16, 23, 42] [4, 8]] lost.shuffle lost.index(23) # [16, 23, 42, 4, 15, 8] ('a'..'z').to_a [5, 3, 7, 39, 1, 15].sort ["a", "b", "c", "d"…] #4 # [1, 3, 5, 7, 15, 39]
  • 48. Tableaux 2/2 double_lost = lost.map { |v| v * 2 } # => [8, 16, 30, 32, 46, 84]
  • 49. Tableaux 2/2 # lost: [4, 8, 15, 16, 23, 42] double_lost = lost.map { |v| v * 2 } double_lost - lost # => [8, 16, 30, 32, 46, 84] # => [30, 32, 46, 84]
  • 50. Tableaux 2/2 # lost: [4, 8, 15, 16, 23, 42] double_lost = lost.map { |v| v * 2 } double_lost - lost # => [8, 16, 30, 32, 46, 84] # => [30, 32, 46, 84] # intersection double_lost & lost # [8, 16]
  • 51. Tableaux 2/2 # lost: [4, 8, 15, 16, 23, 42] double_lost = lost.map { |v| v * 2 } double_lost - lost # => [8, 16, 30, 32, 46, 84] # => [30, 32, 46, 84] # intersection # jointure double_lost & lost (double_lost | lost).sort # [8, 16] # [4, 8, 15, 16, 23, 30, 32, 42, 46, 84]
  • 53. String str = "bar" puts 'foo #{str}' # => foo #{str}
  • 54. String str = "bar" # Interpolation puts 'foo #{str}' puts "foo #{str}" # => foo #{str} # => foo bar
  • 55. String str = "bar" # Interpolation puts 'foo #{str}' puts "foo #{str}" # => foo #{str} # => foo bar str = "a" str.succ # => "b"
  • 56. String str = "bar" # Interpolation puts 'foo #{str}' puts "foo #{str}" # => foo #{str} # => foo bar str = "a" str = "foon" str.succ str.chomp # => "b" # => "foo"
  • 57. String str = "bar" # Interpolation puts 'foo #{str}' puts "foo #{str}" # => foo #{str} # => foo bar str = "a" str = "foon" str.succ str.chomp # => "b" # => "foo" str = "foo" str.chop # => "fo"
  • 58. String str = "bar" # Interpolation puts 'foo #{str}' puts "foo #{str}" # => foo #{str} # => foo bar str = "a" str = "foon" str.succ str.chomp # => "b" # => "foo" "supinfo".capitalize str = "foo" # => "Supinfo" str.chop "supinfo".upcase # => "fo" # => "SUPINFO"
  • 59. String str = "bar" # Interpolation puts 'foo #{str}' puts "foo #{str}" # attention, en 1.8 # => foo #{str} # => foo bar str = "éhé" str.size # => 5 et non 3 str[0] str = "a" str = "foon" # 195 et non é (code ascii) str.succ str.chomp # => "b" # => "foo" # patché dans rails str.mb_chars[0] #é "supinfo".capitalize str.mb_chars.size str = "foo" #3 # => "Supinfo" str.chop "supinfo".upcase # => "fo" # => "SUPINFO"
  • 61. Hash Association clé / valeur h = { :a => 'a', :b => 42, :c => { :d => 'f' } } h2 = { :a => 'foo' } h.merge(h2) => {:a=>"foo", :b=>42, :c=>{:d=>"f"}}
  • 63. Class: les constructeurs class A def A.new end end A.new
  • 64. Class: les constructeurs class A class B def A.new def self.new end end end end A.new B.new
  • 65. Class: les constructeurs class A class B def A.new def self.new end end end end A.new B.new class C def initialize end end C.new
  • 66. Class: les constructeurs class A class B def A.new def self.new end end end end A.new B.new class D # pas de constructeur multiple class C def initialize; end def initialize end def initialize(*args) end end end C.new D.new # => KO D.new(1) # => OK
  • 68. Class: les accesseurs class Product def initialize(name, description, price) @name = name @description = description @price = price end def name @name end def name=(name) @name = name end … end
  • 69. Class: les accesseurs class Product def initialize(name, description, price) @name = name @description = description class Product @price = price attr_accessor :name end attr_reader: description attr_writer :price def name @name def initialize(name, description, price) end @name = name @description = description def name=(name) @price = price @name = name end end end … end
  • 70. Class: portée & héritage
  • 71. Class: portée & héritage class Animal def initialize puts "Born to be alive." end protected def breathe? puts "inhale, exhale" true end private def speak; end end # Animal.new.speak # => fail with private method `speak'
  • 72. Class: portée & héritage class Animal class Dog < Animal def initialize def alive? puts "Born to be alive." puts "I'm alive" if breathe? end end protected def speak def breathe? puts "woff." puts "inhale, exhale" end true end end snoopy = Dog.new private # Born to be alive. def speak; end snoopy.speak end # woff. snoopy.alive? # Animal.new.speak # inhale, exhale # => fail with private method `speak' # I'm alive
  • 74. Class: étendre # Etendre un objet str = "foo" class << str def blank? self !~ /S/ end end str.blank? # => false
  • 75. Class: étendre # Etendre un objet # Etendre une classe str = "foo" class String def blank? class << str self !~ /S/ def blank? end self !~ /S/ end end end " ".blank? # => true str.blank? "foo".blank? # => false # => false
  • 76. Class: ce qui n’existe pas • Pas d’héritage multiple • Basé sur les mixins • Pas d’interface • Pas de classe abstraite native
  • 77. Les outils irb : votre shell ruby [17:59:57] fuse@h [~]$ irb ruby-1.8.7-p302 :001 > puts ‘foo’ foo => nil ruby-1.8.7-p302 :002 > 21 * 2 => 42 ruby-1.8.7-p302 :008 > String.methods.sort => ["<", "<=", "<=>", "==", "===", "=~", ">", …] rvm : gérer plusieurs versions de ruby
  • 78. Documentation • http://www.ruby-doc.org/ • http://www.ruby-lang.org/ • http://apidock.com/ruby • Le pickAxe: LA référence • http://tryruby.org/ • http://groups.google.com/group/rubyfr- public
  • 79. Rails On ne va pas (ou peu) parler de: Copieurs Test I18n Rake Cache Rails 3 ActionMailer Déploiement ActiveSupport
  • 80. L’Histoire • Créé par DHH (David Heinemeier Hansson) • Version 1 en décembre 2005 • Pragmatique dès le début: basecamp
  • 81. Rails en entreprise • Plus un jouet • Présent en entreprise, grandes et petites • Opportunités en temps que développeur
  • 82. Les versions • Stable actuelle: 3.0.7 • Rails 3 issue du merge avec merb (08/10) • Framework agnostic • Stable actuelle: 2.3.11 • La plus rencontrée en entreprise
  • 83. Des conventions Quelques noms barbares: • Convention over configuration • DRY • MVC
  • 84. Convention over configuration • Votre passion est de customiser Tomcat ? Désolé ! • 0 conf pour commencer à développer • Serveur web embarqué • BDD embarquée
  • 85. Don’t repeat yourself • - de code = - de bug • - de code = - de maintenance • - de code = + de temps
  • 86. Modèle - Vue - Contrôleur Modèle Contrôleur Vue Métier Fonctionnel Affichage
  • 87. Rails en vrai • Pas de hello world, c’est trop simple… • La classique liste de produits plutôt.
  • 88. Créons notre application $ rails app 3 environnements
  • 90. class Product < ActiveRecord::Base Modèle end app/models/product.rb
  • 91. class Product < ActiveRecord::Base Modèle end app/models/product.rb class ProductsController < ApplicationController Contrôleur def index @products = Product.all app/controllers/ end end products_controller.rb
  • 92. class Product < ActiveRecord::Base Modèle end app/models/product.rb class ProductsController < ApplicationController Contrôleur def index @products = Product.all app/controllers/ end end products_controller.rb <html><body> Vue <% for product in @products %> <p><%= product.name %></p> app/views/products/ <% end %> </body></html> index.html.erb
  • 93. class Product < ActiveRecord::Base Modèle end app/models/product.rb class ProductsController < ApplicationController Contrôleur def index @products = Product.all app/controllers/ end end products_controller.rb <html><body> Vue <% for product in @products %> <p><%= product.name %></p> app/views/products/ <% end %> </body></html> index.html.erb
  • 94. Que vient on de faire ? • Créer une classe product qui hérite de AR::Base Model • Créer un contrôleur qui gère les actions (ex: index) Contrôleur • Créer des vues pour afficher la liste et les formulaires Vue
  • 95. Le modèle avec Active Record • S’interface avec la base de données • SQLite par défaut • Plus de SQL manuel • Plus de risque d’injections
  • 97. Créer un modèle $ ruby script/generate model Product name:string description:text price:float category_id:integer
  • 98. Créer un modèle $ ruby script/generate model Product name:string description:text price:float category_id:integer class CreateProducts < ActiveRecord::Migration def self.up create_table :products do |t| db/migrate/ t.string :name t.text :description 20110322113407_ t.float :price create_products.rb t.integer :category_id t.timestamps end rake db:migrate end def self.down drop_table :products end end
  • 100. Configuration & log config/database.yml development: adapter: sqlite3 database: db/ Adaptateurs pour MySQL, development.sqlite3 pool: 5 Postgresql, oracle… timeout: 5000
  • 101. Configuration & log config/database.yml development: adapter: sqlite3 database: db/ Adaptateurs pour MySQL, development.sqlite3 pool: 5 Postgresql, oracle… timeout: 5000 Dans le contrôleur log/development.log Product Load (0.3ms) @products = Product.all SELECT * FROM "products"
  • 103. Créer un produit c = Category.first Product.create({ :name => "Ruby 'on Rails", # injection SQL :description => "First book on RoR", :price => 10.0, :category => c })
  • 104. Créer un produit c = Category.first Product.create({ :name => "Ruby 'on Rails", # injection SQL :description => "First book on RoR", :price => 10.0, :category => c }) log/development.log Product Create (0.8ms) INSERT INTO "products" ("name", "price", "created_at", "updated_at", "category_id", "description") VALUES ('Ruby ''on Rails', 10.0, '2011-03-22 18:13:07', '2011-03-22 18:13:07', 1, 'First book on RoR')
  • 105. Encore trop complexe ? Besoin d’un outil qui gère le CRUD en 1 commande: • Create • Read • Update • Delete
  • 108. Plus qu’une migration • Et vous pouvez: • Créer des produits (Create) • Les lister et afficher (Read) • Les mettre à jour (Update) • Et les supprimer (Delete)
  • 111. Les relations class Category < ActiveRecord::Base has_many :products Une catégorie possède end n produits
  • 112. Les relations class Category < ActiveRecord::Base has_many :products Une catégorie possède end n produits class Product < ActiveRecord::Base Un produit appartient à belongs_to :category end une catégorie
  • 113. Les relations class Category < ActiveRecord::Base has_many :products Une catégorie possède end n produits class Product < ActiveRecord::Base Un produit appartient à belongs_to :category end une catégorie ou class Product < ActiveRecord::Base Une catégorie possède has_and_belongs_to_many :category n produits et un end produit n catégories
  • 115. Les finder Product.find(:all, :conditions => { :price => 18 }) Product.find(:first) Product.find(:last)
  • 116. Les finder Product.find(:all, :conditions => { :price => 18 }) Product.find(:first) Product.find(:last) Plusieurs finder dynamiques: Product.find_by_name(‘rails’) Product.find_all_by_name(‘rails’) Product.find_by_name_and_price(‘book’, 18)
  • 117. Les finder Product.find(:all, :conditions => { :price => 18 }) Product.find(:first) Product.find(:last) Plusieurs finder dynamiques: Product.find_by_name(‘rails’) Product.find_all_by_name(‘rails’) Product.find_by_name_and_price(‘book’, 18) Jointure: Product.find(:all, :joins => :category, :conditions => { :categories => { :name => "books" }})
  • 119. Les scope class Product < ActiveRecord::Base named_scope :recent, lambda { { :conditions => ["created_at > ?", 5.days.ago] } } named_scope :limit, lambda { |n| { :limit => n } } named_scope :ordered_by_name, { :order => "NAME ASC" } end
  • 120. Les scope class Product < ActiveRecord::Base named_scope :recent, lambda { { :conditions => ["created_at > ?", 5.days.ago] } } named_scope :limit, lambda { |n| { :limit => n } } named_scope :ordered_by_name, { :order => "NAME ASC" } end Invoquer les scope, de façon chaînable Product.recent.ordered_by_name.limit(2) Product Load (0.3ms) SELECT * FROM "products" WHERE (created_at > '2011-03-17 21:08:24') ORDER BY NAME ASC LIMIT 2
  • 121. Les validations class Product < ActiveRecord::Base belongs_to :category validates_presence_of :name, :category_id validates_numericality_of :price et bien d’autres: validates_confirmation_of validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of …
  • 122. Le contrôleur avec ActionController • L’interface entre le modèle et la vue • Association automatique méthode / vue • @variable directement disponible dans la vue • Possibilité de filtrer des actions
  • 123. Le routeur config/routes.rb ActionController::Routing::Routes.draw do |map| # RESTful /categories/1/products/1/ map.resources :categories do |category| category.resources :products end # route nommée map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' # namespace map.namespace :admin do |admin| # /admin/products admin.resource :products end # route par défaut map.root :controller => 'products' end
  • 124. Les routes rake routes categories GET /categories(.:format) {:controller=>"categories", :action=>"index"} POST /categories(.:format) {:controller=>"categories", :action=>"create"} new_category GET /categories/new(.:format) {:controller=>"categories", :action=>"new"} edit_category GET /categories/:id/edit(.:format) {:controller=>"categories", :action=>"edit"} category GET /categories/:id(.:format) {:controller=>"categories", :action=>"show"} PUT /categories/:id(.:format) {:controller=>"categories", :action=>"update"} DELETE /categories/:id(.:format) {:controller=>"categories", :action=>"destroy"} products GET /products(.:format) {:controller=>"products", :action=>"index"} POST /products(.:format) {:controller=>"products", :action=>"create"} new_product GET /products/new(.:format) {:controller=>"products", :action=>"new"} edit_product GET /products/:id/edit(.:format) {:controller=>"products", :action=>"edit"} product GET /products/:id(.:format) {:controller=>"products", :action=>"show"} PUT /products/:id(.:format) {:controller=>"products", :action=>"update"} DELETE /products/:id(.:format) {:controller=>"products", :action=>"destroy"} /:controller/:action/:id /:controller/:action/:id(.:format) root / {:controller=>"products", :action=>"index"}
  • 125. Les contrôleurs class ProductsController < ApplicationController before_filter :authenticate, :only => :index def index @products = Product.all #disponible dans la vue respond_to do |format| # GET /products format.html # index.html.erb # GET /products.xml format.xml { render :xml => @products } end end private def authenticate # do some stuff end end
  • 126. La vue avec ActionView • Les vues : pas forcément du HTML • Layout • Partials • Helpers
  • 127. Les types de vues i18n des vues app/views/products/index.fr.html.erb app/views/products/index.es.html.erb Rails >= 2.3
  • 128. Les types de vues i18n des vues app/views/products/index.fr.html.erb app/views/products/index.es.html.erb Rails >= 2.3 Différents formats app/views/products/index.iphone.erb app/views/products/index.xml.erb
  • 129. Le layout Squelette de base app/views/layouts/application.html.erb Modifiable depuis <!DOCTYPE…> <html> le contrôleur <body> <%= yield %> </body> </html>
  • 130. Les partials Des morceaux de vue <!DOCTYPE…> <html> <body> app/views/products/_sidebar.html.erb <%= render :partial => ‘products/sidebar’ %> <%= yield %> </body> </html>
  • 131. Exemple de vue: liste <h1>Listing categories</h1> <table> <tr> <th>Name</th> </tr> <% @categories.each do |category| %> <tr> <td><%=h truncate(category.name, :size => 10) %></td> <td><%= link_to 'Show', category %></td> <td><%= link_to 'Edit', edit_category_path(category) %></td> <td><%= link_to 'Destroy', category, :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <br /> <%= link_to 'New category', new_category_path %>
  • 132. Exemple de vue: édition <% form_for(@product) do |f| %> <%= f.error_messages %> <p> <%= f.label :name %><br /> <%= f.text_field :name %> </p><p> <%= f.label :description %><br /> <%= f.text_area :description %> </p><p> <%= f.label :available %><br /> <%= f.check_box :available %> </p><p> <%= f.label :category_id %><br /> <%= f.select :category_id, (Category.all.map do |c| [c.name, c.id] end) %> </p><p> <%= f.submit 'Update' %> </p> <% end %> <%= link_to 'Show', @product %> | <%= link_to 'Back', products_path %>
  • 133. Autour de Rails • Communauté active config/environment.rb • Autour de github Rails::Initializer.run do |config| config.gem ‘hpricot’ • end Gems • Authentification • Pagination • …
  • 134. Documentation • http://www.rubyonrails.org/ • http://guides.rubyonrails.org/ • http://apidock.com/rails • http://railsforzombies.org/ • http://groups.google.com/group/railsfrance
  • 135. Merci, c’est à vous ! • Des questions ? _fuse mcatty@synbioz.com

Editor's Notes