Ⅵ~Ⅷ章では、ユーザ機能及びログイン機能を追加しています。
Ruby on Rails5 学習コースⅥ
・Userモデルとusersテーブルの作成
$ rails g model User name:string email:string $ rails db:migrate
・Userモデルとusersテーブルの作成
# (models/user.rb)
validates :email, {uniqueness: true}
・ユーザ新規登録ページの作成
# (users/new.html.erb) <p>ユーザ名</p> <input name="name" value="<%= @user.name %>"> # 1行のフォームは<input>タグを使用する <input name="email" value="<%= @user.email %>"> # value属性にRubyのコードを埋め込む <input type="submit" value="新規登録">
・完成版
# (models/user.rb)
validates :name, {presence: true}
validates :email, {presence: true, uniqueness: true}
# (routes.rb)
get "users/index" => "users#index"
get "signup" => "users#new"
get "users/:id" => "users#show"
post "users/create" => "users#create"
get "users/:id/edit" => "users#edit"
post "users/:id/update" => "users#update"
# (users_controller.rb)
def index
@users = User.all
end
def show
@user = User.find_by(id: params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(name: params[:name], email: params[:email])
if @user.save
flash[:notice] = "ユーザー登録が完了しました"
redirect_to("/users/#{@user.id}")
else
render("users/new")
end
end
def edit
@user = User.find_by(id: params[:id])
end
def update
@user = User.find_by(id: params[:id])
@user.name = params[:name]
@user.email = params[:email]
if @user.save
flash[:notice] = "ユーザー情報を編集しました"
redirect_to("/users/#{@user.id}")
else
render("users/edit")
end
end
# (layouts/application.html.erb)
<header>
<div class="header-logo">
<%= link_to("TweetApp", "/") %>
</div>
<ul class="header-menus">
<li>
<%= link_to("TweetAppとは", "/about") %>
</li>
<li>
<%= link_to("投稿一覧", "/posts/index") %>
</li>
<li>
<%= link_to("新規投稿", "/posts/new") %>
</li>
<li>
<%= link_to("ユーザー一覧", "/users/index") %> # 追加
</li>
<li>
<%= link_to("新規登録", "/signup") %> # 追加
</li>
</ul>
</header>
# (index.html.erb)
<% @users.each do |user| %>
<%= link_to(user.name, "/users/#{user.id}") %>
<% end %>
# (show.html.erb)
<h2><%= @user.name %></h2>
<p><%= @user.email %></p>
<%= link_to("編集", "/users/#{@user.id}/edit") %>
# (new.html.erb)
<% @user.errors.full_messages.each do |message| %>
<%= message %>
<% end %>
<%= form_tag("/users/create") do %>
<p>ユーザー名</p>
<input name="name" value="<%= @user.name %>">
<p>メールアドレス</p>
<input name="email" value="<%= @user.email %>">
<input type="submit" value="新規登録">
<% end %>
# (edit.html.erb)
<% @user.errors.full_messages.each do |message| %> # エラーメッセージを表示
<div class="form-error">
<%= message %>
</div>
<% end %>
<%= form_tag("/users/#{@user.id}/update") do %> # フォームの送信先を指定
<p>ユーザー名</p>
<input name="name" value="<%= @user.name %>">
<p>メールアドレス</p>
<input name="email" value="<%= @user.email %>">
<input type="submit" value="保存">
<% end %>
・確認すること
- ヘッダーに「ユーザ一覧」と「新規登録」のリンクが表示されていて、画面遷移できる
- 新規登録画面にて、ユーザの新規登録ができ、適宜エラーメッセージとサクセスメッセージが表示される
- メールアドレスが一意であるなどのバリデーションが有効になっている
- ユーザ一覧ページから各ユーザの詳細ページへ画面遷移できる
- ユーザの詳細ページの編集ボタンより編集ができ、適宜エラーメッセージとサクセスメッセージが表示される
Ruby on Rails5 学習コースⅦ
・テーブルにカラムを追加する
$ rails g migration add_image_name_to_users # マイグレーションファイルのみを作成 # (db/migrate/2018MMDDHHMMSS_add_image_name_to_users) # 作成されたマイグレーションファイルを以下のように編集 def change add_column :users, :image_name, :string # usersテーブルにimage_nameカラムを追加 end $ rails db:migrate # DBに変更を反映
・ユーザ登録時に初期画像を保存
# (users_controller.rb) def create @user = User.new( name: params[:name], email: params[:email], image_name: "default_user.jpg" # ユーザ登録時のimage_nameカラムの値を設定 ) if @user.save : end
・ビューに画像を表示する
# (users/show.html.erb)
<img src="<%= "/user_images/#{@user.image_name}" %>">
・画像選択ボタンを表示する
# (users/edit.html.erb)
<%= form_tag("...", {multipart: true}) do %> # 画像の送信にはform_tagに{multipart: true}を追加する
<h2>画像</h2>
<input name="image" type="file"> # 「type="file"」とすることで画像を設定できるようになる
・Rubyのコードでファイルを作成する
$ rails console
> File.write("public/sample.txt", "Hello World")
・画像をDBに保存する
# (users_controller.rb)
def update
:
if params[:image]
@user.image_name = "#{@user.id}.jpg" # 画像のファイル名をimage_nameカラムに保存
image = params[:image] # 送信されたファイルの情報をimage変数に格納
# image変数の画像データをreadメソッドを用いて取得し、ファイルに書き込む
File.binwrite("public/user_images/#{@user.image_name}", image.read)
end
:
end
・完成版
# (db/migrate/2018MMDDHHMMSS_add_image_name_to_users)
def change
add_column :users, :image_name, :string
end
# (users_controller.rb)
def index
@users = User.all
end
def show
@user = User.find_by(id: params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(
name: params[:name],
email: params[:email],
image_name: "default_user.jpg" # 追加
)
if @user.save
flash[:notice] = "ユーザー登録が完了しました"
redirect_to("/users/#{@user.id}")
else
render("users/new")
end
end
def edit
@user = User.find_by(id: params[:id])
end
def update
@user = User.find_by(id: params[:id])
@user.name = params[:name]
@user.email = params[:email]
if params[:image] # 画像を保存する処理を追加
@user.image_name = "#{@user.id}.jpg"
image = params[:image]
File.binwrite("public/user_images/#{@user.image_name}", image.read)
end
if @user.save
flash[:notice] = "ユーザー情報を編集しました"
redirect_to("/users/#{@user.id}")
else
render("users/edit")
end
end
# (users/index.html.erb)
<% @users.each do |user| %>
<div class="users-index-item">
<div class="user-left">
<img src="<%= "/user_images/#{user.image_name}" %>"> # 追加
</div>
<div class="user-right">
<%= link_to(user.name, "/users/#{user.id}") %>
</div>
</div>
<% end %>
# (users/show.html.erb)
<img src="<%= "/user_images/#{@user.image_name}" %>"> # 追加
<h2><%= @user.name %></h2>
<p><%= @user.email %></p>
<%= link_to("編集", "/users/#{@user.id}/edit") %>
# (users/edit.html.erb)
<% @user.errors.full_messages.each do |message| %>
<div class="form-error">
<%= message %>
</div>
<% end %>
<%= form_tag("/users/#{@user.id}/update", {multipart: true}) do %> # 変更
<p>ユーザー名</p>
<input name="name" value="<%= @user.name %>">
<p>画像</p>
<input name="image" type="file"> # 追加
<p>メールアドレス</p>
<input name="email" value="<%= @user.email %>">
<input type="submit" value="保存">
<% end %>
・確認すること
- 編集画面で画像選択ボタンが表示されていて、画像が保存/表示される
Ruby on Rails5 学習コースⅧ
・ログインページの作成
# (routes.rb) get "login" => "users#login_form" # (users_controller.rb) def login_form end # (users/login_form.html.erb) <p>パスワード</p> <input type="password"> # type="password"を指定して入力内容を伏字にする
・パスワードカラムの追加
$ rails g migration add_password_to_users # マイグレーションファイル作成 # (YYYYMMDDHHMMHH_add_password_to_users.rb) def change add_column :users, :pasword, :string # usersテーブルにpasswordカラムを追加 end $ rails db:migrate # DBに変更を反映
・バリデーションの設定
# (models/user.rb)
validates :password, {presence: true}
・ルーティングとアクションの追加
# (routes.rb)
post "login" => "users#login" # フォームの値を送信する為postを使用
# (users/login_form.html.erb)
<%= form_tag("/login") do %>
<p>メールアドレス</p>
<input name="email">
<p>パスワード</p>
<input type="password" name="password">
<% end %>
・ログイン機能の実装
# (users_controller.rb)
def login
# ログインするユーザを特定する
@user = User.find_by(email: params[:email], password: params[:password])
if @user # ユーザが存在する場合
flash[:notice] = "ログインしました"
redirect_to("/posts/index")
else # ユーザが存在しない場合
@error_message = "メールアドレスまたはパスワードが間違っています"
@email = params[:email]
@password = params[:password]
render("users/login_form")
end
end
# (users/login_form.html.erb)
<% if @error_message %>
<%= @error_message %>
<% end %>
<%= form_tag("/login") do %>
<p>メールアドレス</p>
<input name="email" value="<%= @email %>">
<p>パスワード</p>
<input type="password" name="password" value="<%= @password %>">
<% end %>
・session変数を使用してユーザ情報をブラウザで保持する
# (users_controller.rb) def login @user = User.find_by(email: params[:email], password: params[:password]) if @user session[:user_id] = @user.id : end
・ログアウト機能の実装
# (routes.rb)
post "logout" => "users#logout" # sessionの値を変更するのでpostを使用
# (users_controller.rb)
def logout
session[:user_id] = nil
flash[:notice] = "ログアウトしました"
redirect_to("/login")
end
# (layouts/application.html.erb)
<% if session[:user_id] %>
<li>
<%= session[:user_id] %>
</li>
:
・ユーザ登録時のログイン
# (new.html.erb) : # パスワード用のフォームを追加 <p>パスワード</p> <input name="password" type="password" value="<%= @user.password %>"> : # (users_controller.rb) def create @user = User.new( name: params[:name], email: params[:email], image_name: "default_user.jpg", password: params[:password] # passwordカラムの値を設定 ) end
・ユーザ登録時にログイン状態にする
# (users_controller.rb) def create @user = User.new(...) if @user.save session[:user_id] = @user.id # 新規登録時にログイン状態にする :
・ユーザ名の表示
# (layouts/appilcation.html.erb)
<% current_user = User.find_by(id: session[:user_id]) %>
<li>
<%= link_to(current_user.name, "/users/#{current_user.id}") %>
</li>
・アクション側で共通の変数を定義する
# (application_controller.rb) before_action :set_current_user # 全てのコントローラーで共通する処理は纏める def set_current_user @current_user = User.find_by(id: session[:user_id]) end
・アクセス制限の処理を共通化する
# (application_controller.rb)
def authenticate_user
if @current_user == nil
flash[:notice] = "ログインが必要です"
redirect_to("/login")
end
end
# (users_controller.rb)
# onlyを用いて適用したいアクションを指定
before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
・ログインユーザがアクセスできないページの設定
# (application_controller.rb)
def forbid_login_user
if @current_user
flash[:notice] = "すでにログインしています"
redirect_to("/posts/index")
end
end
# (home_controller.rb)
before_action :forbid_login_user, {only: [:top]}
# (users_controller.rb)
before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}
・ユーザの編集を制限する
# (users/show.html.erb)
# 詳細ページのユーザidとログインユーザidが等しい場合のみ編集ボタンを表示
<% if @user.id == @current_user.id %>
<%= link_to("編集", "/users/#{@user.id}/edit") %>
<% end %>
# (users_controller.rb)
before_action :ensure_correct_user, {only: [:edit, :update]}
def ensure_correct_user
# 正しいユーザかどうかを判定する
if @current_user.id != params[:id].to_i # to_iメソッドで文字列を数値に変換
flash[:notice] = "権限がありません"
redirect_to("/posts/index")
end
end
・完成版
# (routes.rb)
get "login" => "users#login_form" # 追加
post "login" => "users#login" # 追加
post "logout" => "users#logout" # 追加
post "users/:id/update" => "users#update"
get "users/:id/edit" => "users#edit"
post "users/create" => "users#create"
get "signup" => "users#new"
get "users/index" => "users#index"
get "users/:id" => "users#show"
get "posts/index" => "posts#index"
get "posts/new" => "posts#new"
get "posts/:id" => "posts#show"
post "posts/create" => "posts#create"
get "posts/:id/edit" => "posts#edit"
post "posts/:id/update" => "posts#update"
post "posts/:id/destroy" => "posts#destroy"
get "/" => "home#top"
get "about" => "home#about"
# (application_controller.rb)
before_action :set_current_user
def set_current_user
@current_user = User.find_by(id: session[:user_id])
end
def authenticate_user
if @current_user == nil
flash[:notice] = "ログインが必要です"
redirect_to("/login")
end
end
def forbid_login_user
if @current_user
flash[:notice] = "すでにログインしています"
redirect_to("/posts/index")
end
end
# (home_controller.rb)
before_action :forbid_login_user, {only: [:top]} # 追加
def top
end
def about
end
# (posts_controller.rb)
before_action :authenticate_user # 追加
def index
@posts = Post.all.order(created_at: :desc)
end
def show
@post = Post.find_by(id: params[:id])
end
def new
@post = Post.new
end
def create
@post = Post.new(content: params[:content])
if @post.save
flash[:notice] = "投稿を作成しました"
redirect_to("/posts/index")
else
render("posts/new")
end
end
def edit
@post = Post.find_by(id: params[:id])
end
def update
@post = Post.find_by(id: params[:id])
@post.content = params[:content]
if @post.save
flash[:notice] = "投稿を編集しました"
redirect_to("/posts/index")
else
render("posts/edit")
end
end
def destroy
@post = Post.find_by(id: params[:id])
@post.destroy
flash[:notice] = "投稿を削除しました"
redirect_to("/posts/index")
end
# (users_controller.rb)
before_action :authenticate_user, {only: [:index, :show, :edit, :update]} # 追加
before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]} # 追加
before_action :ensure_correct_user, {only: [:edit, :update]} # 追加
def index
@users = User.all
end
def show
@user = User.find_by(id: params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(
name: params[:name],
email: params[:email],
image_name: "default_user.jpg",
password: params[:password] # 追加
)
if @user.save
session[:user_id] = @user.id
flash[:notice] = "ユーザー登録が完了しました"
redirect_to("/users/#{@user.id}")
else
render("users/new")
end
end
def edit
@user = User.find_by(id: params[:id])
end
def update
@user = User.find_by(id: params[:id])
@user.name = params[:name]
@user.email = params[:email]
if params[:image]
@user.image_name = "#{@user.id}.jpg"
image = params[:image]
File.binwrite("public/user_images/#{@user.image_name}", image.read)
end
if @user.save
flash[:notice] = "ユーザー情報を編集しました"
redirect_to("/users/#{@user.id}")
else
render("users/edit")
end
end
def login_form
end
def login
@user = User.find_by(email: params[:email], password: params[:password])
if @user
session[:user_id] = @user.id
flash[:notice] = "ログインしました"
redirect_to("/posts/index")
else
@error_message = "メールアドレスまたはパスワードが間違っています"
@email = params[:email]
@password = params[:password]
render("users/login_form")
end
end
def logout
session[:user_id] = nil
flash[:notice] = "ログアウトしました"
redirect_to("/login")
end
def ensure_correct_user # 追加
if @current_user.id != params[:id].to_i
flash[:notice] = "権限がありません"
redirect_to("/posts/index")
end
end
# (layouts/application.html.erb)
<header>
<div class="header-logo">
<% if @current_user %>
<%= link_to("TweetApp", "/posts/index") %>
<% else %>
<%= link_to("TweetApp", "/") %>
<% end %>
</div>
<ul class="header-menus">
<% if @current_user %>
<li><%= link_to(@current_user.name, "/users/#{@current_user.id}") %></li>
<li><%= link_to("投稿一覧", "/posts/index") %></li>
<li><%= link_to("新規投稿", "/posts/new") %></li>
<li><%= link_to("ユーザー一覧", "/users/index") %></li>
<li><%= link_to("ログアウト", "/logout", {method: :post}) %></li> # postを指定
<% else %>
<li><%= link_to("TweetAppとは", "/about") %></li>
<li><%= link_to("新規登録", "/signup") %></li>
<li><%= link_to("ログイン", "/login") %></li>
<% end %>
</ul>
</header>
# (users/show.html.erb)
<h2><%= @user.name %></h2>
<p><%= @user.email %></p>
<% if @user.id == @current_user.id %> # 追加
<%= link_to("編集", "/users/#{@user.id}/edit") %>
<% end %>
# (/users/login_form.html.erb)
<% if @error_message %>
<div class="form-error">
<%= @error_message %>
</div>
<% end %>
<%= form_tag("/login") do %>
<p>メールアドレス</p>
<input name="email" value="<%= @email %>">
<p>パスワード</p>
<input type="password" name="password" value="<%= @password %>">
<input type="submit" value="ログイン">
<% end %>
# (/users/new.html.erb)
<%= form_tag("/users/create") do %>
<p>ユーザー名</p>
<input name="name" value="<%= @user.name %>">
<p>メールアドレス</p>
<input name="email" value="<%= @user.email %>">
<p>パスワード</p>
<input type="password" name="password" value="<%= @user.password %>">
<input type="submit" value="新規登録">
<% end %>
・確認すること
- ログイン前のヘッダーのリンクは、「TweetApp」「TweetAppとは」「新規登録」「ログイン」
- 「TweetApp」は、トップページへ画面遷移する
- 「ログイン」より、ログインページへ画面遷移し、ログインできる(パスワードは伏字)
- ログイン時、エラーメッセージ又はサクセスメッセージが表示される
- ログイン後のヘッダーのリンクは、「TweetApp」「ログインユーザ名」「投稿一覧」「新規投稿」「ユーザ一覧」「ログアウト」
- 「TweetApp」は、投稿一覧ページへ画面遷移する
- 「ログインユーザ名」は、ユーザ詳細ページへ画面遷移する
- 「ログアウト」より、ログアウトできる
- ログイン前のアクセスが制限できている
- ログインユーザがアクセスできないページが設定できている
- 他ユーザの編集ができないよう制限できている
[siteorigin_widget class=”AdWidgetItem”][/siteorigin_widget]
[siteorigin_widget class=”WP_Widget_Search”][/siteorigin_widget]
[siteorigin_widget class=”WP_Widget_Pages”][/siteorigin_widget]
[siteorigin_widget class=”AdWidgetItem”][/siteorigin_widget]
