Desenvolvimento Web com Ruby on Rails (parte 6)

Desenvolvimento Web com Ruby on Rails (parte 6)

Desenvolvimento Web com Ruby on Rails

Transcript

  1. Desenvolvimento Web com Ruby on Rails João Lucas Pereira de

    Santana gtalk | linkedin | twitter: jlucasps
  2. Devise @jlucasps Solução flexível para autenticação de usuários Segue o

    padrão MVC Totalmente integrada com o Rails Permite várias roles autenticadas ao mesmo tempo (user, admin, member) Baseada em conceitos de módulos
  3. • Database Authenticatable ◦ Criptografar a senha e armazenar em

    banco de dados ◦ Auntenticação pode ser feita via POST ou HTTP Basic Authentication Devise @jlucasps
  4. • Token Authenticatable ◦ Autenticar o usuário baseado em um

    token de acesso ◦ Token pode ser enviado via query string ou HTTP Basic Authentication Devise @jlucasps
  5. Devise @jlucasps • Omniauthable ◦ Framework de autenticação compatível com

    diversos providers (facebook, twitter, openId, google, github), além dos tradicionais username e password
  6. Devise @jlucasps • Confirmable ◦ Enviar email com as instruções

    de confirmação de cadastro • Recoverable ◦ Alterar password do usuário e enviar instruções de alteração
  7. Devise @jlucasps • Registerable ◦ Permite cadastar usuários para utilizarem

    uma aplicação ◦ Editar as informações de cadastro do usuário ◦ Excluir o cadastro
  8. Devise @jlucasps • Rememberable ◦ Mecanimo para salvar cookies e

    permitir manter usuário autenticado na aplicação • Trackable ◦ Registrar quantidade de acessos, hora do acesso e IP de origem
  9. Devise @jlucasps • Timeoutable ◦ Expirar a sessão caso o

    usuário fique um período inativo • Validatable ◦ Validação de email e password ◦ Mecanismo opcional e customizável
  10. Devise @jlucasps • Lockable ◦ Bloquear a conta do usuário

    caso haja um certo número de tentativas frustradas de acesso ◦ Desbloqueio pode ser feito via email ou após um período de tempo
  11. Devise @jlucasps # https://github.com/plataformatec/devise # Flexible authentication solution for Rails

    with Warden gem 'devise' Atualizar Gemfile Atualizar config/environments/development.rb config.action_mailer.default_url_options = { :host => 'localhost:3000' }
  12. MailCatcher @jlucasps # https://github.com/sj26/mailcatcher # Catches mail and serves it

    through a dream. gem 'mailcatcher' Adicionar MailCatcher ao Gemfile Atualizar config/environments/development.rb config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :address => "localhost", : port => 1025 } jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ mailcatcher Starting MailCatcher ==> smtp://127.0.0.1:1025 ==> http://127.0.0.1:1080 *** MailCatcher runs as a daemon by default. Go to the web interface to quit.
  13. Devise @jlucasps Após adicionar Devise ao Gemfile, execute o generator

    jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rails g devise: install create config/initializers/devise.rb create config/locales/devise.en.yml =========================================== ==================== Some setup you must do manually if you haven't yet: ....
  14. Devise @jlucasps <!DOCTYPE html> <html> <head> <title>FirstApp</title> <%= stylesheet_link_tag "application",

    :media => "all" %> <%= javascript_include_tag "application" %> <%= csrf_meta_tags %> </head> <body> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <%= render :partial => 'shared/menu_top' %> <div class="container-fluid"> <div class="row-fluid"> <%= yield :sidebar %> <%= yield %> </div> <%= render :partial => 'shared/footer' %> </div> </body> </html> Configurar /app/views/layouts/application.html.erb
  15. Devise @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rails g devise User invoke active_record create

    db/migrate/20130619172147_add_devise_to_users.rb insert app/models/user.rb route devise_for :users Adicionar Devise a algum model Configurar Migration gerada e executá-la jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate == AddDeviseToUsers: migrating =============================================== -- change_table(:users) -> 0.0590s -- add_index(:users, :reset_password_token, {:unique=>true}) -> 0.0007s == AddDeviseToUsers: migrated (0.0600s) ======================================
  16. Devise @jlucasps class ApplicationController < ActionController::Base protect_from_forgery before_filter :authenticate_user! end

    Configurar ApplicationController Configurar arquivo /config/initializers/devise.rb # ==> Scopes configuration # Turn scoped views on. Before rendering "sessions/new", it will first check for # "users/sessions/new". It's turned off by default because it's slower if you # are using only default views. config.scoped_views = true
  17. Devise @jlucasps user_signed_in? current_user user_session Métodos helpers gerados pelo Devise

    Caso o model seja Member before_filter :authenticate_member! member_signed_in? current_member member_session
  18. Devise @jlucasps jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rails generate devise:views users invoke Devise::Generators::SharedViewsGenerator create

    app/views/users/shared create app/views/users/shared/_links.erb invoke form_for create app/views/users/confirmations create app/views/users/confirmations/new.html.erb create app/views/users/passwords create app/views/users/passwords/edit.html.erb Customizar as views utilizadas pelo Devise
  19. Devise @jlucasps class WelcomeController < ApplicationController before_filter :authenticate_user!, :except =>

    [:index, :about, :contact] def index end def black render :layout => 'application_black' end def about end def contact end end Caso queira liberar acesso para actions do WelcomeController
  20. Devise @jlucasps <div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inner"> <div class="container-fluid">

    <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <%= link_to "Project name", index_path, :class => "brand" %> <div class="nav-collapse collapse"> <p class="navbar-text pull-right"> <% if user_signed_in? %> Logged in as <%= link_to current_user.name edit_user_registration_path(current_user), : class => "navbar-link" %> <% else %> <%= link_to "login", new_user_session_path, :class => "btn" %> <% end %> </p> <ul class="nav"> <li class="active"><%= link_to "Home", index_path %></li> <li><%= link_to "About", about_path %></li> <li><%= link_to "Contact", contact_path %></li> </ul> </div><!--/.nav-collapse --> </div> </div> </div> Exibir link para login e usuário logado: /app/views/shared/_menu_top.html.erb
  21. Devise @jlucasps <h2>Sign up</h2> <%= form_for(resource, :as => resource_name, :url

    => registration_path (resource_name)) do |f| %> <%= devise_error_messages! %> <div><%= f.label :name %><br /> <%= f.text_field :name, :autofocus => true %></div> <div><%= f.label :email %><br /> <%= f.email_field :email %></div> <div><%= f.label :password %><br /> <%= f.password_field :password %></div> <div><%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation %></div> <div><%= f.submit "Sign up" %></div> <% end %> <%= render "users/shared/links" %> Alterar tela de cadastro de usuários: /app/views/users/registrations/new.html.erb
  22. Devise @jlucasps RSpec.configure do |config| # ## Mock Framework #

    # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: # # config.mock_with :mocha # config.mock_with :flexmock # config.mock_with :rr config.include Capybara::DSL config.include Devise::TestHelpers, :type => :controller config.include Rails.application.routes.url_helpers # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures #config.fixture_path = "#{::Rails.root}/spec/fixtures" Testes automatizados com Devise: /spec/spec_helper.rb
  23. Devise @jlucasps include Warden::Test::Helpers def create_logged_in_user(user_sym) user = FactoryGirl.find_or_create(user_sym) login_as(user,

    scope: :user) user end class ActiveRecord::Base mattr_accessor :shared_connection @@shared_connection = nil def self.connection @@shared_connection || retrieve_connection end end ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection Devise support /spec/support/devise.rb
  24. FactoryGirl @jlucasps # Factory_girl is a fixtures replacement with a

    straightforward definition syntax # https://github.com/thoughtbot/factory_girl_rails gem 'factory_girl_rails', "~> 4.0" Adicionar factory_girl ao Gemfile Importar factory_girl no spec_helper # This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'rspec/autorun' require 'factory_girl' require 'factory_girl_patch' require 'capybara/rails' require 'capybara/rspec' FactoryGirl.register_strategy(:find_or_create, FactoryGirlPatch)
  25. FactoryGirl @jlucasps FactoryGirl.define do factory :user_bart, :class => User do

    name "Bart Simpson" email "bart@simpson.com" password "dirty_boy" password_confirmation "dirty_boy" encrypted_password BCrypt::Password.create("dirty_boy", :cost => 10) end factory :user_lisa, :class => User do name "Lisa Simpson" email "lisa@simpson.com" password "smart_girl" password_confirmation "smart_girl" encrypted_password BCrypt::Password.create("smart_girl", :cost => 10) end end Criar factories
  26. FactoryGirl @jlucasps class FactoryGirlPatch def association(runner) runner.run end def result(evaluation)

    evaluation.object.tap do |instance| evaluation.notify(:after_build, instance) evaluation.notify(:before_create, instance) saved_object = instance.class.where(instance.attributes.except("id", "created_at", "updated_at")).first if saved_object.present? instance.id = saved_object.id instance.created_at = saved_object.created_at if instance.respond_to?(:created_at) instance.updated_at = saved_object.updated_at if instance.respond_to?(:updated_at) else evaluation.create(instance) evaluation.notify(:after_create, instance) end end end end Estratégia find_or_create: /lib/factory_girl_patch.rb
  27. Devise @jlucasps require 'spec_helper' describe UsersController do let(:user_bart) { FactoryGirl.find_or_create(:user_bart)}

    before(:each) do sign_in user_bart end describe "GET index" do it "assigns @users" do saved_users = [FactoryGirl.find_or_create(:user_bart), FactoryGirl.find_or_create(: user_lisa)] get :index assigns(:users).should eq(saved_users) end end end Testes no controller /spec/controllers/users_controller_spec.rb
  28. Devise @jlucasps Testes no controller /spec/controllers/users_controller_spec.rb jlucasps@lotus:/media/first_app$ rspec spec/controllers/users_controller_spec.rb .

    Finished in 0.331 seconds 1 example, 0 failures Randomized with seed 5290
  29. Desenvolvimento Web com Ruby on Rails João Lucas Pereira de

    Santana gtalk | linkedin | twitter: jlucasps Obrigado!