Download presentation
Presentation is loading. Please wait.
Published byMolly Chase Modified over 10 years ago
1
Ruby on Rails Supinfo 2011
2
A propos Martin Catty, fondateur de Synbioz Rubyiste depuis 2006 _fuse mcatty@synbioz.commcatty@synbioz.com
3
Ruby avant Rails Ne partez pas sans vos bagages ! Rails a aidé à lessor de Ruby Mais pas de framework sans langage
4
Ruby On ne va pas (ou peu) parler de: I/O Réseau Thread Test Debugger Proc / lambda Exceptions Garbage VM Implémentations
5
LHistoire 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 class Hello { public static void main(String [] args) { system.out.println(Hello);}} class Hello { public static void main(String [] args) { system.out.println(Hello); } } JavaRuby puts Hello
9
Tout est objet 2.times { puts "Bonjour Supinfo." } => Bonjour Supinfo 3.upto(5) { |i| puts i } => 3 => 4 => 5 p 1.zero? => false 39 + 3 => 39.+(3)
10
Les variables class A MAX = 42 @@instances = 0 def initialize(name) @name = name @@instances += 1 end def self.instances @@instancesendend class A MAX = 42 @@instances = 0 def initialize(name) @name = name @@instances += 1 end def self.instances @@instancesendend A.new("a")A.new("b")A.ne w("c")A.new("d")A.new("e") p A.instances #=> 5
11
Itérations a = 1..9 for i in a puts i end a = 1..9 for i in a puts i end a = 1..9 a.each { |i| puts i } a = 1..9 a.each { |i| puts i } => 1…9 ou i = 0loop do i += 1 puts i break if 10 == iend i = 0loop do i += 1 puts i break if 10 == iend 1.upto(10) do |i| next if i.odd? # pas d'impair en ruby puts iend 1.upto(10) do |i| next if i.odd? # pas d'impair en ruby puts iend => 2, 4, 6, 8, 10 => 1…9 1.upto(2) do |i| v = rand(2) retry if v.zero?end 1.upto(2) do |i| v = rand(2) retry if v.zero?end
12
Conditions if index == 1 elseend elseend puts 0 if index.zero? puts not 0 unless index.zero? def what_is_it?(a) case a when 1..2 puts "1 or 2" when 3 puts "3" when /4.*/ # Regexp puts "something starting with 4." when "foo" puts "foo" else puts "I don't know." endend what_is_it?(1)# 1 or 2what_is_it?(2)# 1 or 2what_is_it?(3)# 3what_is_it?("4004")# something starting with 4.what_is_it?("foo")# foowhat_is_it?(5)# Don't know.
13
Tableaux 1/2 lost = [8, 15, 16, 23] lost << 42 # push lost.unshift(4) # [4, 8, 15, 16, 23, 42] lost = [8, 15, 16, 23] lost << 42 # push lost.unshift(4) # [4, 8, 15, 16, 23, 42] lost << nil << nil # [4, 8, 15, 16, 23, 42, nil, nil] lost << nil << nil # [4, 8, 15, 16, 23, 42, nil, nil] lost.compact! # [4, 8, 15, 16, 23, 42] lost.compact! # [4, 8, 15, 16, 23, 42] lost << [4, 8] # [4, 8, 15, 16, 23, 42, [4, 8]] lost << [4, 8] # [4, 8, 15, 16, 23, 42, [4, 8]] lost.flatten!.uniq! # [4, 8, 15, 16, 23, 42] lost.flatten!.uniq! # [4, 8, 15, 16, 23, 42] lost.index(23) # 4 lost.index(23) # 4 lost.shuffle # [16, 23, 42, 4, 15, 8] [5, 3, 7, 39, 1, 15].sort # [1, 3, 5, 7, 15, 39] lost.shuffle # [16, 23, 42, 4, 15, 8] [5, 3, 7, 39, 1, 15].sort # [1, 3, 5, 7, 15, 39] ('a'..'z').to_a ["a", "b", "c", "d"…] ('a'..'z').to_a ["a", "b", "c", "d"…] lost.at(0) # 4 lost[-1] # 42 lost.at(0) # 4 lost[-1] # 42 11
14
Tableaux 2/2 double_lost = lost.map { |v| v * 2 } # => [8, 16, 30, 32, 46, 84] double_lost = lost.map { |v| v * 2 } # => [8, 16, 30, 32, 46, 84] # lost: [4, 8, 15, 16, 23, 42] double_lost - lost # => [30, 32, 46, 84] # lost: [4, 8, 15, 16, 23, 42] double_lost - lost # => [30, 32, 46, 84] # intersection double_lost & lost # [8, 16] # intersection double_lost & lost # [8, 16] # jointure (double_lost | lost).sort # [4, 8, 15, 16, 23, 30, 32, 42, 46, 84] # jointure (double_lost | lost).sort # [4, 8, 15, 16, 23, 30, 32, 42, 46, 84]
15
String str = "a"str.succ# => "b" str = "a"str.succ# => "b" # Interpolationputs "foo #{str}"# => foo bar # Interpolationputs "foo #{str}"# => foo bar # attention, en 1.8 str = "éhé" str.size# => 5 et non 3 str[0]# 195 et non é (code ascii) # patché dans rails str.mb_chars[0] # é str.mb_chars.size # 3 # attention, en 1.8 str = "éhé" str.size# => 5 et non 3 str[0]# 195 et non é (code ascii) # patché dans rails str.mb_chars[0] # é str.mb_chars.size # 3 str = "bar" puts 'foo #{str}'# => foo #{str} str = "bar" puts 'foo #{str}'# => foo #{str} str = "foo\n"str.chomp# => "foo" str = "foo\n"str.chomp# => "foo" str = "foo"str.chop# => "fo" str = "foo"str.chop# => "fo" "supinfo".capitalize # => "Supinfo" "supinfo".upcase # => "SUPINFO" "supinfo".capitalize # => "Supinfo" "supinfo".upcase # => "SUPINFO"
16
Hash h = { :a => 'a', :b => 42, :c => { :d => 'f' } } h2 = { :a => 'foo' } h.merge(h2) => {:a=>"foo", :b=>42, :c=>{:d=>"f"}} h2 = { :a => 'foo' } h.merge(h2) => {:a=>"foo", :b=>42, :c=>{:d=>"f"}} Association clé / valeur
17
Class: les constructeurs class A def A.new endendA.new class A def A.new endendA.new class B def self.new endend B.new class B def self.new endend B.new class C def initialize endendC.new endendC.new class C def initialize endendC.new class D # pas de constructeur multiple def initialize; end def initialize(*args) endend D.new # => KOD.new(1) # => OK class D # pas de constructeur multiple def initialize; end def initialize(*args) endend D.new # => KOD.new(1) # => OK
18
Class: les accesseurs class Product def initialize(name, description, price) @name = name @description = description @price = price end def name @nameend def name=(name) @name = name end…end 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 Product attr_accessor :name attr_reader: description attr_writer :price def initialize(name, description, price) @name = name @description = description @price = price endend class Product attr_accessor :name attr_reader: description attr_writer :price def initialize(name, description, price) @name = name @description = description @price = price endend
19
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; endend # Animal.new.speak # => fail with private method `speak' class Animal def initialize puts "Born to be alive." end protected def breathe? puts "inhale, exhale" true end private def speak; endend # Animal.new.speak # => fail with private method `speak' class Dog < Animal def alive? puts "I'm alive" if breathe? end def speak puts "woff." endend snoopy = Dog.new # Born to be alive.snoopy.speak # woff.snoopy.alive? # inhale, exhale# I'm alive class Dog < Animal def alive? puts "I'm alive" if breathe? end def speak puts "woff." endend snoopy = Dog.new # Born to be alive.snoopy.speak # woff.snoopy.alive? # inhale, exhale# I'm alive
20
Class: étendre # Etendre un objetstr = "foo"class false # Etendre un objetstr = "foo"class << str def blank? self !~ /\S/ endendstr.blank?# => false # Etendre une classe class String def blank? self !~ /\S/ endend" ".blank?# => true"foo".blank?# => false # Etendre une classe class String def blank? self !~ /\S/ endend" ".blank?# => true"foo".blank?# => false
21
Class: ce qui nexiste pas Pas dhéritage multiple Basé sur les mixins Pas dinterface Pas de classe abstraite native
22
Les outils [17:59:57] fuse@h [~]$ irbruby-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 => [" ", "==", "===", "=~", ">", …] [17:59:57] fuse@h [~]$ irbruby-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 => [" ", "==", "===", "=~", ">", …] irb : votre shell ruby rvm : gérer plusieurs versions de ruby
23
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://tryruby.org http://groups.google.com/group/rubyfr- public http://groups.google.com/group/rubyfr- public
24
Rails On ne va pas (ou peu) parler de: Test Cache Rake ActionMailer ActiveSupport I18n Déploiement Copieurs Rails 3
25
LHistoire Créé par DHH (David Heinemeier Hansson) Version 1 en décembre 2005 Pragmatique dès le début: basecamp
26
Rails en entreprise Plus un jouet Présent en entreprise, grandes et petites Opportunités en temps que développeur
27
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
28
Des conventions Convention over configuration DRY MVC Quelques noms barbares:
29
Convention over configuration Votre passion est de customiser Tomcat ?Désolé ! 0 conf pour commencer à développer Serveur web embarqué BDD embarquée
30
Dont repeat yourself - de code = - de bug - de code = - de maintenance - de code = + de temps
31
Modèle - Vue - Contrôleur Contrôle ur ModèleModèleVueVue MétierFonctionnelAffichage
32
Rails en vrai Pas de hello world, cest trop simple… La classique liste de produits plutôt.
33
Créons notre application $ rails app 3 environnements
34
class Product < ActiveRecord::Base end end Modèle app/models/product.rb class ProductsController < ApplicationController def index @products = Product.all endend class ProductsController < ApplicationController def index @products = Product.all endend Contrôleur app/controllers/products _controller.rb <html><body> </body></html><html><body> </body></html> Vue app/views/products/i ndex.html.erb
35
Que vient on de faire ? Créer une classe product qui hérite de AR::Base Créer un contrôleur qui gère les actions (ex: index) Créer des vues pour afficher la liste et les formulaires Model Contrôleur Vue
36
Le modèle avec Active Record Sinterface avec la base de données SQLite par défaut Plus de SQL manuel Plus de risque dinjections
37
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| t.string :name t.text :description t.float :price t.integer :category_id t.timestamps end end def self.down drop_table :products endend db/migrate/ 20110322113407 _create_products. rb rake db:migrate
38
Configuration & log @products = Product.all Dans le contrôleurlog/development.log Product Load (0.3ms) SELECT * FROM "products" config/database.yml development: adapter: sqlite3 database: db/development.sqlite3 pool: 5 timeout: 5000 Adaptateurs pour MySQL, Postgresql, oracle…
39
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 }) c = Category.first Product.create({ :name => "Ruby 'on Rails", # injection SQL :description => "First book on RoR", :price => 10.0, :category => c }) Product Create (0.8ms) INSERT INTO "products" 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') Product Create (0.8ms) INSERT INTO "products" 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') log/development.log
40
Encore trop complexe ? Create Read Update Delete Besoin dun outil qui gère le CRUD en 1 commande:
41
Scaffold
42
Plus quune migration Et vous pouvez: Créer des produits (Create) Les lister et afficher (Read) Les mettre à jour (Update) Et les supprimer (Delete)
43
En images
44
Les relations class Category < ActiveRecord::Base has_many :products end class Category < ActiveRecord::Base has_many :products end Une catégorie possède n produits class Product < ActiveRecord::Base belongs_to :category end class Product < ActiveRecord::Base belongs_to :category end Un produit appartient à une catégorie class Product < ActiveRecord::Base has_and_belongs_to_many :category end class Product < ActiveRecord::Base has_and_belongs_to_many :category end Une catégorie possède n produits et un produit n catégories ou
45
Les finder Product.find(:all, :conditions => { :price => 18 }) Product.find(:first) Product.find(:last) 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) Product.find_by_name(rails) Product.find_all_by_name(rails) Product.find_by_name_and_price(book, 18) Product.find(:all, :joins => :category, :conditions => { :categories => { :name => "books" }}) Product.find(:all, :joins => :category, :conditions => { :categories => { :name => "books" }}) Jointure:
46
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 :recent, lambda { { :conditions => ["created_at > ?", 5.days.ago] } } named_scope :limit, lambda { |n| { :limit => n } } named_scope :ordered_by_name, { :order => "NAME ASC" } named_scope :ordered_by_name, { :order => "NAME ASC" }end class Product < ActiveRecord::Base named_scope :recent, lambda { { :conditions => ["created_at > ?", 5.days.ago] } } named_scope :limit, lambda { |n| { :limit => n } } 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" } 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 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
47
Les validations class Product < ActiveRecord::Base belongs_to :category validates_presence_of :name, :category_id validates_numericality_of :price class Product < ActiveRecord::Base belongs_to :category validates_presence_of :name, :category_id validates_numericality_of :price et bien dautres: validates_confirmation_of validates_exclusion_of validates_format_oflidates_format_of valivalidates_inclusion_of validates_length_ofdates_length_of …
48
Le contrôleur avec ActionController Linterface entre le modèle et la vue Association automatique méthode / vue @variable directement disponible dans la vue Possibilité de filtrer des actions
49
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 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
50
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"} 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"}
51
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 endprivate def authenticate # do some stuff endend 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 endprivate def authenticate # do some stuff endend
52
La vue avec ActionView Les vues : pas forcément du HTML Layout Partials Helpers
53
Les types de vues i18n des vues app/views/products/index.fr.html.erb app/views/products/index.es.html.erb 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 app/views/products/index.iphone.erb app/views/products/index.xml.erb
54
Le layout Squelette de base app/views/layouts/application.html.erb Modifiable depuis le contrôleur
55
Les partials Des morceaux de vue <!DOCTYPE…><html><body> products/sidebar %> products/sidebar %> <!DOCTYPE…><html><body> app/views/products/_sidebar.html. erb
56
Exemple de vue: liste Listing categories Name 10) %> 'Are you sure?', :method => :delete %> Listing categories Name 10) %> 'Are you sure?', :method => :delete %>
57
Exemple de vue: édition | |
58
Autour de Rails Communauté active Autour de github Gems Authentification Pagination … config/environment.rb Rails::Initializer.run do |config| config.gem hpricot end Rails::Initializer.run do |config| config.gem hpricot end
59
Documentation http://www.rubyonrails.org/ http://guides.rubyonrails.org/ http://guides.rubyonrails.org http://apidock.com/rails http://railsforzombies.org/ http://groups.google.com/group/railsfran ce http://groups.google.com/group/railsfran ce
60
Merci, cest à vous ! Des questions ? _fuse mcatty@synbioz.commcatty@synbioz.com
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.