No_ideaのわからん日和

✏️...プログラミングが全然出来ない奴がわからんわからん言いながら様々な構文(記述方法やエラー構文など)と奮闘しながら成長していく成長記録です🐢

Ruby on Rails: devise導入〜ログインユーザーの投稿のみを表示...chapter12-2

deviseは簡単にログイン機能を作成できるgem(ライブラリ)で、deviseを導入しログイン画面を実装していきます。

 

今回作りたいイメージ図↓

 

https://gyazo.com/183a087aa2783223f8644a47ae6a8d48

------------------------------------今回行った事-------------------------------------

①deviseのインストール

②deviseに必要なファイルを生成

③Userモデルの作成

④deviseに対応したビューを作成

⑤deviseに対応したコントローラーを作成

⑥Log in画面のemail→nicknameへ変更

⑦nicknameを入力するフォームの追加

⑧パラメータの許可

⑨認証の変更

⑩ルーティングの設定

①①ログイン時に実行してほしい処理(ビュー)を設定

①②コントローラーの設定

①③ビューの作成(ルートページ)

①④ユーザー登録ができるか確認

①⑤ログアウトするリンクを作成

①⑥ログインできるか確認

①⑦コントローラーの設定(index)

①⑧モデルの設定

①⑨コントローラーの設定(create)

②⓪保存できるか確認

②①ビューの作成

②②ビューの確認

---------------------------------------------------------------------------------------

 

 

①deviseのインストール

Gemfileにgem 'devise'を記述

gem 'devise'

$bundle install

 

 

 

 

②deviseに必要なファイルを生成

$rails g devise:install

1. deviseがメール送付する場合の送付元(WebアプリケーションのURL)の指定

2.ログアウト時のリダイレクト(転送)先URLの指定

3.ログインやログアウトなどの処理結果を表示するメッセージ領域の作成

4.deviseで使用する表示画面用テンプレートの作成(作成しなくても良いが、カスタマイズする場合は作成する必要がある)

と書いてあるが、先にUserモデル、コントローラーを作成します。

 

 

 

③Userモデルの作成

$rails g devise user

db/migrate/20200615074103_devise_create_users.rb(作成されたマイグレーションファイル)を開く

t.string :nickname, null: false, default: ""を追加(※)。

※追加し忘れた場合、後からでも追加できます(忘れた場合は🚨内を行う)。

$rails db:migrate

Sequel Proを確認

usersテーブルとカラムが作成されているか確認します。

 

🚨=========ここはカラムにnicknameを追加し忘れた場合用=========🚨

nicknameを追加し忘れて$rails db:migrate

$rails g migration AddNicknameToUsers nickname:string

作成されたマイグレーションファイルを開く

(db/migrate/〇〇〇〇〇〇_add_nickname_to_users.rb)

class AddNicknameToUsers < ActiveRecord::Migration[6.0]
 def change
 end
end

class AddNicknameToUsers < ActiveRecord::Migration[6.0]
 def change
  add_column :users, :nickname, :string, null: false, default: ""
 end
end

$rails db:migrate

Sequel Proを確認

==============================================================

 

 

 

④deviseに対応したビューを作成

$rails g devise:views users

 

 

 

 

⑤deviseに対応したコントローラーを作成

$rails g devise:controllers users

 

 

 

⑥Log in画面のemail→nicknameへ変更

app/views/users/sessions/new.html.erb

<h2>Log in</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
 <div class="field">
  <%= f.label :email %><br />
  <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
 </div>
 
  ・
  ・ (省略)
  ・
<%= render "users/shared/links" %>

<h2>Log in</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
 <div class="field">
  <%= f.label :nickname %><br />
  <%= f.text_field :nickname, autofocus: true, autocomplete: "nickname" %>
 </div>
 
  ・
  ・ (省略)
  ・
<%= render "users/shared/links" %>

emailと書いてあるところをnicknameへ変更。

email_fieldをtext_fieldへ変更。

 

 

 

⑦nicknameを入力するフォームの追加。

app/views/users/registrations/new.html.erb

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "users/shared/error_messages", resource: resource %>

<div class="field">
<%= f.label :nickname %><br />
<%= f.text_field :nickname, autofocus: true, autocomplete: "nickname" %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
  ・
  ・ (省略)
  ・
 
<%= render "users/shared/links" %>

nicknameを入力するフォームを追加。

 

 

 

⑧パラメータの許可

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
end

class ApplicationController < ActionController::Base
 before_action :configure_permitted_parameters, if: :devise_controller?


 
 protected
 def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname, :email])
  devise_parameter_sanitizer.permit(:sign_in, keys: [:nickname])
 end
end

before_ationは定義されている各アクションの実行前に作動するアクションを書きます。

if: :devise_controller?によってdeviseの使用される画面でのみconfigure_permitted_parametersが使用できるようにしています。

protectedの下にdeviseでのストロングパラメーターを設定します。

 

参照:https://qiita.com/weedslayer/items/c3ab7ad37d5a1e325989

参照:https://qiita.com/kazukisu3/items/7f60574379dcce0422b1

参照:https://qiita.com/ry023/items/c6a469f65615f796be45

 

 

 

 

⑨認証の変更

config/initializers/devise.rb

# config.authentication_keys = [:email]

コメントアウトされているのを解除。

config.authentication_keys = [:nickname]

emailをnicknameへ変更。

emailの代わりにnicknameで認証するようにしています。

 

 

 

 

 

⑩ルーティングの設定

config/routes.rb

Rails.application.routes.draw do

 devise_for :users
 get '/tweets/index', to: 'tweets#index'
 get 'tweets/new', to: 'tweets#new'
 post 'tweets', to: 'tweets#create'
 get 'tweets/:id', to: 'tweets#open'
 delete 'tweets/:id', to: 'tweets#destroy'
 get 'tweets/:id/edit', to: 'tweets#edit'
 patch 'tweets/:id', to: 'tweets#update'

end

Rails.application.routes.draw do
 devise_for :users, controllers: {
 registrations: 'users/registrations',
 sessions: 'users/sessions'
 }
 
 root 'tweets#home'
 get 'tweets/index', to: 'tweets#index'
 get 'tweets/new', to: 'tweets#new'
 post 'tweets', to: 'tweets#create'
 get 'tweets/:id', to: 'tweets#open'
 put 'tweets/:id', to: 'tweets#update'
 delete 'tweets/:id', to: 'tweets#destroy'
 get 'tweets/:id/edit', to: 'tweets#edit'
 patch 'tweets/:id', to: 'tweets#update'

end
 

 

devise_for :users

これはdevise導入で自動に設定されます。

この設定によって認証に必要なルーティングを自動に設定してくれます。

参照:https://pikawaka.com/rails/devise

 

 

controllers: {
 registrations: 'users/registrations',
 sessions: 'users/sessions'
}

 

設定前:

https://gyazo.com/0e3cd1548b63936f7c3c1b24d59197f4

設定後:

https://gyazo.com/c9d188a71f2a6874b82b7e0da219d47a

設定する事によってdevise/〇〇#△△→users/〇〇#△△となります。

 

root 'tweets#home'

rootに設定する事でhttp://localhost:3000/へアクセスするとここへ記述したコントローラーのアクションを介してビューへ反映します。'tweets#home'はこれからコントローラーへ設定します。最初のページ(ルートページ)のための設定。

 

 

 

 

①①ログイン時に実行してほしい処理(ビュー)を設定

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
 before_action :configure_permitted_parameters, if: :devise_controller?


 def after_sign_in_path_for(resource)
  tweets_index_path
 end

 protected
 def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname, :email])
  devise_parameter_sanitizer.permit(:sign_in, keys: [:nickname])
 end
end

after_sign_in_path_for(resource)メソッドにログインした後に遷移したいビューのパスを指定します。

ツイート一覧へ遷移したいのでtweet_index_pathを設定。

(ルーティングを確認したい場合は$rails routes)

 

 

 

 

①②コントローラーの設定

app/controllers/tweets_controller.rb

def home
end

homeメソッドを追加。

homeのビューは「ブログをはじめませんか?」と「『ユーザー登録』へのリンク」、「『ログイン』へのリンク」だけなので特に処理内容は記述しないです。

 

 

 

 

 

①③ビューの作成(ルートページ)

app/views/tweets/home.html.erbを作成。

ブログをはじめませんか?
<br>
<%= link_to "ユーザー登録", new_user_registration_path, class: "sign_up" %>
<br>
<%= link_to "ログイン", new_user_session_path, class: "sign_in" %>

 

 

 

 

①④ユーザー登録ができるか確認

$rails s

http://localhost:3000/

ユーザー登録をクリック

ユーザー登録をする。

まだビューは設定してないのでユーザーが投稿したツイート全てが見られる状態。

 

Sequel Proでも登録ができているか確認。

 

 

 

 

 

①⑤ログアウトするリンクを作成

$rails routes

https://gyazo.com/712a98dc4dbb045c25fec0c7d27706d2

ルーティングを見るとsign_outのところのperfixを見るとdestroy_user_sessionとなっているので、ログアウトのpathは destroy_user_session_path と指定し、さらにmethod: :delete も記述します。

app/views/index.html.erb

<div class="tweets-index">
<h1>投稿一覧</h1>

<%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
 
<% @tweets.each do |tweet| %>
 <div class="tweets-index__table">
  <%= tweet.title %>
  <%=link_to "詳細", "/tweets/#{tweet.id}" %><br>
 </div>
<% end %>
 <div class="tweets-index__table__new">
  <%= link_to "新規作成", "/tweets/new" %>
 </div>
</div>

method: :deleteをコードした理由としてはlink_toのHTTP動詞は'get'だから。

 

$rails s

サーバーを立ち上げてログアウトできるか確認。

http://localhost:3000/tweets/index

ログアウトしてみる

 

 

①⑥ログインできるか確認

先ほどルートページに戻ったのでそのままログインできるかを確かめてみる。

ログインしてみる

 

 

 

①⑦コントローラーの設定(index)

投稿一覧を映すためにコントローラー(indexアクション)でselectを使いtitleとidを取得していました。しかし、これだけではuser_idを使用できないので紐付けてUsersテーブルに作成したnicknameも使用できない。よってindexアクションでの処理を変更します。

app/controllers/tweets_controller.rb

before:

def index
 @tweets = Tweet.select("title", "id")
end

取得できている情報:

https://gyazo.com/2c6168c3fb1737dcbbde9776f3abca3c

after:

def index
 @tweets = Tweet.all
end

取得できている情報:

https://gyazo.com/1a6dc1ac80bfe8c7f23114bb6088d245

 

Tweet.allとすることでuser_idも使用できるようになりました。

 

 

①⑧モデルの設定

tweetモデルとuserモデルを紐付けなければ各ユーザーごとにツイートを管理することはできないので、ユーザーとツイートの関係性をコードする必要があります。

READMEにも書いたがユーザーとツイートの関係性はユーザー1人に対してツイートはたくさんできるので1対多の関係にあります。

なので、各モデルは以下のようになります。

user.rb

 tweet.rb

 

 

①⑨コントローラーの設定(create)

 

app/controllers/tweets_controller.rb

def create
 create = Tweet.create(tweet_params)
end

def create
 tweet = Tweet.new(tweet_params)
end

Tweet.newでインスタンスを生成し、tweet_paramsでストロングパラメーターを設定する。それを変数tweetへ代入。

def create
 tweet = Tweet.new(tweet_params)
 tweet.user_id = current_user.id
end

current_userはdeviseを導入したら使えるメソッド。

current_userを使用し、ログインしているユーザーを取得します。

そして、登録したユーザーはusersテーブルの中でidで管理されています。

https://gyazo.com/8f2b04ce4292ea1ac8bbd32c20c43e3d

なのでcurrent_user.idとするとこのidが取得できます。

このidをtweetsテーブルのuser_idでも使用できるようにtweet.user_idにこの値を代入しています。

def create
 tweet = Tweet.new(tweet_params)
 tweet.user_id = current_user.id
 tweet.save
end

user_idも取得できるようになったのでユーザーが投稿したツイートを保存できるようにsaveでツイート情報をDBに保存。

 

 

 

②⓪保存できるか確認

投稿をしてみる

$rails s

http://localhost:3000/tweets/index

投稿してターミナルを見てみる

https://gyazo.com/e5baaebcc04895eee4f71dfe2c74567d

投稿は成功していそうだ。

一覧へ戻って確認してみる。

これでuser_idも取得できたので次にビューを作成していきます。

 

 

 

 

②①ビューの作成

app/views/tweets/index.html.erb

<%= current_user.nickname %>さんがログイン中<br>

deviseで使用できるメソッド(current_user)を使いnicknameを取得し表示。

ID:<%= current_user.id %><br>

上と同様にcurrent_userを使用して、idを取得して表示。

<% if user_signed_in? %> <% end %>

もしログインしているユーザーならこの中の処理をする。

<% if tweet.user_id == current_user.id %> <% end %>

tweet.user_idこれはtweetsテーブルに存在するuser_idがログインしているユーザーのid(current_user.id)と等しければこの中の処理をする。

この中での処理はタイトルや詳細がコードされているので、これでログインしているユーザーのツイートのみが閲覧できるようになります。

 

 

 

 

 

②②ビューの確認

$rails s

http://localhost:3000/tweets/index

できているみたい。

ログアウトして新しいユーザーを登録して投稿一覧を見てみる。

sign upしてみて。。。

aaaが投稿したツイートが消えている。

投稿してみる。

 

 投稿がユーザーbbbのだけ表示されている。

 

参照:https://qiita.com/Hal_mai/items/350c400e8763ce0487a3

参照:https://web-camp.io/magazine/archives/16811

参照:https://url4u.jp/rails-523-devise-username-auth/

参照:https://www.youtube.com/watch?v=Lmq_WLkxp9c&t=522s

 

 

 

 

この記録を書きながら再度実装していたのが、モデルを設定し忘れていて保存できなくて手こずってしまいました。

アソシエーションのテーブルが増えたら設定する!忘れないようにしないとね😅

 

 

 

 

 

 以上です。