• Like
  • Save
Ruby on Rails at PROMPT ISEL '11
Upcoming SlideShare
Loading in...5
×
 

Ruby on Rails at PROMPT ISEL '11

on

  • 1,631 views

An introduction to Ruby on Rails. Presentation made at PROMP, a pos-graduation on ISEL university at Portugal.

An introduction to Ruby on Rails. Presentation made at PROMP, a pos-graduation on ISEL university at Portugal.

Statistics

Views

Total Views
1,631
Views on SlideShare
1,628
Embed Views
3

Actions

Likes
0
Downloads
18
Comments
0

1 Embed 3

http://www.linkedin.com 3

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Ruby on Rails at PROMPT ISEL '11 Ruby on Rails at PROMPT ISEL '11 Presentation Transcript

    • Web Development withRuby On RailsPedro Cunha
    • RubyYukihiro "Matz" Matsumoto Ruby is designed for programmer productivity and fun Created February 1993
    • RubyEverything 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)
    • Rubyclass 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) endend
    • Ruby"hello".class # String:hello.class # Symbol a = "Hello" b = "Hello"# Convention# Use string if you plan to a.equal? b # falsecompute text x = :hello# Use symbols if you want to y = :hellodefine or/and set abehaviour which is not x.equal? y # trueexpected to change
    • Rubya = {}a[:first] = 2a[:things] = 3a[:foo] = "bar"b = { :first => 2, :things => 3, :foo => "bar"}b[:first] # 2
    • Rubyx = [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 selfx.map{ |i| i + 4 } # [5,6,8,9,9,12,14]x.map! do |i| i + 4end # [5,6,8,9,9,12,14]
    • Ruby Monkey Patchingclass String def +() # override string default + operator endend “With great power comes great responsability” Uncle Ben, Amazing Spiderman nº1
    • Ruby on Rails
    • Ruby on RailsCreated by David Heinemeir Hansson• CEO at 37th Signals• Personal Project, 2004Present• Rails 3.1• Growing community
    • Ruby on RailsConvention vs ConfigurationMVC ArchitectureREST routing
    • Conventionvs 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
    • RESTRepresentational State Transfer
    • CRUD REST ROUTESCREATE POST /postsREAD GET /posts/1UPDATE PUT /posts/1DELETE DELETE /posts/1
    • # routes.rbBlog::Application.routes.draw do resources :postsend
    • RoRStarting development
    • pcunha:prompt$ rails new Blog -d mysqlBlog /app /controllers /mailers /models /views /config database.yml /db /migrate Gemfile /public /javascripts /stylesheets
    • # config/database.ymldevelopment: adapter: sqlite3 database: db/development.sqlite3test: adapter: sqlite3 database: db/test.sqlite3production: 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 indevelopment on http://0.0.0.0:3000=> Call with -d to detach=> Ctrl-C to shutdown server
    • localhost:3000
    • ModelDatabase 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.rbclass 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 endend
    • pcunha:Blog$ rake db:createpcunha: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.ymlpcunha:Blog$ rails generate migration AddPostIdToCommentspost_id:integer invoke active_record create db/migrate/20110715103834_add_post_id_to_comments.rb
    • # 20110715103834_add_post_id_to_comments.rbclass AddPostIdToComments < ActiveRecord::Migration def self.up add_column :comments, :post_id, :integer end def self.down remove_column :comments, :post_id endend
    • 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:createrake db:migraterake db:migrate:redorake db:rollbackblog_db.schema_migrations- keeps the version number of allmigrations already runned
    • Model Relations
    • # app/models/post.rbclass Post < ActiveRecord::Base has_many :commentsend# app/models/comment.rbclass Comment < ActiveRecord::Base belongs_to :postendPost.allPost.find(1).commentsComments.find(1).postPost.order(:created_at)Post.limit(5).offset(2)
    • Model Validations
    • # app/models/post.rbclass Post < ActiveRecord::Base has_many :comments validates_presence_of :title validates_format_of :title, :with => /ASLB.*z/endp = Post.newp.save # falsep.errors.full_messages # ["Title cant be blank", "Titleis invalid"]p.title = "SLB is the best"p.save # true
    • validates_presence_of :nifvalidates_format_of :namevalidates_acceptance_of :terms_and_conditions, :on => :createvalidates_numericality_of :age, :greater_than_or_equal_to => 18validates_uniqueness_of :model_fk_key, :scope => :model_fk_key2validates_length_of :minimum => 5
    • Controllers Managing the CRUD
    • # app/controllers/posts_controller.rbclass 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 wassuccessfully 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 endpcunha: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.rbdef 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 youlink_to Show, @post # GET posts/@post.idform_for(@post)if @post.new_record? POST /postselse PUT /posts/@post.idend
    • 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
    • AJAXImprove user experience
    • Improve user experience by not having thewhole page reload when submitting a formor simple pagination linkAlso save resources used (SQL queries,memory, more bandwidth usage,... etc)
    • AJAXChanging default forms to AJAX
    • # config/routes.rbBlog::Application.routes.draw do resources :posts do resources :comments, :only => [:create] endendPOST /posts/:post_id/comments Limiting actions is always the best practice
    • # app/controllers/comments_controller.rbclass 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 endend
    • # 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.rbclass 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 wassuccessfully created.) } format.js else format.html { render :action => "new" } format.js end end endend
    • # 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 defaultRails 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
    • RJSRuby (to) JavaScript Templates
    • # app/views/comments/create.js.rjsif @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].resetend
    • Gems
    • GemsExtend Rails frameworkEasy installation and usageIncreasing community • Github • Gemcutter
    • Bundler gem# Gemfilegem "rails", "2.3.10"gem "will_paginate"gem "authlogic"gem "pg"gem "postgis_adapter", "0.7.8"gem "GeoRuby", "1.3.4"# Sphinxgem "thinking-sphinx", "1.4.5"group :development do gem "capistrano" gem "capistrano-ext" gem "ruby-debug" gem "wirble" gem "mongrel"end
    • Questions ?
    • Referenceshttp://rubyonrails.org/http://railsapi.com/http://railscasts.com/http://railsforzombies.org/
    • References
    • Thanks :)pedro.cunha@rupeal.com @mryise