Screencast: Testen von Password-Reset und Erinnerung

In der letzten Woche zeigte Ryan wie man selber eine Funktion zum Zurücksetzen von Passwörter bauen kann. In dieser Woche zeigt er wie er diese Funktion mit RSpec, Capybara, Factory Girl und Guard testet.

 

Downloads in verschiedenen Formaten:

source code
mp4
m4v
webm
ogv

 

Resourcen:

bash

[bash]
bundle rails g rspec:install mkdir spec/support spec/models spec/routing guard init rspec gem install rb-fsevent rails g integration_test password_reset rails g controller password_resets new –no-test-framework rails g mailer user_mailer password_reset rails g migration add_password_reset_to_users password_reset_token:string password_reset_sent_at:datetime rake db:migrate
[/bash]

Gemfile

[ruby]
gem "rspec-rails", :group => [:test, :development] group :test do gem "factory_girl_rails" gem "capybara" gem "guard-rspec" end
[/ruby]

spec_helper.rb

[ruby]
require ‚capybara/rspec‘ RSpec.configure do |config| # … config.include(MailerMacros) config.before(:each) { reset_email } end
[/ruby]

spec/support/mailer_macros.rb

[ruby]
module MailerMacros def last_email ActionMailer::Base.deliveries.last end def reset_email ActionMailer::Base.deliveries = [] end end
[/ruby]

config/environments/test.rb

[ruby]
config.action_mailer.default_url_options = { :host => "www.example.com" }
[/ruby]

spec/requests/password_resets_spec.rb

[ruby]
describe "PasswordResets" do it "emails user when requesting password reset" do user = Factory(:user) visit login_path click_link "password" fill_in "Email", :with => user.email click_button "Reset Password" current_path.should eq(root_path) page.should have_content("Email sent") last_email.to.should include(user.email) end it "does not email invalid user when requesting password reset" do visit login_path click_link "password" fill_in "Email", :with => "nobody@example.com" click_button "Reset Password" current_path.should eq(root_path) page.should have_content("Email sent") last_email.should be_nil end it "updates the user password when confirmation matches" do user = Factory(:user, :password_reset_token => "something", :password_reset_sent_at => 1.hour.ago) visit edit_password_reset_path(user.password_reset_token) fill_in "Password", :with => "foobar" click_button "Update Password" page.should have_content("Password doesn’t match confirmation") fill_in "Password", :with => "foobar" fill_in "Password confirmation", :with => "foobar" click_button "Update Password" page.should have_content("Password has been reset") end it "reports when password token has expired" do user = Factory(:user, :password_reset_token => "something", :password_reset_sent_at => 5.hour.ago) visit edit_password_reset_path(user.password_reset_token) fill_in "Password", :with => "foobar" fill_in "Password confirmation", :with => "foobar" click_button "Update Password" page.should have_content("Password reset has expired") end it "raises record not found when password token is invalid" do lambda { visit edit_password_reset_path("invalid") }.should raise_exception(ActiveRecord::RecordNotFound) end end
[/ruby]

spec/models/user_spec.rb

[ruby]
describe User do describe "#send_password_reset" do let(:user) { Factory(:user) } it "generates a unique password_reset_token each time" do user.send_password_reset last_token = user.password_reset_token user.send_password_reset user.password_reset_token.should_not eq(last_token) end it "saves the time the password reset was sent" do user.send_password_reset user.reload.password_reset_sent_at.should be_present end it "delivers email to user" do user.send_password_reset last_email.to.should include(user.email) end end end
[/ruby]

spec/mailers/user_mailer_spec.rb

[ruby]
describe UserMailer do describe "password_reset" do let(:user) { Factory(:user, :password_reset_token => "anything") } let(:mail) { UserMailer.password_reset(user) } it "send user password reset url" do mail.subject.should eq("Password Reset") mail.to.should eq([user.email]) mail.from.should eq(["from@example.com"]) mail.body.encoded.should match(edit_password_reset_path(user.password_reset_token)) end end end
[/ruby]

Rails AntiPatterns: Best Practice Ruby on Rails Refactoring

The Complete Guide to Avoiding and Fixing Common Rails 3 Code and Design Problems As developers worldwide have adopted the powerful Ruby on Rails web framework, many have fallen victim to common mistakes that reduce code quality, performance, reliability, stability, scalability, and maintainability. Railsa AntiPatterns identifies these widespread Rails code and design problems, explains why they’re bad and why they happen–and shows exactly what to do instead.

The book is organized into concise, modular chapters–each outlines a single common AntiPattern and offers detailed, cookbook-style code solutions that were previously difficult or impossible to find. Leading Rails developers Chad Pytel and Tammer Saleh also offer specific guidance for refactoring existing bad code or design to reflect sound object-oriented principles and established Rails best practices. With their help, developers, architects, and testers can dramatically improve new and existing applications, avoid future problems, and establish superior Rails coding standards throughout their organizations. This book will help you understand, avoid, and solve problems with.

  • Model layer code, from general object-oriented programming violations to complex SQL and excessive redundancy
  • Domain modeling, including schema and database issues such as normalization and serialization
  • View layer tools and conventions
  • Controller-layer code, including RESTful code
  • Service-related APIs, including timeouts, exceptions, backgrounding, and response codes
  • Third-party code, including plug-ins and gems
  • Testing, from test suites to test-driven development processes
  • Scaling and deployment
  • Database issues, including migrations and validations
  • System design for „graceful degradation“ in the real world.

Screencast: Refactoring und Dynamic Delegator

Code Refactoring ist der Prozess bei dem ein Programm modifiziert (optimiert, verbessert) wird ohne sein Verhalten nach aussen zu verändern. Diese Woche zeigt Ryan wie Refactoring eingesetzt werden kann und wie man Dynamic Delegator in Active Recors nutzt.

 

Download:

Download (11.2 MB, 7:58)
Alternativer Download für iPod & Apple TV (10.9 MB, 7:58)

 

Resourcen:

 

Quellcode:

[ruby]
# rails console
Product.search({}).class
Object.instance_methods
BasicObject.instance_methods

# products_controller.rb
@products = Product.search(params)

# models/product.rb
def self.search(params)
products = scope_builder
products.where("name like ?", "%" + params[:name] + "%") if params[:name]
products.where("price >= ?", params[:price_gt]) if params[:price_gt]
products.where("price <= ?", params[:price_lt]) if params[:price_lt]
products
end

def self.scope_builder
DynamicDelegator.new(scoped)
end

# lib/dynamic_delegator.rb
class DynamicDelegator < BasicObject
def initialize(target)
@target = target
end

def method_missing(*args, &block)
result = @target.send(*args, &block)
@target = result if result.kind_of? @target.class
result
end
end
[/ruby]

Refactoring: Ruby Edition

The Definitive Refactoring Guide, Fully Revamped for Ruby With refactoring, programmers can transform even the most chaotic software into well-designed systems that are far easier to evolve and maintain. What’s more, they can do it one step at a time, through a series of simple, proven steps. Now, there’s an authoritative and extensively updated version of Martin Fowler’s classic refactoring book that utilizes Ruby examples and idioms throughout–not code adapted from Java or any other environment.

The authors introduce a detailed catalog of more than 70 proven Ruby refactorings, with specific guidance on when to apply each of them, step-by-step instructions for using them, and example code illustrating how they work. Many of the authors‘ refactorings use powerful Ruby-specific features, and all code samples are available for download. Leveraging Fowler’s original concepts, the authors show how to perform refactoring in a controlled, efficient, incremental manner, so you methodically improve your code’s structure without introducing new bugs. Whatever your role in writing or maintaining Ruby code, this book will be an indispensable resource. This book will help you / Understand the core principles of refactoring and the reasons for doing it / Recognize „bad smells“ in your Ruby code / Rework bad designs into well-designed code, one step at a time / Build tests to make sure your refactorings work properly / Understand the challenges of refactoring and how they can be overcome / Compose methods to package code properly / Move features between objects to place responsibilities where they fit best / Organize data to make it easier to work with / Simplify conditional expressions and make more effective use of polymorphism / Create interfaces that are easier to understand and use / Generalize more effectively / Perform larger refactorings that transform entire software systems and may take months or years / Successfully refactor Ruby on Rails code