[Ruby on Rails5]Progate 学習メモ4
引き続きメモ。とっ散らかっている内容は後でまとめます。
▼投稿した内容に記事の内容とユーザIDを保存する
新規投稿作成時に、投稿したユーザの値をいれて保存する。
投稿したユーザーは、現在ログインしているユーザなので、ログインユーザの変数で取得可能。
xxx.controller.rbにて記載。
def create
@post = Post.new(
content: params[:content]
user_id: @current_user.id
)
...
end
▼ユーザIDからユーザ情報(ユーザ名、アイコン)を取得する
user_idカラムの値から、そのユーザーの情報を取得します。
投稿詳細ページなので、postsコントローラのshowアクション内で、
そのidに該当するユーザーの情報をデータベースから取得する。
xxx.controller.rbにて記載。
def show
@post = Post.find_by(id: params[:id])
@user = User.find_by(id: @post.user_id)
...
end
取得した情報を表示する。
xxx.html.erbにて記載。
<div class="post-user-name">
<img src="<%= "/user_images/#{@user.image_name}" %>">
<%= link_to(@user.name, "/users/#{@user.id}") %>
</div>
▼モデルにインスタントメソッドを定義する
モデルにインスタンスメソッドを定義する。
models/xxx.rbにて記載。
class
def hello(インスタントメソッド)
puts "It is test."
end
end
ターミナルで確認してみる。
$ rails console
> post = Post.find_by(id:1)
> post.hello
It is test.
これを応用してユーザidに紐付いている情報を表示させる。
インスタンスメソッド内で、selfはそのインスタンス自身を表す。
models/xxx.rbにて記載。
class Post < ApplicationRecord
...
def user
return User.find_by(id: self.user_id)
end
end
ターミナルで確認してみる。
$ rails console
> post = Post.find_by(id: 1)
> post.user
id :1
name: "XXX"
password: "YYY"
...
実際にコードに記述してみる。
xxx.controller.rbに記載。
書き換え前
@user = User.find_by(id: @post.user_id)
書き換え後
@user = @post.user
▼ユーザに紐づく複数のデータを取得する
投稿一覧を表示させるためには、投稿からidを抽出することになる。
投稿は複数に渡るため、1つのデータしか取得できないfind_byメソッドではなく、whereメソッドを利用することになる。
ターミナルで確認してみる。
$ rails console |
> post = Post.where(id: 1) | idの値が「1]であること
> [...] (idが1である投稿の配列) | idが「1」である投稿のすべて)
...
posts[0].content
=> "XXXXX"
▼ユーザの投稿を一覧で表示させる
各投稿を表示させるには、whereメソッドで取得した値は配列に入っているので、ビュー側でeach文を用いて、1つずつ投稿を表示していく。
xxx.html.erbにて記載。
<% @user.posts.each do |post| %>
...
<% end %>
▼2つのテーブルが持つカラムを連携させる
いいね機能は、ユーザ情報を持ったテーブルと投稿情報を持ったテーブルが各々持ったカラムを保持するテーブルにその情報が書き込まれる。
テーブルの追加し、マイグレーションを行う。
rails g model コントロール テーブル名, :カラム名, :データ型
rails db:migrate
model配下のファイルにバリデーションを設定しておく。
両方存在しないと不完全なデータになってしまうため、
validates :1つ目のカラム, {presence: true}
validates :2つ目のカラム, {presence: true}
コンソールで挙動を確認する。
コマンド後、DBが更新されている。
rails console
> like = Like.new(user_id:1, post_id:2)
> like.save
▼いいね機能で表示する仕組み
いいねの存在で画面表示を変化させる
「ログインしているユーザーがその投稿にいいねしたデータが存在する」という条件のために、user_idとpost_idが合致するデータがlikesテーブルに存在するかどうか、find_byを用いてチェックします。(find_byは該当するデータが見つからなかった時にnilを返す)
下記では、2つのテーブルのカラムがLikesテーブルに存在するかチェックしている。
<% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>
いいね!済み
<% else %>
いいね!していません
<% end %>
▼いいねボタンの実装(ボタンを押下するといいねされる)
作成するアクションの追加を行う
likes_contoroller.rb
class LikesController < ApplicationContoroller
def create
@like = Like.new(
user_id: @current_user.id,
post_id: params[:post_id]
)
@like.save
redirect_to("/posts/#{params[:post_id]}")
end
end
route.rb
rails.application.routes.draw do
...
post "likes/:post_id/create" => "likes#create"
end
上記によって「どの投稿をいいねしたのか」という情報が連携される。
リンクも反映させる。
posts/show.html.erb
<%= link_to("いいね!", "/likes/#{@post.id}/create", {method: "post"}) %>
▼いいねボタンの実装(いいね中にボタンを押下すると取り消される)
likes_contoroller.rb
class LikesController < ApplicationContoroller
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
end
route.rb
rails.application.routes.draw do
...
post "likes/:post_id/destory" => "likes#destroy"
end
リンクも反映させる。
posts/show.html.erb
<%= link_to("いいね!済み", "/likes/#{@post.id}/destroy", {method: "post"}) %>
▼いいねボタンをハートアイコンにする
「Font Awesome」を利用する際は
タグなどの共通のHTMLはapplication.html.erbに書きますので、
今回はそこに読み込み用のタグを追加します。
共通なので、application.html.erbに記載
<!DOCTYPE html>
<html>
<head>
...
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
...
</head>
...
HTML上には下記のように記載。
<span class="fa fa-heart"></span>
xxx.html.erbには下記のように記載。
通常のlink_toメソッド
<%= link_to("表示する文字列", "URL") %>
HTML要素を記述したい場合のlink_toメソッド
<%= link_to("URL") do %>
ここに記載
<% end %>
つまりこうなる
<%= link_to("/likes/#{@post.id}/create", {method: "post"}) do %>
<span class="fa fa-heart like-btn"></span>
<% end %>
いいねがついていないときは
<%= link_to("/likes/#{@post.id}/destroy", {method: "post"}) do %>
<span class="fa fa-heart like-btn-unlike"></span>
<% end %>
後はCSSで色を調整する
▼いいねの件数を表示する
ikesテーブルからデータの件数を取得するには、countメソッドを用います。countメソッドは配列の要素数を取得するメソッドですが、テーブルのデータ数を取得するためにも利用することができます。
$ rails console
> Like.all.count
=> 3
> Like.where(post_id: 1).count
=> 2
def show
...
@likes_count = Like.where(post_id: @post.id).count
end
▼いいねの一覧を作成する
route.rbにて
Rails.application.routes.draw do
...
get "users/:id/likes" => "users#likes"
...
end
user_controller.rbにて
def likes
@user = User.find_by(id: params[:id])
@likes = Like.where(user_id: @user.id)
end
xxx.html.erbにて
<% @likes.each do |like| %>
<% post = Post.find_by(id: like.post_id) %>
...
<% end %>
▼パスワードを暗号化する
DB上に平文でパスワード管理するのは危険です。
Railsでは暗号化するためにbcryptを使用する。
今回はbcryptという「暗号化するためのgem」を使います。
RailsにはGemfileというファイルがあり、インストールするgemが書かれています。「gem 'bcrypt'」という1行を追加し、ターミナルで「bundle install」というコマンドを実行すると、書かれたgemをインストールすることができます。
gem 'bcrypt'
$ bundle install
bcryptをインストールすると、has_secure_passwordというメソッドが使えるようになります。図のようにパスワードを扱うUserモデルにhas_secure_passwordを追加します。こうすることで、ユーザーを保存する際に自動的にパスワードを暗号化してくれます。
user.rb
class User < ApplicationRecord
has_secure_password
...
end
次にpasswordカラムのバリデーションを削除する
validates :password, {presence: true}
パスワード管理するにあたり、下記2点の変更を行う
・passwordカラムの削除
・暗号化されたパスワードが格納されるpassword_digestカラムの追加
$ rails g migration change_users_column
マイグレーションファイル(xxx.rb)
add_column :users, :password_digest, :string
remove_column :users, :password, :string
$ rails db:migration
password_digestカラムに暗号化されたパスワードを保存するためには、今まで通りpasswordに値を代入します。
こうすることで、has_secure_passwordによってpasswordに代入された値が暗号化され、password_digestカラムに保存されます。
このため、既にあるpasswordに関するコードを変更する必要はありません。
has_secure_passwordメソッドを有効にすると、authenticateメソッドを使えるようになります。authenticateメソッドは渡された引数を暗号化し、password_digestの値と一致するかどうかを判定してくれます。
authenticateメソッドを使って、「送信されたメールアドレスと一致するユーザー」のpassword_digestと、送信されたパスワードが一致するかどうかでログイン処理をします。
まずはユーザの呼び出しにメールアドレスとパスワードにしていたが、メールアドレスのみとし、ユーザの存在確認のif文にパスワード一致をand条件にする。
if @user && @user.authenticate(params[:password])
Author And Source
この問題について([Ruby on Rails5]Progate 学習メモ4), 我々は、より多くの情報をここで見つけました https://qiita.com/hiro-gen/items/b9201ee9cc61efb5a4f7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .