Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ten Years of Rails Tutorials (RailsConf 2018)

Ten Years of Rails Tutorials (RailsConf 2018)

Come see how Rails has evolved over the years through the lens of introductory Rails tutorials. Marvel at Rails pre-REST, survive the merger with Merb, feel the joy & pain of the then-new asset pipeline, and watch testing techniques grow, evolve, and simplify. Leave with a deeper appreciation for where Rails came from and where it is today.

Avatar for Michael Hartl

Michael Hartl

April 24, 2018
Tweet

More Decks by Michael Hartl

Other Decks in Programming

Transcript

  1. 1 <?php echo "<html>" ?> 2 <?php echo "<head>" ?>

    3 <?php echo "<script src='site.js'></script>" ?> 4 <?php echo "</head>" ?> 5 <?php echo "<body>" ?> 6 <?php echo "<h1>Hello $name</h1>" ?> 7 <?php echo "<p>Hello, world!</p>" ?> 8 <?php echo "</body>" ?> 9 <?php echo "</html>" ?>
  2. 1 create table users ( 2 id int not null

    auto_increment, 3 name varchar(100) not null, 4 hashed_password char(40) null, 5 primary key (id) 6 );
  3. 1 # app/models/user.rb 2 class User < ActiveRecord::Base 3 validates_uniqueness_of

    :screen_name, :email 4 validates_length_of :screen_name, :within => 4..20 5 validates_length_of :password, :within => 4..40 6 validates_length_of :email, :maximum => 50 7 validates_presence_of :email 8 end
  4. 1 # app/models/user.rb 2 class User < ActiveRecord::Base 3 validates_uniqueness_of

    :screen_name, :email 4 validates_length_of :screen_name, :within => 4..20 5 validates_length_of :password, :within => 4..40 6 validates_length_of :email, :maximum => 50 7 validates_presence_of :email 8 end
  5. 1 # app/models/user.rb 2 class User < ActiveRecord::Base 3 validates_uniqueness_of

    :screen_name, :email 4 validates_length_of :screen_name, :within => 4..20 5 validates_length_of :password, :within => 4..40 6 validates_length_of :email, :maximum => 50 7 validates_presence_of :email 8 end
  6. 1 <!-- app/view/profile/show.rhtml --> 2 <div id="left_column"> 3 <%= render

    :partial => 'faq/sidebar_box' %> 4 </div> 5 <div id="main_content"> 6 <div id="full_name"> 7 <%= h @spec.full_name.or_else(@user.screen_name) %> 8 </div> 9 <div id="occupation"> 10 <%= h @spec.occupation %> 11 </div> 12 <div id="location"> 13 <%= h @spec.location %> 14 </div> 15 </div>
  7. 1 <!-- app/view/profile/show.rhtml --> 2 <div id="left_column"> 3 <%= render

    :partial => 'faq/sidebar_box' %> 4 </div> 5 <div id="main_content"> 6 <div id="full_name"> 7 <%= h @spec.full_name.or_else(@user.screen_name) %> 8 </div> 9 <div id="occupation"> 10 <%= h @spec.occupation %> 11 </div> 12 <div id="location"> 13 <%= h @spec.location %> 14 </div> 15 </div>
  8. 1 <!-- app/view/profile/show.rhtml --> 2 <div id="left_column"> 3 <%= render

    :partial => 'faq/sidebar_box' %> 4 </div> 5 <div id="main_content"> 6 <div id="full_name"> 7 <%= h @spec.full_name.or_else(@user.screen_name) %> 8 </div> 9 <div id="occupation"> 10 <%= h @spec.occupation %> 11 </div> 12 <div id="location"> 13 <%= h @spec.location %> 14 </div> 15 </div>
  9. 1 <!-- app/views/user/register.rthml --> 2 <h2>Register</h2> 3 <% form_for :user

    do |form| %> 4 <fieldset> 5 <legend>Enter Your Details</legend> 6 <div class="form_row"> 7 <label for="screen_name">Screen name:</label> 8 <%= form.text_field :screen_name %> 9 </div> 10 <div class="form_row"> 11 <label for="email">Email:</label> 12 <%= form.text_field :email %> 13 </div> 14 <div class="form_row"> 15 <label for="password">Password:</label> 16 <%= form.password_field :password %> 17 </div>
  10. 1 <!-- app/views/user/register.rthml --> 2 <h2>Register</h2> 3 <% form_for :user

    do |form| %> 4 <fieldset> 5 <legend>Enter Your Details</legend> 6 <div class="form_row"> 7 <label for="screen_name">Screen name:</label> 8 <%= form.text_field :screen_name %> 9 </div> 10 <div class="form_row"> 11 <label for="email">Email:</label> 12 <%= form.text_field :email %> 13 </div> 14 <div class="form_row"> 15 <label for="password">Password:</label> 16 <%= form.password_field :password %> 17 </div>
  11. 1 <!-- app/views/user/register.rthml --> 2 <h2>Register</h2> 3 <% form_for :user

    do |form| %> 4 <fieldset> 5 <legend>Enter Your Details</legend> 6 <div class="form_row"> 7 <label for="screen_name">Screen name:</label> 8 <%= form.text_field :screen_name %> 9 </div> 10 <div class="form_row"> 11 <label for="email">Email:</label> 12 <%= form.text_field :email %> 13 </div> 14 <div class="form_row"> 15 <label for="password">Password:</label> 16 <%= form.password_field :password %> 17 </div>
  12. 1 # app/controllers/user_controller.rb 2 class UserController < ApplicationController 3 4

    def index 5 end 6 7 def register 8 @title = "Register" 9 if request.post? and params[:user] 10 @user = User.new(params[:user]) 11 if @user.save 12 flash[:notice] = "User created!" 13 redirect_to :action => "index" 14 end 15 end 16 end 17 end
  13. 1 # app/controllers/user_controller.rb 2 class UserController < ApplicationController 3 4

    def index 5 end 6 7 def register 8 @title = "Register" 9 if request.post? and params[:user] 10 @user = User.new(params[:user]) 11 if @user.save 12 flash[:notice] = "User created!" 13 redirect_to :action => "index" 14 end 15 end 16 end 17 end
  14. 1 # app/controllers/user_controller.rb 2 class UserController < ApplicationController 3 4

    def index 5 end 6 7 def register 8 @title = "Register" 9 if request.post? and params[:user] 10 @user = User.new(params[:user]) 11 if @user.save 12 flash[:notice] = "User created!" 13 redirect_to :action => "index" 14 end 15 end 16 end 17 end
  15. 1 # app/controllers/user_controller.rb 2 class UserController < ApplicationController 3 4

    def index 5 end 6 7 def register 8 @title = "Register" 9 if request.post? and params[:user] 10 @user = User.new(params[:user]) 11 if @user.save 12 flash[:notice] = "User created!" 13 redirect_to :action => "index" 14 end 15 end 16 end 17 end
  16. 1 # config/database.yml 2 development: 3 adapter: mysql 4 database:

    rails_space_development 5 username: root 6 password: 7 host: localhost 8 test: 9 adapter: mysql 10 database: rails_space_test 11 username: root 12 password: 13 host: localhost 14 production: 15 adapter: mysql 16 database: rails_space_production 17 username: root 18 password: <your password> 19 host: localhost
  17. 1 # config/database.yml 2 development: 3 adapter: mysql 4 database:

    rails_space_development 5 username: root 6 password: 7 host: localhost 8 test: 9 adapter: mysql 10 database: rails_space_test 11 username: root 12 password: 13 host: localhost 14 production: 15 adapter: mysql 16 database: rails_space_production 17 username: root 18 password: <your password> 19 host: localhost
  18. 1 # test/functional/user_controller_test.rb 2 # Test a valid login. 3

    def test_login_success 4 try_to_login @valid_user, :remember_me => "0" 5 assert logged_in? 6 assert_equal @valid_user.id, session[:user_id] 7 assert_equal "User #{@valid_user.name} logged in!”, 8 flash[:notice] 9 assert_response :redirect 10 assert_redirected_to :action => "index" 11 end
  19. 1 # test/functional/user_controller_test.rb 2 def test_login_success 3 try_to_login @valid_user, :remember_me

    => "0" 4 assert logged_in? 5 assert_equal @valid_user.id, session[:user_id] 6 assert_equal "User logged in!", flash[:notice] 7 assert_response :redirect 8 assert_redirected_to :action => "index" 9 end
  20. 1 # test/fixtures/users.yml 2 valid_user: 3 id: 1 4 screen_name:

    millikan 5 email: [email protected] 6 password: electron 7 8 invalid_user: 9 id: 2 10 screen_name: aa/noyes 11 email: anoyes@example,com 12 password: sun
  21. 1 # spec/controllers/sessions_controller_spec.rb 2 describe SessionsController do 3 4 describe

    "POST 'create'" do 5 6 describe "with valid email and password" do 7 before(:each) do 8 @user = Factory(:user) 9 @attr = { :email => @user.email, 10 :password => @user.password } 11 end 12 13 it "should sign the user in" do 14 post :create, :session => @attr 15 controller.current_user.should == @user 16 controller.should be_signed_in 17 end
  22. 1 # spec/controllers/sessions_controller_spec.rb 2 describe SessionsController do 3 4 describe

    "POST 'create'" do 5 6 describe "with valid email and password" do 7 before(:each) do 8 @user = Factory(:user) 9 @attr = { :email => @user.email, 10 :password => @user.password } 11 end 12 13 it "should sign the user in" do 14 post :create, :session => @attr 15 controller.current_user.should == @user 16 controller.should be_signed_in 17 end
  23. 1 # spec/controllers/sessions_controller_spec.rb 2 describe SessionsController do 3 4 describe

    "POST 'create'" do 5 6 describe "with valid email and password" do 7 before(:each) do 8 @user = Factory(:user) 9 @attr = { :email => @user.email, 10 :password => @user.password } 11 end 12 13 it "should sign the user in" do 14 post :create, :session => @attr 15 controller.current_user.should == @user 16 controller.should be_signed_in 17 end
  24. 1 # features/signing_in.feature 2 Feature: Signing in 3 4 Scenario:

    Successful signin 5 Given a user visits the signin page 6 And the user has an account 7 When the user submits valid signin information 8 Then they should see their profile page 9 And they should see a signout link
  25. 1 # features/step_definitions/authentication_steps.rb 2 Given /^a user visits the signin

    page$/ do 3 visit signin_path 4 end 5 6 When /^they submit invalid signin information$/ do 7 click_button "Sign in" 8 end 9 10 Then /^they should see an error message$/ do 11 page.should have_selector('div.alert.alert-error') 12 end
  26. 1 # test/functional/user_controller_test.rb 2 def test_login_success 3 try_to_login @valid_user, :remember_me

    => "0" 4 assert logged_in? 5 assert_equal @valid_user.id, session[:user_id] 6 assert_equal "User logged in!", flash[:notice] 7 assert_response :redirect 8 assert_redirected_to :action => "index" 9 end
  27. 1 # test/integration/users_login_test.rb 2 test "login with valid information" do

    3 get login_path 4 post login_path, params: { 5 session: { email: @user.email, 6 password: 'password' } } 7 assert is_logged_in? 8 assert_redirected_to @user 9 follow_redirect! 10 assert_template 'users/show' 11 end
  28. 1 # test/fixtures/users.yml 2 valid_user: 3 id: 1 4 screen_name:

    millikan 5 email: [email protected] 6 password: electron 7 8 invalid_user: 9 id: 2 10 screen_name: aa/noyes 11 email: anoyes@example,com 12 password: sun
  29. 1 # test/fixtures/users.yml 2 michael: 3 name: Michael Example 4

    email: [email protected] 5 password_digest: <%= User.digest('password') %> 6 admin: true 7 activated: true 8 activated_at: <%= Time.zone.now %> 9 10 archer: 11 name: Sterling Archer 12 email: [email protected] 13 password_digest: <%= User.digest('password') %> 14 activated: true 15 activated_at: <%= Time.zone.now %>
  30. 1 # test/fixtures/users.yml 2 michael: 3 name: Michael Example 4

    email: [email protected] 5 password_digest: <%= User.digest('password') %> 6 admin: true 7 activated: true 8 activated_at: <%= Time.zone.now %> 9 10 archer: 11 name: Sterling Archer 12 email: [email protected] 13 password_digest: <%= User.digest('password') %> 14 activated: true 15 activated_at: <%= Time.zone.now %>
  31. 1 create table users ( 2 id int not null

    auto_increment, 3 name varchar(100) not null, 4 hashed_password char(40) null, 5 primary key (id) 6 );
  32. 1 # db/migrate/001_create_users.rb 2 class CreateUsers < ActiveRecord::Migration 3 def

    self.up 4 create_table :users do |t| 5 # t.column :name, :string 6 end 7 end 8 9 def self.down 10 drop_table :users 11 end 12 end
  33. 1 # db/migrate/timestamp_create_users.rb 2 class CreateUsers < ActiveRecord::Migration[5.0] 3 def

    change 4 create_table :users do |t| 5 t.string :name 6 t.string :email 7 8 t.timestamps 9 end 10 end 11 end
  34. 1 # app/controllers/user_controller.rb 2 def register 3 @title = "Register"

    4 if request.post? and params[:user] 5 @user = User.new(params[:user]) 6 if @user.save 7 flash[:notice] = "User created!" 8 redirect_to :action => "index" 9 end 10 end 11 end
  35. 1 # app/controllers/user_controller.rb 2 def register 3 @title = "Register"

    4 if request.post? and params[:user] 5 @user = User.new(params[:user]) 6 if @user.save 7 flash[:notice] = "User created!" 8 redirect_to :action => "index" 9 end 10 end 11 end
  36. 1 # app/controllers/users_controller.rb 2 def create 3 @user = User.new(user_params)

    4 if @user.save 5 log_in @user 6 flash[:success] = "Welcome to the Sample App!" 7 redirect_to @user 8 else 9 render 'new' 10 end 11 end 12 13 private 14 15 def user_params 16 params.require(:user).permit(:name, :email, :password, 17 :password_confirmation) 18 end
  37. 1 # app/controllers/users_controller.rb 2 def create 3 @user = User.new(user_params)

    4 if @user.save 5 log_in @user 6 flash[:success] = "Welcome to the Sample App!" 7 redirect_to @user 8 else 9 render 'new' 10 end 11 end 12 13 private 14 15 def user_params 16 params.require(:user).permit(:name, :email, :password, 17 :password_confirmation) 18 end
  38. 1 # app/controllers/users_controller.rb 2 def create 3 @user = User.new(user_params)

    4 if @user.save 5 log_in @user 6 flash[:success] = "Welcome to the Sample App!" 7 redirect_to @user 8 else 9 render 'new' 10 end 11 end 12 13 private 14 15 def user_params 16 params.require(:user).permit(:name, :email, :password, 17 :password_confirmation) 18 end
  39. 1 <!-- app/view/profile/show.rhtml --> 2 <div id="left_column"> 3 <%= render

    :partial => 'faq/sidebar_box' %> 4 </div> 5 <div id="main_content"> 6 <div id="full_name"> 7 <%= h @spec.full_name.or_else(@user.screen_name) %> 8 </div> 9 <div id="occupation"> 10 <%= h @spec.occupation %> 11 </div> 12 <div id="location"> 13 <%= h @spec.location %> 14 </div> 15 </div>
  40. 1 <!-- app/view/profile/show.rhtml --> 2 <div id="left_column"> 3 <%= render

    :partial => 'faq/sidebar_box' %> 4 </div> 5 <div id="main_content"> 6 <div id="full_name"> 7 <%= h @spec.full_name.or_else(@user.screen_name) %> 8 </div> 9 <div id="occupation"> 10 <%= h @spec.occupation %> 11 </div> 12 <div id="location"> 13 <%= h @spec.location %> 14 </div> 15 </div>
  41. 1 <!-- app/views/users/show.html.erb --> 2 <% provide(:title, @user.name) %> 3

    <div class="row"> 4 <aside class="col-md-4"> 5 <section> 6 <h1> 7 <%= gravatar_for @user %> 8 <%= @user.name %> 9 </h1> 10 </section> 11 . 12 . 13 . 14 </aside> 15 </div>
  42. 1 <!-- app/views/users/show.html.erb --> 2 <% provide(:title, @user.name) %> 3

    <div class="row"> 4 <aside class="col-md-4"> 5 <section> 6 <h1> 7 <%= gravatar_for @user %> 8 <%= @user.name %> 9 </h1> 10 </section> 11 . 12 . 13 . 14 </aside> 15 </div>
  43. 1 <!-- app/views/users/show.html.erb --> 2 <% provide(:title, @user.name) %> 3

    <div class="row"> 4 <aside class="col-md-4"> 5 <section> 6 <h1> 7 <%= gravatar_for @user %> 8 <%= sanitize @user.name %> 9 </h1> 10 </section> 11 . 12 . 13 . 14 </aside> 15 </div>
  44. 1 <!-- app/views/users/show.html.erb --> 2 <% provide(:title, @user.name) %> 3

    <div class="row"> 4 <aside class="col-md-4"> 5 <section> 6 <h1> 7 <%= gravatar_for @user %> 8 <%= raw @user.name %> 9 </h1> 10 </section> 11 . 12 . 13 . 14 </aside> 15 </div>
  45. 1 class UsersController < ApplicationController 2 3 def index 4

    end 5 6 def show 7 end 8 9 def new 10 end 11 12 def edit 13 end 14 15 def create 16 end 17 18 def update 19 end 20 21 def destroy 22 end 23 end
  46. 1 # app/controllers/user_controller.rb 2 def register 3 @title = "Register"

    4 if param_posted?(:user) 5 @user = User.new(params[:user]) 6 if @user.save 7 @user.login!(session) 8 flash[:notice] = "User created!" 9 redirect_to_forwarding_url 10 else 11 @user.clear_password! 12 end 13 end 14 end
  47. 1 # app/controllers/user_controller.rb 2 def register 3 @title = "Register"

    4 if param_posted?(:user) 5 @user = User.new(params[:user]) 6 if @user.save 7 @user.login!(session) 8 flash[:notice] = "User created!" 9 redirect_to_forwarding_url 10 else 11 @user.clear_password! 12 end 13 end 14 end
  48. 1 # depot_final/app/controllers/login_controller.rb: 2 class LoginController < ApplicationController 3 before_filter

    :authorize, :except => :login 4 5 def index 6 @total_orders = Order.count 7 @pending_orders = Order.count_pending 8 end 9 . 10 . 11 . 12 end
  49. 1 # depot_final/app/controllers/login_controller.rb: 2 class LoginController < ApplicationController 3 before_filter

    :authorize, :except => :login 4 5 def index 6 @total_orders = Order.count 7 @pending_orders = Order.count_pending 8 end 9 . 10 . 11 . 12 end
  50. 1 # app/controllers/sessions_controller.rb 2 class SessionsController < ApplicationController 3 4

    def new 5 end 6 7 def create 8 email = params[:session][:email].downcase 9 password = params[:session][:password] 10 user = User.find_by(email: email) 11 if user && user.authenticate(password) 12 . 13 . 14 . 15 end 16 end
  51. 1 # app/controllers/sessions_controller.rb 2 class SessionsController < ApplicationController 3 4

    def new 5 end 6 7 def create 8 email = params[:session][:email].downcase 9 password = params[:session][:password] 10 user = User.find_by(email: email) 11 if user && user.authenticate(password) 12 . 13 . 14 . 15 end 16 end
  52. 1 # app/controllers/sessions_controller.rb 2 class SessionsController < ApplicationController 3 4

    def new 5 end 6 7 def create 8 email = params[:session][:email].downcase 9 password = params[:session][:password] 10 user = User.find_by(email: email) 11 if user && user.authenticate(password) 12 . 13 . 14 . 15 end 16 end
  53. 1 # app/controllers/user_controller.rb 2 def register 3 @title = "Register"

    4 if param_posted?(:user) 5 @user = User.new(params[:user]) 6 if @user.save 7 @user.login!(session) 8 flash[:notice] = "User created!" 9 redirect_to_forwarding_url 10 else 11 @user.clear_password! 12 end 13 end 14 end
  54. 1 # app/controllers/user_controller.rb 2 def register 3 @title = "Register"

    4 if param_posted?(:user) 5 @user = User.new(params[:user]) 6 if @user.save 7 @user.login!(session) 8 flash[:notice] = "User created!" 9 redirect_to_forwarding_url 10 else 11 @user.clear_password! 12 end 13 end 14 end
  55. 1 # app/controllers/users_controller.rb 2 def create 3 @user = User.new(user_params)

    4 if @user.save 5 log_in @user 6 flash[:success] = "Welcome to the Sample App!" 7 redirect_to @user 8 else 9 render 'new' 10 end 11 end
  56. 1 # app/controllers/users_controller.rb 2 def create 3 @user = User.new(user_params)

    4 if @user.save 5 log_in @user 6 flash[:success] = "Welcome to the Sample App!" 7 redirect_to @user 8 else 9 render 'new' 10 end 11 end
  57. 1 # app/controllers/users_controller.rb 2 def create 3 @user = User.new(user_params)

    4 if @user.save 5 @user.send_activation_email 6 flash[:info] = "Check email to activate" 7 redirect_to root_url 8 else 9 render 'new' 10 end 11 end https://commons.wikimedia.org/wiki/File:Lewis_Hamilton_2017_Malaysia_FP2.jpg
  58. 1 # app/controllers/users_controller.rb 2 def create 3 @user = User.new(user_params)

    4 if @user.save 5 @user.send_activation_email 6 flash[:info] = "Check email to activate" 7 redirect_to root_url 8 else 9 render 'new' 10 end 11 end https://commons.wikimedia.org/wiki/File:Lewis_Hamilton_2017_Malaysia_FP2.jpg