Ruby on Rails

Conceptos básicos

Fernando Blat & Fernando García & Álvaro Ortiz

The Cocktail

Ruby on Rails

Ciclo de vida de una petición HTTP

Ciclo de vida de una petición Rails

Libro

Imagen del libro de Rails
No hay versión on-line, sólo de pago

Documentación

Instalación

Estructura de directorios

$ rails demostracion

...

Estructura de directorios (ii)

...

Estructura de directorios (iii)

Estructura de directorios (iv)

Entornos de ejecución

Configuración

Ciclo de vida de una petición HTTP

Ciclo de vida de una petición Rails

Active Record

Active Record

Convención vs. Configuración

Se puede forzar con una simple línea:

class Person < ActiveRecord::Base
  set_table_name "person"
end
	

Convención vs. Configuración (ii)

CREATE TABLE clients (
  id           int NOT NULL auto_increment,
  nif          varchar(10) NOT NULL default '',
  razon_social varchar(128) NOT NULL default'',
  alias        varchar(128) default '',
  nombre       varchar(128) default '',
  apellido     varchar(128) default '',
  PRIMARY KEY  (id),
  UNIQUE KEY nif (nif)
);
	
c = Client.new
c.nif = '12 456 567'
c.razon_social = 'Transportes Luis'
c.save
	

Convención vs. Configuración (iii)

class Client < ActiveRecord::Base
end
	

¿Y la definición de atributos?

Don't Repeat Yourself!

Mapeo de atributos

Claves primarias e IDs

class Client < ActiveRecord::Base
  set_primary_key 'nif'
end
	

CRUD - Create, Read, Update, Delete

CRUD - Create

CRUD - Read

client = Client.find(3)

clients = Client.find(:all, :conditions => 'ciudad = Madrid', 
		:order => 'nombre ASC', 
		:limit => 10)

client = Client.find(:first, :conditions => 'ciudad = Madrid', 
		:order => 'nombre DESC')

clients = Client.find_by_sql("select * from clients 
		where num_telefono like '91%'")
	

CRUD - Update

client = Client.update(4, :nombre => 'Fernando A.', 
		:num_fax => '14343343')

clients = Client.update_all("descuento = 1.1*descuento", 
		"ciudad = 'madrid'")
	

CRUD - Delete

Client.delete(4)

Client.delete_all("ciudad = 'madrid'")
	

Relaciones

CREATE TABLE `proposals` (
  `id` int NOT NULL auto_increment,
  `client_id` int NOT NULL default '0',
  ...
	

Relaciones: uno-a-uno

class Contract < ActiveRecord::Base
  belongs_to :proposal
end

class Proposal < ActiveRecord::Base
  has_one :contract
end

p = Proposal.new
p.contract = Contract.new...
		

Relaciones: uno-a-muchos

class Client < ActiveRecord::Base
  has_many :proposals
end

class Proposal < ActiveRecord::Base
  belongs_to :client
end

c = Client.find(3)
c.proposals.each { |proposal| print proposal.estado 
	 		if proposal.estado == 'Aceptada' }
		

Relaciones: muchos-a-muchos

class Client < ActiveRecord::Base
  has_and_belongs_to_many :proposals
end

class Proposal < ActiveRecord::Base
  has_and_belongs_to_many :clients
end
		

Relaciones: muchos-a-muchos (ii)

CREATE TABLE clients_proposals (
  client_id int NOT NULL auto_increment,
  proposal_id int NOT NULL auto_increment,
  PRIMARY KEY  (client_id, proposal_id)
)
		

Validación de datos

class Client < ActiveRecord::Base
  has_many :proposals

  validates_length_of :codigo_postal, :is => 5
  validates_presence_of :nif, :razon_social
end
		

Validación de datos (ii)

Validación de datos (iii)

Validación de datos (iv)

class Client < ActiveRecord::Base

  validates_format_of :longitud , :with => /^\d+(cm|px|em)/

  validates_inclusion_of  :estado,
                          :in => %w{Aceptada Recibida}

end
		

Action Controller

Ciclo de vida de una petición HTTP

Ciclo de vida de una petición Rails

Action Controller

Métodos del controlador

http://tuapp.com/clients/list

app/controllers/clients_controller.rb

  def list
    @clients = Client.find(:all)
  end
	

Métodos del controlador (ii)

app/views/clients/list.rhtml

...
<% @clients.each do |client| %>

  <td><%= client.name %></td>

<% end %>
...
	

Métodos del controlador (iii)

  def create
    @client = Client.new(params[:client])
    if @client.save
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
	

Métodos del controlador (iv)

  def create
    @client = Client.new(params[:client])
    if @client.save
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
	

Ejemplo de creación

método new » vista new » método create

  def new
    @client = Client.new
  end
	

Ejemplo de creación (ii)

método new » vista new » método create

<form action="/clients/create" method="post">

  <p><label for="client_nif">Nif</label><br/>
  <input id="client_nif" name="client[nif]" size="30" 
  type="text" value="" /></p>

  <p><label for="client_razon_social">Razón social</label><br/>
  <input id="client_razon_social" name="client[razon_social]"
   size="30" type="text" value="" /></p>

  <input name="commit" type="submit" value="Create" />
</form>
	

Ejemplo de creación (iii)

método new » vista new » método create

  def create
    @client = Client.new(params[:client])
    if @client.save
      flash[:notice] = 'Client was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
  end
	

Paso de parámetros

Después de la llamada a Client.new

params = { 'client' => {:nombre => 'Luis', 
			:telefono => '914562123', 
			:nif => '12345323N' }, 
	'action' => 'create' , 
	'controller' => 'clients' }		


params[:client]
params[:action]
params[:controller]
	

Las URIs en Rails

Redirigiendo rutas en Rails

routes.rb

  map.connect ':username/contacto', :controller => 'users', 
	:action =>'contact'

  map.connect 'users/:action/:id', :username=>'ap', 
	:controller => 'users'

  map.connect 'ver/*nicetitles', :username=>'ap', 
	:controller => 'pageposts', 
	:action => 'route'

  map.connect 'programa/:year/:month/:day/:id', 
	:username => 'ap', 
	:controller => 'programmeposts', 
	:action => 'post'
	

Rutas con nombre

routes.rb

  map.programa 'programa/:year/:month/:day/:id', 
	:username => 'ap', 
	:controller => 'programmeposts', 
	:action => 'post'

  programa_url(:year => '2005', :month => '12', 
	:day => '20', :id => '5')
		
	» http://tu.url.com/programa/2005/12/20/5

	

El objeto Flash

  def create
    @client = Client.new(params[:client])
    if @client.save
      flash[:notice] = 'Client was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
  end
	

Filtros

class ClientsController < ApplicationController

  before_filter :authorize, :only => [ :admin_views, :create, 
					:update, :delete ]

  def authorize
    if not session[:user_id]
      flash[:notice] = "Por favor, identifícate"
      redirect_to :controller => 'user', :action => 'login'
    end
  end
	

Sesiones

def login
  user = User.find(:first, 
		:conditions => "name = '#{params[:name]}' 
			and password = '#{params[:password]}'")
  if user
    session[:user_id] = user.id
    redirect_to :action => 'index'
  else
    reset_session
    flash[:note] = 'Nombre de usuario o contraseña inválidos'
  end

end
	

Action View

Ciclo de vida de una petición HTTP

Ciclo de vida de una petición Rails

ActionView

RHTML básico

app/views/clients/view.rhtml

...
<% @clients.each do |client| %>

  <td><%= client.name %></td>

<% end %>
...
  

Helpers

Helpers de formateo

<%= human_size 34567 %> » 35 kb

<%= time_ago_in_words Time.local(2004,10,13) %> » 470 days

<%= number_with_precision 65.0/3, 3 %> 	» 21.667

<%= truncate program.name, 20 %> 	» La cocina de Arg... 
	

Helpers de HTML

<%= link_to 'Eliminar', :action => 'delete' %>

<%= link_to 'Eliminar', 
	{:action => 'delete', :controller => 'clients'}, 
	{:class => 'enlace-home', :confirm => '¿Estás seguro?'} 
%>

<%= image_tag "images/home.png", :class => "img-small", 
		:size => "320x240" %>

<%= image_tag "home", :class => "img-small", 
		:size => "320x240" %>

<%= mail_to "soporte@tecnicos.com", "Servicio Técnico", 
		:subject => 'Avería' %>
	

Paginadores

def list
  @client_pages, @clients = paginate :clients, :per_page => 10
end
		

<%= pagination_links @client_pages %>
		

El resultado

Helpers de formularios

<%= start_form_tag :action => 'create' %>

  <p><label for="client_nif">Nif</label><br/>
  <%= text_field 'client', 'nif'  %></p>

  <p><label for="client_razon_social">Razón social</label><br/>
  <%= text_field 'client', 'razon_social'  %></p>

  <%= submit_tag "Create" %>

<%= end_form_tag %>
	

Helpers de formularios (ii)

<form action="/clients/create" method="post">

  <p><label for="client_nif">Nif</label><br/>
  <input id="client_nif" name="client[nif]" size="30" 
	type="text" value="" /></p>

  <p><label for="client_razon_social">Razón social</label><br/>
  <input id="client_razon_social" name="client[razon_social]"
	 size="30" type="text" value="" /></p>

  <input name="commit" type="submit" value="Create" />
</form>
		

Helpers de formularios (iii)

params = { 'client' => {:nif => '12345323N', 
			:razon_social => 'Pinturas Esponja' }, 
	 'action' => 'create'}
	

Helpers de formularios (iv)

Helpers de formularios (v)

<p><label for="proposal_estado">Estado</label><br/>
<%= 
 select :proposal, :estado, %w{Aceptada Recibida Preparación} 
%></p>
	

Layouts

Layouts (ii)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 
 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html lang="es">
<head>
  <title>Maitre</title>
</head>

<body>
  <div class="message">
    <%= flash['note'] %>
  </div>

  <%= @content_for_layout %>

</body>
		

Active Support

Active Support

Ejemplo

now = Time.now
puts now 		» Sun Jan 29 11:02:54 CET 2006
puts 20.minutes.ago 	» Sun Jan 29 10:43:29 CET 2006
puts 3.days.ago 	» Thu Jan 26 11:03:45 CET 2006
puts now.at_midnight 	» Sun Jan 29 00:00:00 CET 2006
puts now.next_week 	» Mon Jan 30 00:00:00 CET 2006
puts now.tomorrow 	» Mon Jan 30 11:02:54 CET 2006
puts now.tomorrow.tomorrow » Tue Jan 31 11:02:54 CET 2006