ここでは、ユーザに紐付く投稿を取得し、いいね機能を実装し、パスワードを暗号化していきます。
Ruby on Rails5 学習コースⅨ
・postsテーブルにuser_idカラムを追加する
$ rails g migration add_user_id_to_posts # (YYYYMMDDHHMMHH_add_user_id_to_posts.rb) def change add_column :posts, :user_id, :integer end $ rails db:migrate
・user_idのバリデーション
# (models/post.rb) validates :user_id, {presence: true}
・投稿したユーザのidを保存する
# (posts_controller.rb) def create @post = Post.new( content: params[:content], user_id: @current_user.id # 投稿したユーザidを保存 ) : end
・user_idからユーザ情報を取得する
# (posts_controller.rb) def show @post = Post.find_by(id: params[:id]) @user = User.find_by(id: @post.user_id) # @post.user_idの値からユーザ情報を取得 end
・ユーザ画像とユーザ名を表示する
# (posts/show.html.erb) <img src="<%= "/user_images/#{@user.image_name}" %>"> # ユーザ画像 <%= link_to(@user.name, "/users/#{@user.id}") %> # ユーザ名(リンク)
・モデルにインスタンスメソッドを定義する
# (models/post.rb) def user return User.find_by(id: self.user_id) # インスタンスメソッド内で、selfはそのインスタンス自身を指す end $ rails c > post = Post.find_by(id: 1) # Postモデルのインスタンスを取得する > post.user # 変数postに対してuserメソッドを呼び出す id: 1, # 投稿に紐付いているユーザ情報が表示される name: "にんじゃわんこ", : password: "wanko"
・ユーザに紐付く複数の投稿を取得する
$ rails c > posts = Post.where(user_id: 1) # whereメソッドで複数のデータを取得 # (models/user.rb) def posts return Post.where(user_id: self.id) end $ rails c > user = User.find_by(id: 1) > user.posts # 変数userに対してpostsメソッドを呼び出す # ユーザに紐付いている複数の投稿情報が表示される # (users/show.html.erb) <% @user.posts.each do |post| %> # ユーザに紐付いている複数の投稿を1つづつpost変数に格納 <div class="posts-index-item"> <div class="post-left"> <img src="<%= "/user_images/#{post.user.image_name}" %>"> # 投稿に紐付いているユーザの画像を表示 </div> <div class="post-right"> <div class="post-user-name"> # 投稿に紐付いているユーザ名を、投稿に紐付いているユーザの詳細ページへリンクする <%= link_to(post.user.name, "/users/#{post.user.id}") %> </div> <%= link_to(post.content, "/posts/#{post.id}") %> </div> </div> <% end %>
・投稿者だけが編集できるようにする
# (posts/show.html.erb) # 投稿を作成したユーザidとログインしているユーザidが等しいことを確認 <% if @post.user_id == @current_user.id %> <%= link_to("編集", "/posts/#{@post.id}/edit") <%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "post"}) %> <% end %> # (posts_controller.rb) before_action :ensure_corrent_user, {only: [:edit, :update, :destroy]} : def ensure_correct_user @post = Post.find_by(id: params[:id]) if @post.user_id != @current_user.id flash[:notice] = "権限がありません" redirect_to("/posts/index") end end
・完成版
# (YYYYMMDDHHMMHH_add_user_id_to_posts.rb) def change add_column :posts, :user_id, :integer end # (models/post.rb) validates :content, {presence: true, length: {maximum: 140}} validates :user_id, {presence: true} # 追加 def user return User.find_by(id: self.user_id) # 追加 end # (models/user.rb) validates :name, {presence: true} validates :email, {presence: true, uniqueness: true} validates :password, {presence: true} def posts return Post.where(user_id: self.id) # 追加 end # (posts_controller.rb) before_action :authenticate_user before_action :ensure_correct_user, {only: [:edit, :update, :destroy]} # 追加 def index @posts = Post.all.order(created_at: :desc) end def show @post = Post.find_by(id: params[:id]) @user = @post.user # 追加 end def new @post = Post.new end 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 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 def ensure_correct_user # 追加 @post = Post.find_by(id: params[:id]) if @post.user_id != @current_user.id flash[:notice] = "権限がありません" redirect_to("/posts/index") end end # (posts/show.html.erb) <div class="post-user-name"> <img src="<%= "/user_images/#{@user.image_name}" %>"> # 追加 <%= link_to(@user.name, "/users/#{@user.id}") %> # 追加 </div> <p> <%= @post.content %> </p> <div class="post-time"> <%= @post.created_at %> </div> <% if @post.user_id == @current_user.id %> # 追加 <div class="post-menus"> <%= link_to("編集", "/posts/#{@post.id}/edit") %> <%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "post"}) %> </div> <% end %> # (posts/index.html.erb) <% @posts.each do |post| %> <div class="posts-index-item"> <div class="post-left"> <img src="<%= "/user_images/#{post.user.image_name}" %>"> # 追加 </div> <div class="post-right"> <div class="post-user-name"> <%= link_to(post.user.name, "/users/#{post.user.id}") %> # 追加 </div> <%= link_to(post.content, "/posts/#{post.id}") %> </div> </div> <% end %> # (users/show.html.erb) <div class="user"> <img src="<%= "/user_images/#{@user.image_name}" %>"> <h2><%= @user.name %></h2> <p><%= @user.email %></p> <% if @user.id == @current_user.id %> <%= link_to("編集", "/users/#{@user.id}/edit") %> <% end %> </div> <% @user.posts.each do |post| %> # 追加 <div class="posts-index-item"> <div class="post-left"> <img src="<%= "/user_images/#{post.user.image_name}" %>"> </div> <div class="post-right"> <div class="post-user-name"> <%= link_to(post.user.name, "/users/#{post.user.id}") %> </div> <%= link_to(post.content, "/posts/#{post.id}") %> </div> </div> <% end %>
・確認すること
- 投稿詳細ページで、ユーザ名のリンクが表示されていて、ユーザ詳細ページへ画面遷移する
- ユーザ詳細ページにそのユーザが出品したアイテムのみ一覧表示されている
- 投稿者のみ編集/削除ボタンが表示されていて、実行できる
- 投稿者以外は編集/削除ができない
Ruby on Rails5 学習コースⅩ
・いいね機能の実装
# likesテーブルを作成するマイグレーションファイルを作成 $ rails g model Like user_id:integer post_id:integer $ rails db:migrate # DBに変更を反映 # (models/like.rb) validates :user_id, {presence: true} validates :post_id, {presence: true} $ rails c > like = Like.new(user_id: 1, post_id: 2) # データを追加してみる > like.save # (posts/show.html.erb) <% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %> いいね!済み <% else %> いいね!していません <% end %>
・いいねボタンの設置
# (routes.rb) post "likes/:post_id/create" => "likes#create" # (likes_controller.rb) before_action :authenticate_user def create @like = Like.new(user_id: @current_user.id, post_id: params[:post_id]) @like.save redirect_to("/posts/#{params[:post_id]}") end # (posts/show.html.erb) <% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %> いいね!済み <% else %> <%= link_to("いいね!", "/likes/#{@post.id}/create", {method: "post"}) %> <% end %>
・いいね取り消しボタンの設置
# (routes.rb) post "likes/:post_id/destroy" => "likes#destroy" # (likes_controller.rb) 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 # (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"}) %> <% else %> <%= link_to("いいね!", "/likes/#{@post.id}/create", {method: "post"}) %> <% end %>
・ボタンをアイコンに変更
# (layouts/application.html.erb) <head> : # Font Awesomeの読み込み <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> </head> # (posts/show.html.erb) <%= link_to("/likes/#{@post.id}/create", {method: "post"}) do %> # 文字列として認識されるのを避ける為、HTML要素は以下に記述する <span class="fa fa-heart like-btn"></span> <% end %>
・いいねの数を取得する
$ rails c > Like.all.count # likesテーブルの全データの数 > Like.where(post_id: 1).count # likesテーブルのpost_idが1の数 # (posts_controller.rb) def show @post = Post.find_by(id: params[:id]) @user = @post.user @likes_count = Like.where(post_id: @post.id).count # 変数@likes_countを定義 end # (posts/show.html.erb) <%= @likes_count %>
・いいねした投稿の一覧を表示する
# (routes.rb) get "users/:id/likes" => "users#likes" # (users_controller.rb) def likes @user = User.find_by(id: params[:id]) @likes = Like.where(user_id: @user.id) end # (users/show.html.erb) <ul class="user-tabs"> <li class="active"><%= link_to("投稿", "/users/#{@user.id}") %></li> <li><%= link_to("いいね!", "/users/#{@user.id}/likes") %></li> </ul> # (users/likes.html.erb) <% @likes.each do |like| %> <% post = Post.find_by(id: like.post_id) %> : <% end %>
・完成版
# (models/like.rb) validates :user_id, {presence: true} validates :post_id, {presence: true} # (routes.rb) post "likes/:post_id/create" => "likes#create" # 追加 post "likes/:post_id/destroy" => "likes#destroy" # 追加 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" post "login" => "users#login" post "logout" => "users#logout" get "login" => "users#login_form" get "users/:id/likes" => "users#likes" # 追加 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" # (users_controller.rb) def likes @user = User.find_by(id: params[:id]) @likes = Like.where(user_id: @user.id) end # (posts_controller.rb) def show @post = Post.find_by(id: params[:id]) @user = @post.user @likes_count = Like.where(post_id: @post.id).count # 追加 end # (likes_controller.rb) before_action :authenticate_user 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 # (layouts/application.html.erb) <head> <title>TweetApp</title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> # 追加 </head> # (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 %> <span class="fa fa-heart like-btn-unlike"></span> <% end %> <% else %> <%= link_to("/likes/#{@post.id}/create", {method: "post"}) do %> <span class="fa fa-heart like-btn"></span> <% end %> <% end %> <%= @likes_count %> <% if @post.user_id == @current_user.id %> <div class="post-menus"> <%= link_to("編集", "/posts/#{@post.id}/edit") %> <%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "post"}) %> </div> <% end %> # (users/show.html.erb) <ul class="user-tabs"> <li class="active"><%= link_to("投稿", "/users/#{@user.id}") %></li> <li><%= link_to("いいね!", "/users/#{@user.id}/likes") %></li> </ul> # (users/likes.html.erb) <div class="user"> <img src="<%= "/user_images/#{@user.image_name}" %>"> <h2><%= @user.name %></h2> <p><%= @user.email %></p> <% if @user.id == @current_user.id %> <%= link_to("編集", "/users/#{@user.id}/edit") %> <% end %> </div> <ul class="user-tabs"> <li><%= link_to("投稿", "/users/#{@user.id}") %></li> <li class="active"><%= link_to("いいね!", "/users/#{@user.id}/likes") %></li> </ul> <% @likes.each do |like| %> <% post = Post.find_by(id: like.post_id) %> <div class="posts-index-item"> <div class="post-left"> <img src="<%= "/user_images/#{post.user.image_name}" %>"> </div> <div class="post-right"> <div class="post-user-name"> <%= link_to(post.user.name, "/users/#{post.user.id}") %> </div> <%= link_to(post.content, "/posts/#{post.id}") %> </div> </div> <% end %>
・確認すること
- 投稿詳細ページでいいねボタンといいねの数が表示されている
- いいねボタンをクリックすると、いいね又はいいね解除ができる(色が変わる)
- いいね一覧タブが表示されていて、画面遷移できる
Ruby on Rails5 学習コースⅪ
・bcryptのインストール
# (Gemfile) gem 'bcrypt' # 暗号化する為のgem $ bundle install # 上記で記載したgemをインストール $ rails s -b $IP -p $PORT # 「bundle install」後は、railsサーバを「ctrl+c」で停止した後、起動する # (models/user.rb) has_secure_password # bcryptをインストールすることで暗号化するメソッドを使用できる validates :name, {presence: true} validates :email, {presence: true, uniqueness: true} # passwordカラムのバリデーションは削除しておく(has_secure_passwordメソッドが自動的にチェック) def posts return Post.where(user_id: self.id) end
・password_digestカラムの追加
$ rails g migration change_users_columns # YYYYMMDDHHMMSS_change_users_columns.rb def change add_column :users, :password_digest, :string # password_digestカラムの追加 remove_column :users, :password, :string # passwordカラムの削除 end $ rails db:migrate
・暗号化されたパスワードを用いてログインする
# (users_controller.rb) def login @user = User.find_by(email: params[:email]) # authenticateメソッドを使って、「送信されたメールアドレスと一致するユーザー」のpassword_digestと、送信されたパスワードが一致するかを確認 if @user && @user.authenticate(params[:password]) : end end
・確認すること
- 「rails c」にて、パスワードが暗号化されて保存されることを確認
- 問題なくログインできる
> user = User.find_by(id: 1)
> user.password = “password”
> user.save
[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]