2. 投稿とユーザーを 紐付ける準備をしよう
ここでは投稿とユーザーを紐付ける準備をします。どのユーザーが作成した投稿かわかるようにしましょう。
postsテーブルにuser_idカラムを追加してください。データ型はintegerとしてください。
user_idの値が必ず存在するようにバリデーションを設定してください。
■ ターミナルで以下のコマンドを実行してください
rails g migration add_user_id_to_posts
■ マイグレーションファイル編集後に、ターミナルで以下のコマンドを実行してください
rails db:migrate
20170705055449_add_user_id_to_posts.rb
class AddUserIdToPosts < ActiveRecord::Migration[5.0]
def change
add_column :posts, :user_id, :integer
end
end
models/post.rb
class Post < ApplicationRecord
validates :content, {presence: true, length: {maximum: 140}}
validates :user_id, {presence: true}
end
3. 新規投稿をログイン中の ユーザーと紐付ける
手順
それでは投稿とユーザーを紐付けましょう。
まずは、新規投稿に「どのユーザーが作成したのか」という情報を追加します。
postsコントローラのcreateアクションを編集して、新規投稿とログインしているユーザーを紐付けてください。
・views/posts/show.html.erb内の
・貼り付けたコードの中で、投稿に紐付いたユーザー名とユーザー画像を表示してください。
※ユーザー画像はpublic/user_imagesフォルダに保存されるようになっています。
※ユーザー名はそのユーザーの詳細ページへのリンクにしてください。
posts_controller.rb
def create
@post = Post.new(
content: params[:content],
user_id: @current_user.id
)
if @post.save
flash[:notice] = “投稿を作成しました”
redirect_to(“/posts/index”)
else
render(“posts/new”)
end
end
post.rb
def user
return User.find_by(id: self.user_id)
end
show.html.erb
<%= link_to(@user.name, "/users/#{@user.id}") %>
4. 投稿一覧ページにユーザー情報を表示しよう
index.html.erb
<%= link_to(post.content, "/posts/#{post.id}") %>
<% end %>
5. ユーザー詳細ページに投稿を表示しよう
whereメソッド
ある条件に合致する「複数の」データを取得するには、whereメソッドを
用いる必要があります。whereメソッドでデータを取得した場合、それぞれのデータは配列に入っています。
ユーザー詳細ページを編集しましょう。
見本と同じように、ユーザー詳細ページでそのユーザーの投稿一覧が表示されるようにしてください。
ヒント
条件に合致する全てのデータを取得するためには、whereメソッドを使います。
例) user_idの値が1である「全て」の投稿を取得
Post.where(user_id: 1)
posts = Post.where(user_id: 1)
user.rb
def posts
return Post.where(user_id: self.id)
end
show.html.erb
<% @user.posts.each do |post| %>
<%= link_to(post.content, "/posts/#{post.id}") %>
<% end %>
6. 投稿の編集と削除を制限しよう
ログインしているユーザーの投稿以外の投稿には編集ボタンと削除ボタンが表示されないようにしてください。
次に、権限の無いユーザーが直接URLにアクセスして投稿の編集や削除を行えないようにしましょう。
権限の無いユーザーがpostsコントローラのedit、update、destroyアクションにアクセスしようとした時、
“権限がありません”
というフラッシュを表示
・投稿一覧ページにリダイレクト
の2つを行ってください。
show.html.erb
<% if @post.user_id == @current_user.id %>
<% end %>
posts_controller.rb
before_action :ensure_correct_user, {only: [:edit, :update, :destroy]}
def ensure_correct_user
@post = Post.find_by(id: params[:id])
if @current_user.id != @post.user_id
flash[:notice] = “権限がありません”
redirect_to(“/posts/index”)
end
end
7. いいね機能を作る準備
ターミナルにコマンドを打ち込んでLikeモデルとlikesテーブルを作成してください。
※ただし、
・integer型のuser_idカラム
・integer型のpost_idカラム
を持たせてください。
マイグレーションファイルが作成されていることが確認できたら、データベースに変更を反映してください。
user_idとpost_idの値が必ず存在するようにバリデーションを追加してください。
■ ターミナルで以下のコマンドを実行してください
rails g model Like user_id:integer post_id:integer
■ マイグレーションファイルが作成されていることが確認できたら以下のコマンドを実行してください
rails db:migrate
like.rb
class Like < ApplicationRecord
validates :user_id, {presence: true}
validates :post_id, {presence: true}
end
8. 「いいね!」ボタンの準備
likesコントローラを作成し、createアクションとdestroyアクションを追加してください。(アクションの中身はまだ空で構いません。)
ただし、authenticate_userメソッドを用いてアクションへのアクセスをログインしているユーザーのみに制限してください。
① ルーティング
② アクション
を作成していきます。
「localhost:3000/likes/:post_id/create」というURLになるようにルーティングを追加してください。
※ ただし、
・ 対応するアクションはlikesコントローラのcreateアクションとなるようにしてください。
・ post URL => コントローラ名#アクション名となるようにしてください。
次に、likesコントローラを作成し、アクションを追加しましょう。
…/controllers/likes_controller.rb
app/controllersフォルダに
likes_controller.rb
というファイルを作成してください。
post “likes/:post_id/create” => “likes#create”
post “likes/:post_id/destroy” => “likes#destroy”
likes_controller.rb
class LikesController < ApplicationController
before_action :authenticate_user
def create
end
def destroy
end
end
9. 「いいね!」ボタンを作ろう
「いいね!」ボタンを作成します。まずはlikesコントローラの中身を完成させましょう。
・likesコントローラのcreate、destroyアクションの中身を作って、投稿の「いいね!」とその取り消しができるようにしてください。
・それぞれのアクションの最後で、いいねした投稿の詳細ページへリダイレクトしてください。
ハートアイコンを利用するために、Font Awesomeを読み込みましょう。
・application.html.erbの
投稿詳細ページの見本のように、投稿内容の下に「いいね!」ボタンを作成しましょう。
likes_controller.rb
def create
@like = Like.new(user_id: @current_user.id, post_id: params[:post_id])
@like.save
redirect_to(“/posts/#{params[:post_id]}”)
end
def destroy
@like = Like.find_by(user_id: @current_user.id, post_id: params[:post_id])
@like.destroy
redirect_to(“/posts/#{params[:post_id]}”)
end
view/posts/show.html.erb
<% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>
<%= link_to("/likes/#{@post.id}/destroy", {method: "post"}) do %>
<% end %>
<% else %>
<%= link_to("/likes/#{@post.id}/create", {method: "post"}) do %>
<% end %>
<% end %>
10. いいね数を表示しよう
投稿詳細ページの見本と同じように、「いいね!」ボタンの隣に投稿に付いたいいねの数を表示してください。
ヒント
ヒント
条件に一致したデータの数を表示できるようにするためには、 count メソッドを使用します。
Like.where(post_id: 投稿のid).count
…/controllers/posts_controller.rb
showアクションで変数@likes_countを定義してください。
また、whereメソッド、countメソッドを用いて、変数@likes_countにいいね数を代入してください。
def show
@post = Post.find_by(id: params[:id])
@user = @post.user
@likes_count = Like.where(post_id: @post.id).count
end
../posts/show.html.erb
ハートアイコンを表示している部分の下で、変数@likes_countの値を表示してください。
<%= @likes_count %>
11. 「いいね!」した投稿を表示しよう
…/config/routes.rb
「localhost:3000/users/:id/likes」というURLでアクセスできるルーティングを追加してください。
※ ただし、対応するアクションはusersコントローラのlikesアクションとなるようにしてください。
② 次に、アクションを追加しましょう。
…/controllers/users_controller.rb
likesアクションを追加してください。
③ likesアクションに対応するビューファイルを用意しましょう。
…/users/likes.html.erb
app/views/usersフォルダに
likes.html.erb
というファイルを作成してください。
作成したlikesアクションへのリンクを追加しましょう。
…/users/show.html.erb
ユーザー詳細ページの指定箇所に、以下のコードを貼り付けてください。
…/controllers/users_controller.rb
likesアクションで、
・idがparams[:id]のUserインスタンスをデータベースから取得し、変数@userに代入してください。
・@userと紐付くLikeインスタンスの配列をデータベースから取得し、変数@likesに代入してください。
…/users/likes.html.erb
変数@likesに対して、each文を用いてください。
※ただし、
・doの後ろの変数名は
like
としてください。
・最後にendを書くのを忘れないでください。
../users/likes.html.erb
each文の中で、変数likeに紐付くPostインスタンスをデータベースから取得し、変数postに代入してください。
①
get “users/:id/likes” => “users#likes”
②…/controllers/users_controller.rb
def likes
@user = User.find_by(id: params[:id])
@likes = Like.where(user_id: @user.id)
end
③…/users/likes.html.erb
<% @likes.each do |like| %>
<% post = Post.find_by(id: like.post_id) %>
<%= link_to(post.content, "/posts/#{post.id}") %>
<% end %>
12. パスワード暗号化の準備
ここからはパスワードを暗号化していきます。まずは暗号化のためのgemをインストールしましょう。
Gemfileに
gem ‘bcrypt’
を追加し、ターミナルで
bundle install
を実行してください。
13. パスワードの暗号化と保存
Userモデルにhas_secure_passwordを追加してください。
usersテーブルに、
・
string
型の
password_digest
カラムを追加
・
string
型の
password
カラムを削除
するマイグレーションファイルを作成してください。
ヒント
ヒント
カラムを削除するためには、マイグレーションファイルに以下の記述を行います。
remove_column :テーブル名, :カラム名, :データ型
ターミナルでコマンドを実行して、マイグレーションファイルの内容をデータベースに反映してください。
■ ターミナルで以下のコマンドを実行してください
rails g migration change_users_columns
■ マイグレーションファイルを変更してから以下のコマンドを実行してください
rails db:migrate
■ ターミナルで以下のコマンドを実行してください
rails console
■ コンソールで以下のコードを実行してください
user = User.find_by(id: 1)
user.password = “ninjawanko”
user.save
models/user.rb
class User < ApplicationRecord
has_secure_password
validates :name, {presence: true}
validates :email, {presence: true, uniqueness: true}
def posts
return Post.where(user_id: self.id)
end
end
20170707031454_change_users_columns.rb
class ChangeUsersColumns < ActiveRecord::Migration[5.0]
def change
add_column :users, :password_digest, :string
remove_column :users, :password, :string
end
end
14. 暗号化されたパスワードでログインする
authenticateメソッド
has_secure_passwordメソッドを有効にすると、authenticateメソッドを使えるようになります。authenticateメソッドは渡された引数を暗号化し、password_digestの値と一致するかどうかを判定してくれます。
ヒント
authenticateメソッドはhas_secure_passwordメソッドが
有効になっているモデルのインスタンスで使うことが可能です。
@user = User.find_by(カラム名: 条件)
@user.authenticate(パスワード)
def login
# メールアドレスのみを用いて、ユーザーを取得するように書き換えてください
@user = User.find_by(email: params[:email])
# if文の条件を&&とauthenticateメソッドを用いて書き換えてください
if @user && @user.authenticate(params[:password])
session[:user_id] = @user.id
flash[:notice] = "ログインしました"
redirect_to("/posts/index")