Rails チュートリアル復習用メモ
以下を参考にした、Rails アプリを作成する手順の覚書です。
- Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
- GitHub - yasslab/sample_apps: Rails チュートリアルの各章が終わった状態を集めたリポジトリです。
モデルとコントローラーの基本的な部分を知ることが目的だったので、モデルの応用的な部分や View 周りはできるだけ省いたアプリケーションに仕上がっています。具体的には 4, 11, 12, 14 章をスキップし、それ以外の各章もスタイルやインテグレーションテストについては省いています。(発展的なログイン機構、アカウント有効化のメール送信、パスワード再設定、ユーザーのフォローなどが機能として未実装。)
- 新規アプリ作成
- Gemfile 更新
- モデルを作成
- コントローラー作成
- ルーティングを設定
- セッションヘルパー
- サンプルデータを追加
- ビューとコントローラーを調整
- 元記事のメモ/リンク
- Rails ガイドより
新規アプリ作成
rails _5.1.4_ new first_app
rails server
# => http://localhost:3000/
Gemfile 更新
feat: upadte Gemfile · ryotah/rails-tutorial@6336633
bundle install --without production
モデルを作成
User モデルと Micropost モデルを作成します。
User モデルを作成
rails generate model User name:string email:string password_digest:string # => app/models/user.rb # => db/migrate/xxx_create_users.rb # => test/fixtures/user.yml # => test/models/user_test.rb rails db:migrate # => db/schema.rb # Rails 4以前 # bundle exec rake db:migrate
すでに存在するモデルにインデックスを追加。
rails generate migration add_index_to_users_email
生成されたdb/migrate/[timestamp]_add_index_to_users_email.rb
を更新してから migrate を実行。
class AddIndexToUsersEmail < ActiveRecord::Migration[5.0] def change # 以下の行を追加 # # unique: true => 一意性を強制 add_index :users, :email, unique: true end end
User モデルに validates
, has_secure_password
, has_many :microposts, dependent: :destroy
などを追加。
class User < ApplicationRecord has_many :microposts, dependent: :destroy before_save { self.email = email.downcase } validates :name, presence: true, length: { maximum: 50 } VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false } has_secure_password validates :password, presence: true, length: { minimum: 6 }, allow_nil: true def User.digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost BCrypt::Password.create(string, cost: cost) end end
(メモ)rails console
からユーザーを追加
user = User.create(name: "Michael Hartl", email: "mhartl@example.com", password: "foobar", password_confirmation: "foobar") user.authenticate("foobaz") # => false !!user.authenticate("foobar") # => true
Micropost モデル
rails generate model Micropost content:text user:references
生成されたdb/migrate/[timestamp]_create_microposts.rb
を更新。
class CreateMicroposts < ActiveRecord::Migration[5.1] def change create_table :microposts do |t| t.text :content t.references :user, foreign_key: true t.timestamps end # 以下の行を追加 # # インデックスを追加して、user_id に関連付けられたマイクロポストを # 作成時刻の逆順で取り出しやすくする add_index :microposts, [:user_id, :created_at] end end
Micropost モデルに validates
, default_scope
を追加。(belongs_to :user
は最初から用意されている。)
class Micropost < ApplicationRecord belongs_to :user default_scope -> { order(created_at: :desc) } validates :user_id, presence: true validates :content, presence: true, length: { maximum: 140 } end
テスト
- https://github.com/ryotah/rails-tutorial/blob/251afb06508ad9357689b1d182e64d999ed97ef4/test/models/user_test.rb
- https://github.com/ryotah/rails-tutorial/blob/251afb06508ad9357689b1d182e64d999ed97ef4/test/models/micropost_test.rb
- fixtures を用意
# 全テストを実行 rails test # modelsのみテストを実行 rails test:models # 特定ファイルのテストを実行 rails test test/models/micropost_test.rb
コントローラー作成
必要なControllerを作成。
rails generate controller StaticPages home rails generate controller Users new rails generate controller Sessions new rails generate controller Microposts
ルーティングを設定
config/routes.rb
を更新
Rails.application.routes.draw do # root_path root 'static_pages#home' # 名前付きルートを定義 get '/signup', to: 'users#new' post '/signup', to: 'users#create' get '/login', to: 'sessions#new' post '/login', to: 'sessions#create' delete '/logout', to: 'sessions#destroy' resources :users resources :microposts, only: [:create, :destroy] end
セッションヘルパー
- 以下 5 つを定義
- ログイン
- セッション情報から現在のユーザー(ログインユーザ)を取得
- ログインユーザーか確認
- ログイン済みか確認
- ログアウト
module SessionsHelper def log_in(user) session[:user_id] = user.id end def current_user @current_user ||= User.find_by(id: session[:user_id]) end def current_user?(user) user == current_user end def logged_in? !current_user.nil? end def log_out session.delete(:user_id) @current_user = nil end end
ApplicationController
でinclude
する。(各ビューとコントローラーで利用できるようになる)
class ApplicationController < ActionController::Base protect_from_forgery with: :exception include SessionsHelper end
サンプルデータを追加
https://github.com/ryotah/rails-tutorial/blob/b27827169748425dbff08188d97c366eb73ec1fb/db/seeds.rb
rails db:seed
ビューとコントローラーを調整
ヘッダー
- https://github.com/ryotah/rails-tutorial/blob/0198d75b02672dbac7e96f08927afd7f004b45c8/app/views/layouts/_header.html.erb
logged_in
current_user
(メモ)デバッグ
<%= debug(params) if Rails.env.development? %>
ユーザー一覧
views/users/index.html.erb
を追加。
<h1>Users#index</h1> <%= render @users %>
views/users/_user.html.erb
を追加。(render @users
に対応するパーシャル)
<div><%= user.name %>, <%= user.email %></div>
コントローラーにindex
を追加。
class UsersController < ApplicationController # ... def index @users = User.all end # ... end
ログイン
views/sessions/new.html.erb
にフォームを追加。
<%= form_for(:session, url: login_path) do |f| %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.submit "Log in", class: "btn btn-primary" %> <% end %> <p>New user? <%= link_to "Sign up now!", signup_path %></p>
コントローラーにcreate
を追加。
def create user = User.find_by(email: params[:session][:email]) if user && user.authenticate(params[:session][:password]) log_in user redirect_to user else flash.now[:danger] = 'Invalid email/password combination' render 'new' end end
(メモ)Flash
<% flash.each do |message_type, message| %> <div><%= message_type %> | <%= message %></div> <% end %>
ユーザー作成
- feat: implement user signup · ryotah/rails-tutorial@cb0c924
- コントローラーの
new
,create
- Strong Parameters
app/views/users/new.html.erb
にフォームを追加
- コントローラーの
<%= form_for(@user, url: signup_path) do |f| %> <%= render 'shared/error_messages', object: f> # ...
ユーザー詳細
- feat: show a user detail · ryotah/rails-tutorial@340cf3a
- コントローラーの
show
app/views/users/show.html.erb
でユーザー名とマイクロポストを表示
- コントローラーの
ホーム(マイクロポスト作成)
- feat: post a micropost · ryotah/rails-tutorial@98a775c
- ログイン済みユーザーかどうか確認する
logged_in_user
をApplicationController
に追加 MicropostsController
のcreate
を実装before_action :logged_in_user, only: :create
app/views/static_pages/home.html.erb
にマイクロポスト用のフォームを追加
- ログイン済みユーザーかどうか確認する
<h1>StaticPages#home</h1> <p>Find me in app/views/static_pages/home.html.erb</p> <p>Find me in app/views/static_pages/home.html.erb</p> <% if logged_in? %> <%= current_user.name %>, <%= current_user.email %> <%= form_for(@micropost) do |f| %> <%= render 'shared/error_messages', object: f.object %> <%= f.text_area :content, placeholder: "Compose new micropost..." %> <%= f.submit "Post", class: "btn btn-primary" %> <% end %> <% end %>
元記事のメモ/リンク
- コラム 1.2. お手軽すぎる Scaffold の甘い誘惑
- 5.2.1 アセットパイプライン
- 5.3.2 Rails のルート URL
なお、Rails チュートリアルでは一般的な規約に従い、基本的には_path 書式を使い、リダイレクトの場合のみ_url 書式を使うようにします。これは HTTP の標準としては、リダイレクトのときに完全な URL が要求されるためです。ただしほとんどのブラウザでは、どちらの方法でも動作します。
- コラム 6.2. データベースのインデックス
- 6.3.1 ハッシュ化されたパスワード
password_digest
- セキュアにハッシュ化したパスワード
password
,password_confirmation
- 2 つのペアの仮想的な属性
- 存在性と値が一致するかどうかのバリデーションも追加
authenticate
メソッドhas_secure_password
を利用してパスワードをハッシュ化するためにbcrypt
gem が必要
- 表 7.1: リスト 7.3 の Users リソースが提供する RESTful なルート
- リスト 8.21: fixture 向けの digest メソッドを追加する
digest メソッドを User クラス自身に配置して、クラスメソッドにすることにしましょう
- 13.1.3 User/Micropost の関連付け
@user = users(:michael) # このコードは慣習的に正しくない @micropost = Micropost.new(content: "Lorem ipsum", user_id: @user.id)
Rails ガイドより
users = User.all user = User.first david = User.find_by(name: 'David')
- update
save
- 属性変更後に実行が必要
update
- 複数の属性を更新できる(
save
不要)
- 複数の属性を更新できる(
- update_attribute => http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_attribute
- ひとつの属性を更新
- バリデーションがスキップされる
- delete
- Active Record バリデーション | Rails ガイド
- valid? と invalid?
- format, length, presence, uniqueness, など
case_sensitive
- Active Record の関連付け (アソシエーション) | Rails ガイド
- Rails のルーティング | Rails ガイド
- 2 リソースベースのルーティング: Rails のデフォルト
resources
- 名前付きヘルパー
- 2 リソースベースのルーティング: Rails のデフォルト
- Rails セキュリティガイド | Rails ガイド
- Rails のコマンドラインツール | Rails ガイド
- https://railsguides.jp/command_line.html#rails-console
rails console
rails console --sandbox
- https://railsguides.jp/command_line.html#rails-console