SlideShare uma empresa Scribd logo
1 de 44
Baixar para ler offline
Desenvolvimento
Web com Ruby on
Rails
João Lucas Pereira de Santana
gtalk | linkedin | twitter: jlucasps
Definindo Models
Vamos definir a entidade User para
representar os usuários de um sistema
Um usuário possui nome, email e idade.
@jlucasps
User
Active
Record
users
.......
aplicação rails banco de dados
Definindo Models
@jlucasps
users
name email age
users
id name email age created_at updated_at
Como criar a tabela no banco de dados utilizando o Rails ?
Migrations
Migrations disponibilizam uma forma
conveniênte para alterar o seu banco de dados
de uma maneira estruturada e organizada
ActiveRecord armazena quais migrations
foram executadas utilizando timestamps
Tudo o que precisamos fazer é atualizar o
código e executar $ rake db:migrate
Vamos analizar a anatomia de uma migration
@jlucasps
Migrations
@jlucasps
class CreateProducts < ActiveRecord::Migration
def up
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
def down
drop_table :products
end
end
release (up) e rollback (down)
Migrations
@jlucasps
release-rollback (change)
class AddSizeToProducts < ActiveRecord::
Migration
def change
add_column :products, :size, :integer, :null =>
:false
end
end
Rails consegue identificar rollback a partir da
release, bem como release a partir do rollback
release <-> rollback
Migrations
Migrations são subclasses de ActiveRecord::
Migration
Implementam dois métodos: up e down
(change)
E uma série de métodos auxiliares
@jlucasps
Migrations
ActiveRecord fornece métodos que executam
tarefas comuns de definição e manipulação de
dado.
Realizam esta tarefa de forma independente de
um banco de dados específico
@jlucasps
Data Definition Language (DDL)
CREATE
ALTER
DROP
Data Manipulation Language (DML)
SELECT
UPDATE
DELETE
Migrations
Métodos para definição de dados
@jlucasps
create_table(:name, options)
drop_table(:name)
rename_table(:old_name, :new_name)
add_column(:table_name, :column_name, :type,
options)
rename_column(:table_name, :column_name, :
new_column_name)
change_column(:table_name, :column_name, :type,
options)
remove_column(:table_name, :column_names)
add_index(:table_name, :column_names, options)
remove_index(:table_name, :column => :
column_name)
remove_index(:table_name, :name => :index_name)
Migrations
ActiveRecord suporta os seguintes tipos de
dados para colunas do banco:
@jlucasps
:binary
:boolean
:date
:datetime
:decimal
:float
:integer
:primary_key
:string
:text
:time
:timestamp
Migrations
Vamos gerar a Migration, implementá-la e
executá-la para criar a tabela users
@jlucasps
class CreateTableUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.column :name, :string
t.column :email, :string
t.column :age, :integer
t.timestamps
end
end
end
jlucasps@lotus:/media/first_app$ rails g migration
CreateUsersTable
invoke active_record
create db/migrate/20130613063127_create_users_table.rb
Migrations
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate
== CreateTableUsers: migrating
=============================================
==
-- create_table(:users)
-> 0.0491s
== CreateTableUsers: migrated (0.0492s)
======================================
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:rollback
== CreateTableUsers: reverting
==============================================
=
-- drop_table("users")
-> 0.0008s
== CreateTableUsers: reverted (0.0009s)
======================================
Criando Models
Vamos criar o model User para representar
entidades mapeadas na tabela users
@jlucasps
class User < ActiveRecord::Base
# Attrs accessible
attr_accessible :name, :email, :age
# Validations
# Associations
# Scopes
# Públic methods
end
Testes unitários nos models
Adicionar a gem shoulda e executar $ bundle install
Criar o arquivo /spec/models/user_spec.rb
@jlucasps
# -*- coding: utf-8 -*-
require 'spec_helper'
describe User do
it { should allow_mass_assignment_of :name }
it { should allow_mass_assignment_of :email }
it "creates an user" do
user = User.new(:name => "João Lucas", :email =>
"jlucasps@gmail.com", :age => 24)
user.save.should be_true
end
end
Testes unitários nos models
Executar $ rspec
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec
....FFF
Failures:
1) User
2) User
3) User creates an user
Finished in 0.35138 seconds
7 examples, 3 failures
Failed examples:
rspec ./spec/models/user_spec.rb:7 # User
rspec ./spec/models/user_spec.rb:6 # User
rspec ./spec/models/user_spec.rb:9 # User creates an user
Randomized with seed 10444
Testes unitários nos models
Executar $ rake db:test:load e $ rspec
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$
rake db:test:load
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$
rspec
.......
Finished in 0.41314 seconds
7 examples, 0 failures
$ git status
$ git add .
$ git commit -m "Testes unitários no modelo User"
Mudanças no negócio
E se quisermos que os campos nome e email
sejam obrigatórios?
@jlucasps
Mudanças no negócio
Vamos implementar testes para nossa nova regra
@jlucasps
# -*- coding: utf-8 -*-
require 'spec_helper'
describe User do
it { should allow_mass_assignment_of :name }
it { should allow_mass_assignment_of :email }
it "creates an user" do
user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :
age => 24)
user.save.should be_true
end
it "fail to create a user when name is blank" do
user = User.new(:email => "jlucasps@gmail.com", :age => 24)
user.save.should be_false
end
it "fail to create a user when email is blank" do
user = User.new(:name => "João Lucas", :age => 24)
user.save.should be_false
end
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec
.......FF
Failures:
1) User fail to create a user when name is blank
Failure/Error: user.save.should be_false
expected: false value
got: true
# ./spec/models/user_spec.rb:16:in `block (2 levels) in <top (required)>'
2) User fail to create a user when email is blank
Failure/Error: user.save.should be_false
expected: false value
got: true
# ./spec/models/user_spec.rb:21:in `block (2 levels) in <top (required)>'
Finished in 0.37949 seconds
9 examples, 2 failures
Failed examples:
rspec ./spec/models/user_spec.rb:14 # User fail to create a user when name
is blank
rspec ./spec/models/user_spec.rb:19 # User fail to create a user when email
is blank
Randomized with seed 46469
Mudanças no negócio
O que devemos implementar para o teste
passar?
Implementar alterações no banco (not null)
Implementar alterações no model (validations)
@jlucasps
jlucasps@lotus:/first_app$ rails g migration
NotNullToNameAndEmailToUsers
invoke active_record
create
db/migrate/20130613074955_not_null_to_name_and_email_to_users.rb
Mudanças no negócio
@jlucasps
class NotNullToNameAndEmailToUsers < ActiveRecord::Migration
def up
change_column :users, :name, :string, :null => false
change_column :users, :email, :string, :null => false
end
def down
change_column :users, :name, :string, :null => true
change_column :users, :email, :string, :null => true
end
end
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate
== NotNullToNameAndEmailToUsers: migrating
===================================
-- change_column(:users, :name, :string, {:null=>false})
-> 0.0106s
-- change_column(:users, :email, :string, {:null=>false})
-> 0.0038s
== NotNullToNameAndEmailToUsers: migrated (0.0146s)
==========================
Mudanças no negócio
@jlucasps
class User < ActiveRecord::Base
# Attrs accessible
attr_accessible :name, :email, :age
# Validations
validates :name, :presence => true, :allow_blank
=> false
validates :email, :presence => true, :allow_blank
=> false
# Associations
# Scopes
# Públic methods
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/truecrypt1/first_app$ rake db:
test:load
jlucasps@lotus:/media/truecrypt1/first_app$ rspec
.........
Finished in 0.50004 seconds
9 examples, 0 failures
Randomized with seed 2195
$ git status
$ git add .
$ git commit -m "Não permitir que sejam criados usuários
com nome ou email em branco."
Mudanças no negócio
Outra vez as regras mudaram, agora
precisamos adicionar um campo para opção
sexual do usuário.
*Não há necessidade do campo ser obrigatório
Quais os passos?
@jlucasps
Testes Código Refactoring
Mudanças no negócio
@jlucasps
# -*- coding: utf-8 -*-
require 'spec_helper'
describe User do
...................
...................
it "creates a user with gender value MALE" do
user = User.new(:name => "Bob Dylan", :email => "bob@dylan.
com", :age => 72, :gender => User::MALE)
user.save.should be_true
end
it "creates a user with gender value FEMALE" do
user = User.new(:name => "Candice Swanepoel", :email =>
"candice@swanepoel.com", :age => 24, :gender => User::FEMALE)
user.save.should be_true
end
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec
.......FF..
Failures:
1) User fail to create a user with gender value MALE
Failure/Error: user = User.new(:name => "Bob Dylan", :email =>
"bob@dylan.com", :age => 72, :gender => User::MALE)
NameError:
uninitialized constant User::MALE
# ./spec/models/user_spec.rb:25:in `block (2 levels) in <top (required)>'
2) User fail to create a user with gender value FEMALE
Failure/Error: user = User.new(:name => "Candice Swanepoel", :email =>
"candice@swanepoel.com", :age => 24, :gender => User::FEMALE)
NameError:
uninitialized constant User::FEMALE
# ./spec/models/user_spec.rb:30:in `block (2 levels) in <top (required)>'
Finished in 0.38009 seconds
11 examples, 2 failures
Failed examples:
rspec ./spec/models/user_spec.rb:24 # User fail to create a user with gender
value MALE
rspec ./spec/models/user_spec.rb:29 # User fail to create a user with gender
value FEMALE
Randomized with seed 23755
Mudanças no negócio
@jlucasps
class User < ActiveRecord::Base
# Attrs accessible
attr_accessible :name, :email, :age, :gender
# Constants
MALE = 1
FEMALE = 2
OTHER = 3
# Validations
validates :name, :presence => true, :allow_blank => false
validates :email, :presence => true, :allow_blank => false
# Associations
# Scopes
# Públic methods
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/first_app$ rails g migration
AddGenderToUsers gender:integer
invoke active_record
create db/migrate/20130613081853_add_gender_to_users.rb
class AddGenderToUsers < ActiveRecord::Migration
def change
add_column :users, :gender, :integer
end
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate
== AddGenderToUsers: migrating
===============================================
-- add_column(:users, :gender, :integer)
-> 0.0009s
== AddGenderToUsers: migrated (0.0010s)
======================================
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:test:load
...........
Finished in 0.38494 seconds
11 examples, 0 failures
Randomized with seed 52935
$ git status
$ git add .
$ git commit -m "Adicionando campo gender no modelo User."
Mudanças no negócio
E se for necessário informar o sexo caso a idade seja maior
ou igual a 18?
@jlucasps
context "when age >= 18" do
it "creates an user with gender value" do
user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 18, :
gender => User::MALE)
user.save.should be_true
end
it "does not create an user without gender value" do
user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 18)
user.save.should be_false
end
end
context "when age < 18" do
it "creates an user with gender value" do
user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 17, :
gender => User::MALE)
user.save.should be_true
end
it "does not create an user without gender value" do
user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 17)
user.save.should be_true
end
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec
...........F....
Failures:
1) User when age >= 18 does not create an user without gender
value
Failure/Error: user.save.should be_false
expected: false value
got: true
# ./spec/models/user_spec.rb:48:in `block (3 levels) in <top
(required)>'
Finished in 0.40493 seconds
16 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:46 # User when age >= 18 does
not create an user without gender value
Mudanças no negócio
@jlucasps
class User < ActiveRecord::Base
# Attrs accessible
attr_accessible :name, :email, :age, :gender
# Constants
MALE = 1
FEMALE = 2
OTHER = 3
# Validations
validates :name, :presence => true, :allow_blank => false
validates :email, :presence => true, :allow_blank => false
validates :gender, :presence => true, :if => :adulthood
# Associations
# Scopes
# Públic methods
def adulthood
age >= 18
end
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:
/media/truecrypt1/handsonrails/first_app$ rspec
................
Finished in 0.40208 seconds
16 examples, 0 failures
Randomized with seed 46088
$ git status
$ git add .
$ git commit -m "Necessário informar o sexo caso a idade seja maior ou igual
a 18."
Mudanças no negócio
@jlucasps
Vasmo modificar nosso código para que não
seja possível o cadastro de dois usuários com o
mesmo email.
Vale lembrar que, além da validação no
modelo, podemos também implementar uma
validação no banco de dados para garantir
unicidade de uma coluna.
No entanto, primeiro, vamos aos testes.
Mudanças no negócio
@jlucasps
Vamos adicionar o seguinte contexto à nossa
suite de testes e executar $ rspec
context "when tries to create two users with same email" do
it "create two users with differente emails" do
user_1 = User.create(:name => "Primeiro usuário", :email =>
"email_1@gmail.com")
user_2 = User.new(:name => "Segundo usuário", :email =>
"email_2@gmail.com")
user_2.save.should be_true
end
it "does no create two users with same emails" do
user_1 = User.create(:name => "Primeiro usuário", :email =>
"email_1@gmail.com")
user_2 = User.new(:name => "Segundo usuário", :email =>
"email_1@gmail.com")
user_2.save.should be_false
end
end
Mudanças no negócio
@jlucasps
Verificamos que foram reportados dois erros
que não esperávamos
1) User when tries to create two users with same email create two users with
differente emails
Failure/Error: user_1 = User.create(:name => "Primeiro usuário", :email
=> "email_1@gmail.com")
NoMethodError:
undefined method `>=' for nil:NilClass
# ./app/models/user.rb:21:in `adulthood'
# ./spec/models/user_spec.rb:68:in `block (3 levels) in <top (required)>'
2) User when tries to create two users with same email does no create two
users with same emails
Failure/Error: user_1 = User.create(:name => "Primeiro usuário", :email
=> "email_1@gmail.com")
NoMethodError:
undefined method `>=' for nil:NilClass
# ./app/models/user.rb:21:in `adulthood'
# ./spec/models/user_spec.rb:74:in `block (3 levels) in <top (required)>'
Mudanças no negócio
@jlucasps
Qual o motivo dos erros inesperados?
Vamos implementar alguns testes para o método
adulthood, verificar os erros e atualizar o código
describe "#adulthood" do
it "is adult when age == 18" do
user = User.new(:name => "Nome", :email => "email@gmail.com", :age => 18)
user.adulthood.should be_true
end
it "is adult when age > 18" do
user = User.new(:name => "Nome", :email => "email@gmail.com", :age => 30)
user.adulthood.should be_true
end
it "is not adult when age < 18" do
user = User.new(:name => "Nome", :email => "email@gmail.com", :age => 17)
user.adulthood.should be_false
end
it "is not adult when age is blank" do
user = User.new(:name => "Nome", :email => "email@gmail.com")
user.adulthood.should be_false
end
end
Mudanças no negócio
@jlucasps
Atualizando o model User
class User < ActiveRecord::Base
# Attrs accessible
attr_accessible :name, :email, :age, :gender
# Constants
MALE = 1
FEMALE = 2
OTHER = 3
# Validations
validates :name, :presence => true, :allow_blank => false
validates :email, :presence => true, :allow_blank => false
validates :gender, :presence => true, :if => :adulthood
# Associations
# Scopes
# Públic methods
def adulthood
self.age.present? and age >= 18
end
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec
............F.........
Failures:
1) User when tries to create two users with same email does no create two users
with same emails
Failure/Error: user_2.save.should be_false
expected: false value
got: true
# ./spec/models/user_spec.rb:76:in `block (3 levels) in <top (required)>'
Finished in 0.40533 seconds
22 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:73 # User when tries to create two users with
same email does no create two users with same emails
Randomized with seed 45305
Agora sim, encontramos o erro esperado na criação de
dois usuários com mesmo email.
Mudanças no negócio
@jlucasps
first_app$ rails g migration AddUniqueToEmail
class AddUniqueToEmail < ActiveRecord::
Migration
def change
add_index :users, :email, :unique => true
end
end
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate
== AddUniqueToEmail: migrating
===============================================
-- add_index(:users, :email, {:unique=>true})
-> 0.0009s
== AddUniqueToEmail: migrated (0.0010s)
========================================
Mudanças no negócio
@jlucasps
class User < ActiveRecord::Base
# Attrs accessible
attr_accessible :name, :email, :age, :gender
# Constants
MALE = 1
FEMALE = 2
OTHER = 3
# Validations
validates :name, :presence => true, :allow_blank => false
validates :email, :presence => true, :allow_blank => false
validates_uniqueness_of :email
validates :gender, :presence => true, :if => :adulthood
# Associations
# Scopes
# Públic methods
def adulthood
self.age.present? and age >= 18
end
end
Mudanças no negócio
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec
......................
Finished in 0.46128 seconds
22 examples, 0 failures
Randomized with seed 64622
$ git status
$ git add .
$ git commit -m "Validação de unicidade de email."
Mudanças no negócio
@jlucasps
Outras possíveis validações:
● formatos
● inclusão em uma lista, range
● exclusão
● formato
● presença
● números (inteiros, decimais)
● condicionais
● custom validations
Desenvolvimento
Web com Ruby on
Rails
João Lucas Pereira de Santana
gtalk | linkedin | twitter: jlucasps
Obrigado!

Mais conteúdo relacionado

Destaque

Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04Maurício Linhares
 
Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)Joao Lucas Santana
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Joao Lucas Santana
 
Desenvolvimento web com Ruby on Rails (parte 6)
Desenvolvimento web com Ruby on Rails (parte 6)Desenvolvimento web com Ruby on Rails (parte 6)
Desenvolvimento web com Ruby on Rails (parte 6)Joao Lucas Santana
 
Consultation on 16 19 vocational reform fa qs (5)
Consultation on 16 19 vocational reform fa qs (5)Consultation on 16 19 vocational reform fa qs (5)
Consultation on 16 19 vocational reform fa qs (5)amyclaire
 
Servidores de E-mail: Qmail, Sendmail e Postfix
Servidores de E-mail: Qmail, Sendmail e PostfixServidores de E-mail: Qmail, Sendmail e Postfix
Servidores de E-mail: Qmail, Sendmail e PostfixAlvaro Oliveira
 

Destaque (6)

Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04
 
Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)
 
Desenvolvimento web com Ruby on Rails (parte 6)
Desenvolvimento web com Ruby on Rails (parte 6)Desenvolvimento web com Ruby on Rails (parte 6)
Desenvolvimento web com Ruby on Rails (parte 6)
 
Consultation on 16 19 vocational reform fa qs (5)
Consultation on 16 19 vocational reform fa qs (5)Consultation on 16 19 vocational reform fa qs (5)
Consultation on 16 19 vocational reform fa qs (5)
 
Servidores de E-mail: Qmail, Sendmail e Postfix
Servidores de E-mail: Qmail, Sendmail e PostfixServidores de E-mail: Qmail, Sendmail e Postfix
Servidores de E-mail: Qmail, Sendmail e Postfix
 

Semelhante a Desenvolvimento web com Ruby on Rails (parte 3)

More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weiboshaokun
 
Rails Model Basics
Rails Model BasicsRails Model Basics
Rails Model BasicsJames Gray
 
Building Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModelBuilding Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModelpauldix
 
Building Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModelBuilding Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModelpauldix
 
Rails, Postgres, Angular, and Bootstrap: The Power Stack
Rails, Postgres, Angular, and Bootstrap: The Power StackRails, Postgres, Angular, and Bootstrap: The Power Stack
Rails, Postgres, Angular, and Bootstrap: The Power StackDavid Copeland
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”apostlion
 
Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)Joao Lucas Santana
 
Rails World 2023: Powerful Rails Features You Might Not Know
Rails World 2023: Powerful Rails Features You Might Not KnowRails World 2023: Powerful Rails Features You Might Not Know
Rails World 2023: Powerful Rails Features You Might Not KnowChris Oliver
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
えっ、なにそれこわい
えっ、なにそれこわいえっ、なにそれこわい
えっ、なにそれこわいKei Shiratsuchi
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Railsrstankov
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails Mohit Jain
 
Gmaps Railscamp2008
Gmaps Railscamp2008Gmaps Railscamp2008
Gmaps Railscamp2008xilinus
 

Semelhante a Desenvolvimento web com Ruby on Rails (parte 3) (20)

More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weibo
 
Rails Model Basics
Rails Model BasicsRails Model Basics
Rails Model Basics
 
Building Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModelBuilding Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModel
 
Building Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModelBuilding Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModel
 
Migrating legacy data
Migrating legacy dataMigrating legacy data
Migrating legacy data
 
Rails, Postgres, Angular, and Bootstrap: The Power Stack
Rails, Postgres, Angular, and Bootstrap: The Power StackRails, Postgres, Angular, and Bootstrap: The Power Stack
Rails, Postgres, Angular, and Bootstrap: The Power Stack
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”
 
Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)
 
TDC 2015 - DSLs em Ruby
TDC 2015 - DSLs em RubyTDC 2015 - DSLs em Ruby
TDC 2015 - DSLs em Ruby
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 
Rails World 2023: Powerful Rails Features You Might Not Know
Rails World 2023: Powerful Rails Features You Might Not KnowRails World 2023: Powerful Rails Features You Might Not Know
Rails World 2023: Powerful Rails Features You Might Not Know
 
Well
WellWell
Well
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
えっ、なにそれこわい
えっ、なにそれこわいえっ、なにそれこわい
えっ、なにそれこわい
 
Controller specs
Controller specsController specs
Controller specs
 
Beyond MVC
Beyond MVCBeyond MVC
Beyond MVC
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails
 
SOLID Ruby SOLID Rails
SOLID Ruby SOLID RailsSOLID Ruby SOLID Rails
SOLID Ruby SOLID Rails
 
Gmaps Railscamp2008
Gmaps Railscamp2008Gmaps Railscamp2008
Gmaps Railscamp2008
 

Último

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 

Último (20)

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 

Desenvolvimento web com Ruby on Rails (parte 3)

  • 1. Desenvolvimento Web com Ruby on Rails João Lucas Pereira de Santana gtalk | linkedin | twitter: jlucasps
  • 2. Definindo Models Vamos definir a entidade User para representar os usuários de um sistema Um usuário possui nome, email e idade. @jlucasps User Active Record users ....... aplicação rails banco de dados
  • 3. Definindo Models @jlucasps users name email age users id name email age created_at updated_at Como criar a tabela no banco de dados utilizando o Rails ?
  • 4. Migrations Migrations disponibilizam uma forma conveniênte para alterar o seu banco de dados de uma maneira estruturada e organizada ActiveRecord armazena quais migrations foram executadas utilizando timestamps Tudo o que precisamos fazer é atualizar o código e executar $ rake db:migrate Vamos analizar a anatomia de uma migration @jlucasps
  • 5. Migrations @jlucasps class CreateProducts < ActiveRecord::Migration def up create_table :products do |t| t.string :name t.text :description t.timestamps end end def down drop_table :products end end release (up) e rollback (down)
  • 6. Migrations @jlucasps release-rollback (change) class AddSizeToProducts < ActiveRecord:: Migration def change add_column :products, :size, :integer, :null => :false end end Rails consegue identificar rollback a partir da release, bem como release a partir do rollback release <-> rollback
  • 7. Migrations Migrations são subclasses de ActiveRecord:: Migration Implementam dois métodos: up e down (change) E uma série de métodos auxiliares @jlucasps
  • 8. Migrations ActiveRecord fornece métodos que executam tarefas comuns de definição e manipulação de dado. Realizam esta tarefa de forma independente de um banco de dados específico @jlucasps Data Definition Language (DDL) CREATE ALTER DROP Data Manipulation Language (DML) SELECT UPDATE DELETE
  • 9. Migrations Métodos para definição de dados @jlucasps create_table(:name, options) drop_table(:name) rename_table(:old_name, :new_name) add_column(:table_name, :column_name, :type, options) rename_column(:table_name, :column_name, : new_column_name) change_column(:table_name, :column_name, :type, options) remove_column(:table_name, :column_names) add_index(:table_name, :column_names, options) remove_index(:table_name, :column => : column_name) remove_index(:table_name, :name => :index_name)
  • 10. Migrations ActiveRecord suporta os seguintes tipos de dados para colunas do banco: @jlucasps :binary :boolean :date :datetime :decimal :float :integer :primary_key :string :text :time :timestamp
  • 11. Migrations Vamos gerar a Migration, implementá-la e executá-la para criar a tabela users @jlucasps class CreateTableUsers < ActiveRecord::Migration def change create_table :users do |t| t.column :name, :string t.column :email, :string t.column :age, :integer t.timestamps end end end jlucasps@lotus:/media/first_app$ rails g migration CreateUsersTable invoke active_record create db/migrate/20130613063127_create_users_table.rb
  • 12. Migrations @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate == CreateTableUsers: migrating ============================================= == -- create_table(:users) -> 0.0491s == CreateTableUsers: migrated (0.0492s) ====================================== jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:rollback == CreateTableUsers: reverting ============================================== = -- drop_table("users") -> 0.0008s == CreateTableUsers: reverted (0.0009s) ======================================
  • 13. Criando Models Vamos criar o model User para representar entidades mapeadas na tabela users @jlucasps class User < ActiveRecord::Base # Attrs accessible attr_accessible :name, :email, :age # Validations # Associations # Scopes # Públic methods end
  • 14. Testes unitários nos models Adicionar a gem shoulda e executar $ bundle install Criar o arquivo /spec/models/user_spec.rb @jlucasps # -*- coding: utf-8 -*- require 'spec_helper' describe User do it { should allow_mass_assignment_of :name } it { should allow_mass_assignment_of :email } it "creates an user" do user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 24) user.save.should be_true end end
  • 15. Testes unitários nos models Executar $ rspec @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec ....FFF Failures: 1) User 2) User 3) User creates an user Finished in 0.35138 seconds 7 examples, 3 failures Failed examples: rspec ./spec/models/user_spec.rb:7 # User rspec ./spec/models/user_spec.rb:6 # User rspec ./spec/models/user_spec.rb:9 # User creates an user Randomized with seed 10444
  • 16. Testes unitários nos models Executar $ rake db:test:load e $ rspec @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:test:load jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec ....... Finished in 0.41314 seconds 7 examples, 0 failures $ git status $ git add . $ git commit -m "Testes unitários no modelo User"
  • 17. Mudanças no negócio E se quisermos que os campos nome e email sejam obrigatórios? @jlucasps
  • 18. Mudanças no negócio Vamos implementar testes para nossa nova regra @jlucasps # -*- coding: utf-8 -*- require 'spec_helper' describe User do it { should allow_mass_assignment_of :name } it { should allow_mass_assignment_of :email } it "creates an user" do user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", : age => 24) user.save.should be_true end it "fail to create a user when name is blank" do user = User.new(:email => "jlucasps@gmail.com", :age => 24) user.save.should be_false end it "fail to create a user when email is blank" do user = User.new(:name => "João Lucas", :age => 24) user.save.should be_false end end
  • 19. Mudanças no negócio @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec .......FF Failures: 1) User fail to create a user when name is blank Failure/Error: user.save.should be_false expected: false value got: true # ./spec/models/user_spec.rb:16:in `block (2 levels) in <top (required)>' 2) User fail to create a user when email is blank Failure/Error: user.save.should be_false expected: false value got: true # ./spec/models/user_spec.rb:21:in `block (2 levels) in <top (required)>' Finished in 0.37949 seconds 9 examples, 2 failures Failed examples: rspec ./spec/models/user_spec.rb:14 # User fail to create a user when name is blank rspec ./spec/models/user_spec.rb:19 # User fail to create a user when email is blank Randomized with seed 46469
  • 20. Mudanças no negócio O que devemos implementar para o teste passar? Implementar alterações no banco (not null) Implementar alterações no model (validations) @jlucasps jlucasps@lotus:/first_app$ rails g migration NotNullToNameAndEmailToUsers invoke active_record create db/migrate/20130613074955_not_null_to_name_and_email_to_users.rb
  • 21. Mudanças no negócio @jlucasps class NotNullToNameAndEmailToUsers < ActiveRecord::Migration def up change_column :users, :name, :string, :null => false change_column :users, :email, :string, :null => false end def down change_column :users, :name, :string, :null => true change_column :users, :email, :string, :null => true end end jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate == NotNullToNameAndEmailToUsers: migrating =================================== -- change_column(:users, :name, :string, {:null=>false}) -> 0.0106s -- change_column(:users, :email, :string, {:null=>false}) -> 0.0038s == NotNullToNameAndEmailToUsers: migrated (0.0146s) ==========================
  • 22. Mudanças no negócio @jlucasps class User < ActiveRecord::Base # Attrs accessible attr_accessible :name, :email, :age # Validations validates :name, :presence => true, :allow_blank => false validates :email, :presence => true, :allow_blank => false # Associations # Scopes # Públic methods end
  • 23. Mudanças no negócio @jlucasps jlucasps@lotus:/media/truecrypt1/first_app$ rake db: test:load jlucasps@lotus:/media/truecrypt1/first_app$ rspec ......... Finished in 0.50004 seconds 9 examples, 0 failures Randomized with seed 2195 $ git status $ git add . $ git commit -m "Não permitir que sejam criados usuários com nome ou email em branco."
  • 24. Mudanças no negócio Outra vez as regras mudaram, agora precisamos adicionar um campo para opção sexual do usuário. *Não há necessidade do campo ser obrigatório Quais os passos? @jlucasps Testes Código Refactoring
  • 25. Mudanças no negócio @jlucasps # -*- coding: utf-8 -*- require 'spec_helper' describe User do ................... ................... it "creates a user with gender value MALE" do user = User.new(:name => "Bob Dylan", :email => "bob@dylan. com", :age => 72, :gender => User::MALE) user.save.should be_true end it "creates a user with gender value FEMALE" do user = User.new(:name => "Candice Swanepoel", :email => "candice@swanepoel.com", :age => 24, :gender => User::FEMALE) user.save.should be_true end end
  • 26. Mudanças no negócio @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec .......FF.. Failures: 1) User fail to create a user with gender value MALE Failure/Error: user = User.new(:name => "Bob Dylan", :email => "bob@dylan.com", :age => 72, :gender => User::MALE) NameError: uninitialized constant User::MALE # ./spec/models/user_spec.rb:25:in `block (2 levels) in <top (required)>' 2) User fail to create a user with gender value FEMALE Failure/Error: user = User.new(:name => "Candice Swanepoel", :email => "candice@swanepoel.com", :age => 24, :gender => User::FEMALE) NameError: uninitialized constant User::FEMALE # ./spec/models/user_spec.rb:30:in `block (2 levels) in <top (required)>' Finished in 0.38009 seconds 11 examples, 2 failures Failed examples: rspec ./spec/models/user_spec.rb:24 # User fail to create a user with gender value MALE rspec ./spec/models/user_spec.rb:29 # User fail to create a user with gender value FEMALE Randomized with seed 23755
  • 27. Mudanças no negócio @jlucasps class User < ActiveRecord::Base # Attrs accessible attr_accessible :name, :email, :age, :gender # Constants MALE = 1 FEMALE = 2 OTHER = 3 # Validations validates :name, :presence => true, :allow_blank => false validates :email, :presence => true, :allow_blank => false # Associations # Scopes # Públic methods end
  • 28. Mudanças no negócio @jlucasps jlucasps@lotus:/media/first_app$ rails g migration AddGenderToUsers gender:integer invoke active_record create db/migrate/20130613081853_add_gender_to_users.rb class AddGenderToUsers < ActiveRecord::Migration def change add_column :users, :gender, :integer end end
  • 29. Mudanças no negócio @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate == AddGenderToUsers: migrating =============================================== -- add_column(:users, :gender, :integer) -> 0.0009s == AddGenderToUsers: migrated (0.0010s) ====================================== jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:test:load ........... Finished in 0.38494 seconds 11 examples, 0 failures Randomized with seed 52935 $ git status $ git add . $ git commit -m "Adicionando campo gender no modelo User."
  • 30. Mudanças no negócio E se for necessário informar o sexo caso a idade seja maior ou igual a 18? @jlucasps context "when age >= 18" do it "creates an user with gender value" do user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 18, : gender => User::MALE) user.save.should be_true end it "does not create an user without gender value" do user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 18) user.save.should be_false end end context "when age < 18" do it "creates an user with gender value" do user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 17, : gender => User::MALE) user.save.should be_true end it "does not create an user without gender value" do user = User.new(:name => "João Lucas", :email => "jlucasps@gmail.com", :age => 17) user.save.should be_true end end
  • 31. Mudanças no negócio @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec ...........F.... Failures: 1) User when age >= 18 does not create an user without gender value Failure/Error: user.save.should be_false expected: false value got: true # ./spec/models/user_spec.rb:48:in `block (3 levels) in <top (required)>' Finished in 0.40493 seconds 16 examples, 1 failure Failed examples: rspec ./spec/models/user_spec.rb:46 # User when age >= 18 does not create an user without gender value
  • 32. Mudanças no negócio @jlucasps class User < ActiveRecord::Base # Attrs accessible attr_accessible :name, :email, :age, :gender # Constants MALE = 1 FEMALE = 2 OTHER = 3 # Validations validates :name, :presence => true, :allow_blank => false validates :email, :presence => true, :allow_blank => false validates :gender, :presence => true, :if => :adulthood # Associations # Scopes # Públic methods def adulthood age >= 18 end end
  • 33. Mudanças no negócio @jlucasps jlucasps@lotus: /media/truecrypt1/handsonrails/first_app$ rspec ................ Finished in 0.40208 seconds 16 examples, 0 failures Randomized with seed 46088 $ git status $ git add . $ git commit -m "Necessário informar o sexo caso a idade seja maior ou igual a 18."
  • 34. Mudanças no negócio @jlucasps Vasmo modificar nosso código para que não seja possível o cadastro de dois usuários com o mesmo email. Vale lembrar que, além da validação no modelo, podemos também implementar uma validação no banco de dados para garantir unicidade de uma coluna. No entanto, primeiro, vamos aos testes.
  • 35. Mudanças no negócio @jlucasps Vamos adicionar o seguinte contexto à nossa suite de testes e executar $ rspec context "when tries to create two users with same email" do it "create two users with differente emails" do user_1 = User.create(:name => "Primeiro usuário", :email => "email_1@gmail.com") user_2 = User.new(:name => "Segundo usuário", :email => "email_2@gmail.com") user_2.save.should be_true end it "does no create two users with same emails" do user_1 = User.create(:name => "Primeiro usuário", :email => "email_1@gmail.com") user_2 = User.new(:name => "Segundo usuário", :email => "email_1@gmail.com") user_2.save.should be_false end end
  • 36. Mudanças no negócio @jlucasps Verificamos que foram reportados dois erros que não esperávamos 1) User when tries to create two users with same email create two users with differente emails Failure/Error: user_1 = User.create(:name => "Primeiro usuário", :email => "email_1@gmail.com") NoMethodError: undefined method `>=' for nil:NilClass # ./app/models/user.rb:21:in `adulthood' # ./spec/models/user_spec.rb:68:in `block (3 levels) in <top (required)>' 2) User when tries to create two users with same email does no create two users with same emails Failure/Error: user_1 = User.create(:name => "Primeiro usuário", :email => "email_1@gmail.com") NoMethodError: undefined method `>=' for nil:NilClass # ./app/models/user.rb:21:in `adulthood' # ./spec/models/user_spec.rb:74:in `block (3 levels) in <top (required)>'
  • 37. Mudanças no negócio @jlucasps Qual o motivo dos erros inesperados? Vamos implementar alguns testes para o método adulthood, verificar os erros e atualizar o código describe "#adulthood" do it "is adult when age == 18" do user = User.new(:name => "Nome", :email => "email@gmail.com", :age => 18) user.adulthood.should be_true end it "is adult when age > 18" do user = User.new(:name => "Nome", :email => "email@gmail.com", :age => 30) user.adulthood.should be_true end it "is not adult when age < 18" do user = User.new(:name => "Nome", :email => "email@gmail.com", :age => 17) user.adulthood.should be_false end it "is not adult when age is blank" do user = User.new(:name => "Nome", :email => "email@gmail.com") user.adulthood.should be_false end end
  • 38. Mudanças no negócio @jlucasps Atualizando o model User class User < ActiveRecord::Base # Attrs accessible attr_accessible :name, :email, :age, :gender # Constants MALE = 1 FEMALE = 2 OTHER = 3 # Validations validates :name, :presence => true, :allow_blank => false validates :email, :presence => true, :allow_blank => false validates :gender, :presence => true, :if => :adulthood # Associations # Scopes # Públic methods def adulthood self.age.present? and age >= 18 end end
  • 39. Mudanças no negócio @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec ............F......... Failures: 1) User when tries to create two users with same email does no create two users with same emails Failure/Error: user_2.save.should be_false expected: false value got: true # ./spec/models/user_spec.rb:76:in `block (3 levels) in <top (required)>' Finished in 0.40533 seconds 22 examples, 1 failure Failed examples: rspec ./spec/models/user_spec.rb:73 # User when tries to create two users with same email does no create two users with same emails Randomized with seed 45305 Agora sim, encontramos o erro esperado na criação de dois usuários com mesmo email.
  • 40. Mudanças no negócio @jlucasps first_app$ rails g migration AddUniqueToEmail class AddUniqueToEmail < ActiveRecord:: Migration def change add_index :users, :email, :unique => true end end jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate == AddUniqueToEmail: migrating =============================================== -- add_index(:users, :email, {:unique=>true}) -> 0.0009s == AddUniqueToEmail: migrated (0.0010s) ========================================
  • 41. Mudanças no negócio @jlucasps class User < ActiveRecord::Base # Attrs accessible attr_accessible :name, :email, :age, :gender # Constants MALE = 1 FEMALE = 2 OTHER = 3 # Validations validates :name, :presence => true, :allow_blank => false validates :email, :presence => true, :allow_blank => false validates_uniqueness_of :email validates :gender, :presence => true, :if => :adulthood # Associations # Scopes # Públic methods def adulthood self.age.present? and age >= 18 end end
  • 42. Mudanças no negócio @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rspec ...................... Finished in 0.46128 seconds 22 examples, 0 failures Randomized with seed 64622 $ git status $ git add . $ git commit -m "Validação de unicidade de email."
  • 43. Mudanças no negócio @jlucasps Outras possíveis validações: ● formatos ● inclusão em uma lista, range ● exclusão ● formato ● presença ● números (inteiros, decimais) ● condicionais ● custom validations
  • 44. Desenvolvimento Web com Ruby on Rails João Lucas Pereira de Santana gtalk | linkedin | twitter: jlucasps Obrigado!