2. image_nameカラムを追加しよう
画像を保存するために、usersテーブルにimage_nameカラムを追加しましょう。
usersテーブルにimage_nameカラムを追加してください。データ型はstringとしてください。
def change
add_column :テーブル名, :カラム名, :データ型
end
1マイグレーションファイルを作成
usersテーブルに画像名を保存するために、マイグレーションファイルを作成しましょう。
ターミナル
rails g migrationコマンドを用いて、
add_image_name_to_users
というファイル名で、マイグレーションファイルを作成してください。
rails g migration add_image_name_to_users
2マイグレーションファイル編集
class AddImageNameToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :image_name, :string
end
end
3マイグレーションファイルをデータベースに反映
rails db:migrate
3. 初期画像を設定しよう
createアクションで、Userインスタンスを作成するときにimage_nameカラムの値が設定されるようにしてください。
(※ newメソッドの引数を追加します)
users_controller.rb
def create
@user = User.new(
name: params[:name],
email: params[:email],
image_name: "default_user.jpg"
)
プロフィール画像を表示
show.html.erb
4. 画像編集機能を作ろう
画像編集機能を作ろう
ユーザー編集ページから画像をアップロードできるようにしましょう。
画像を保存する時はファイル名はデータベースに保存し、画像データはpublicフォルダ内に保存するようにします。
ユーザー編集ページで、「保存」ボタンが押された時に画像データが送信されるようにしてください。
ヒント
ヒント
画像用のフォームを作成します。
以下のように、inputタグにtype=”file”を指定します。
form_tagメソッドに「{multipart: true}」を追加することで、画像を送信できます。
以下のように指定しましょう。
<%= form_tag("送信先のURL", {multipart: true}) %>
usersコントローラのupdateアクションで画像データを受け取り、画像データが存在する時にだけ画像が保存されるようにしてください。
ただし、画像のファイル名はデータベースに、画像データはpublic/user_imagesフォルダに保存してください。
また、画像のファイル名は「1.jpg」のように「ユーザーのid.jpg」となるようにしてください。
ヒント
画像データをpublic/imagesフォルダに保存しましょう。
以下のように、binwriteメソッドとreadメソッドを用います。
File.binwrite(“public/user_images/#{画像名}”, 画像データ.read)
https://prog-8.com/rails5/study/7/6#
https://prog-8.com/rails5/study/7/8#/25
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
5. パスワードカラムを追加しよう
https://prog-8.com/rails5/study/8/3#
■ ターミナルで以下のコマンドを実行してください
rails g migration add_password_to_users
■ マイグレーションファイル編集後に、ターミナルで以下のコマンドを実行してください
rails db:migrate
20170612014736_add_password_to_users.rb
class AddPasswordToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :password, :string
end
end
■ コンソールで以下のコードを実行してください
user = User.find_by(id: 1)
user.password = "好きなパスワード"
user.save
user.rb
class User < ApplicationRecord
validates :name, {presence: true}
validates :email, {presence: true, uniqueness: true}
validates :password, {presence: true}
end
6. ログインフォームを作成しよう
・ 対応するアクションはusersコントローラのloginアクションとなるようにしてください。
・ post URL => コントローラ名#アクション名となるようにしてください。
get “login” => “users#login_form”
def login
end
7. ログイン処理を追加しよう
ユーザーが存在する場合、以下の処理を行ってください。
・フォームに入力されたデータからユーザーを特定し、そのユーザーが存在する場合、session[:user_id]にユーザーのidを代入してください。
・ログイン後、
ログインしました
というフラッシュが表示されるようにしてください。
・ログイン後、投稿一覧ページにリダイレクトされるようにしてください。
ユーザーが存在しない場合の処理を作りましょう。
ユーザーが存在しない場合には、ログインページが再表示されるようにしてください。
ログインしている場合には、ヘッダーに「ログイン中のユーザーのid」を表示しましょう。
ログイン中のユーザーがいる場合には、ヘッダーに「現在ログインしているユーザーのid: 1」のように、ログイン中のユーザーのidを表示してください。
現在ログインしているユーザーのid:
post “login” => “users#login”
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
render(“users/login_form”)
end
end
<% if session[:user_id] %>
<%= session[:user_id] %>
<% end %>
8. ユーザーが存在しない場合の処理
ログイン処理で、ユーザーが存在しなかった場合の処理を完成させましょう。
ログインに失敗した場合に、エラーメッセージを表示するようにしてください。
ログインに失敗した場合にメールアドレスとパスワードのフォームに初期値が入るようにしてください。
users_controller.rb
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
login_form.html.erb
<% if @error_message %>
<%= @error_message %>
<% end %>
<%= form_tag("/login") do %>
メールアドレス
<% end %>
9. ユーザー登録時にログイン状態にしよう
ユーザー登録時にもログイン状態となるようにしていきましょう。
まずは、ユーザー登録ページでもログインページと同じようにパスワードの入力欄を追加しましょう。
メールアドレス入力欄の下に以下のHTMLを貼り付けて、パスワード用の入力欄を追加してください。
・ユーザー登録に失敗した場合には、パスワードの入力欄に初期値が入るようにしてください。
・usersコントローラのcreateアクションで、入力されたパスワードを取得し保存してください。
・ユーザーの登録に成功した場合、登録されたユーザーがログインするようにしてください。
new.html.erb
<%= form_tag("/users/create") do %>
ユーザー名
<% end %>
users_controller.rb
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
10. ログアウト機能を作ろう
ログアウト機能を作成してみましょう。
・ヘッダーに「ログアウト」リンクを用意し、リンクがクリックされた時にユーザーがログアウトできるようにしてください。「ログアウト」リンクのURLは/logoutとしてください。
ただし、アクションはusersコントローラに定義してください。
・ログアウト後に、
ログアウトしました
というフラッシュを表示してください。
・ログアウト後は、ログインページにリダレクトしてください。
ログアウトするためには、
session[:user_id] を nil にします。
ログアウト機能ができたら、ログインしている状態としていない状態でヘッダーに表示する内容を変えてみましょう。
routes.rb
post “logout” => “users#logout”
users_controller.rb
def logout
session[:user_id] = nil
flash[:notice] = “ログアウトしました”
redirect_to(“/login”)
end
application.html.erb
11. ヘッダーにユーザー名を表示しよう
ヘッダーに現在ユーザーのidが表示されていますが、その代わりにログイン中のユーザーの名前を表示してください。
また、そのユーザーの詳細ページへのリンクとなるようにしてください。
ヒント
共通処理は application_controller内に記述します。
また、 before_action を定義することで、事前処理を行うことができます。
以下のように記述します。
before_action :メソッド名
def メソッド名
全アクションで共通する処理
end
before_action
before_action
各コントローラの全アクションで共通する処理がある場合には、before_actionを使うと便利です。before_actionを用いることで、アクションが呼び出される際に必ずbefore_actionの処理が実行されます。
これにより、全アクションで共通する処理を1箇所にまとめることができます。
application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_current_user
def set_current_user
@current_user = User.find_by(id: session[:user_id])
end
end
12. ログインしていない場合のアクセス制限
ログインしていない場合にアクセスできないページを作成していきましょう。
ログインしていないユーザーが以下のアクションにアクセスした場合には、ログインページへリダイレクトするようにしてください。
・postsコントローラの全アクション
・usersコントローラのindex, show, edit, updateアクション
また、
ログインが必要です
というフラッシュを表示してください。
ヒント
before_actionは限定して適用することができます。
onlyを用いることで、指定したアクションにだけbefore_actionを適用させることができます。
before_action :メソッド名, {only: [:アクション名, :アクション名, ... ]}
posts_controller.rb
class PostsController < ApplicationController
before_action :authenticate_user
users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
application_controller.rb
def authenticate_user
if @current_user == nil
flash[:notice] = "ログインが必要です"
redirect_to("/login")
end
end
13. ログインしている場合のアクセス制限
ログインしている場合にアクセスできないページを作っていきましょう。
ログイン中のユーザーが以下のURLにアクセスした場合には、投稿一覧ページにリダイレクトしてください。
・get /signup
・get /login
・get / (localhost:3000)
・post /users/create
・post /login
また、
すでにログインしています
というフラッシュを表示してください。
posts_controller.rb
class PostsController < ApplicationController
before_action :authenticate_user
users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}
home_controller.rb
class HomeController < ApplicationController
before_action :forbid_login_user, {only: [:top]}
14. 自分の情報のみ編集できるようにしよう
ログインしているユーザーの情報のみ編集できるようにしていきましょう。
まずは、ユーザー詳細ページの「編集」リンクは自分の詳細ページの時にだけ表示するようにしましょう。
ユーザー詳細ページで、詳細ページのユーザーとログインしているユーザーが一致した場合のみ「編集」リンクが表示されるようにしてください。
次に、URLを直接入力した時にもアクセス制限がかかるようにしましょう。
ログインしているユーザーが他のユーザーの編集ページ、ユーザー情報更新時のURLにアクセスした場合には、投稿一覧ページにリダイレクトしてください。
また、
権限がありません
というフラッシュを表示してください。
show.html.erb
<% if @user.id == @current_user.id %>
<%= link_to("編集", "/users/#{@user.id}/edit")%>
users_controller.rb
def ensure_correct_user
if params[:id].to_i != @current_user.id
flash[:notice] = “権限がありません”
redirect_to(“/posts/index”)
end
end