No_ideaのわからん日和

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

Ruby on Rails: チャットグループ機能(アイコン表示)の実装(CarrierWave使用)...chapter15

今日はusersテーブルとchat_groupsテーブルにアイコンを保存できるように各user_iconカラムとchat_group_iconカラムを追加したいと思います。

そして↓のようにユーザーページにアイコンを編集できるようにして、チャットグループでもアイコンを選べるようにして表示できるようにしていきたいと思います。

 

イメージ図:

 

やりたいこと

①DB設計(README)にアイコンを追加する

②カラム追加

③CarrierWaveの導入

④コントローラーの編集(chat_groups_controller.rb)

⑤ビューの編集(chat_groups/new.html.erb, edit.html.erb)

⑥コントローラーの編集(users_controller.rb)

⑦ルーティングの編集

⑧パスの変更

⑨ユーザーページの編集及び編集ページを作成

⑩ユーザーページのアイコンを表示

①①チャットグループへアイコンを表示

①②各アイコンを整える

 

①DB設計(README)にアイコンを追加する

## usersテーブル
|Column|Type|Options|
|------|----|-------|
|nickname|string|null: false|
|email|string|null: false|
|password|string|null: false|
|user_icon|string||
 
|Column|Type|Options|
|------|----|-------|
|chat_group_name|string|null: false|
|chat_group_description|text||
|chat_group_icon|string||

user_icon、chat_group_iconをstring型で追加します。

 

 

 

 

 

②カラム追加

各テーブルにアイコンを保存できるようにカラムを追加していきます。

最初はusersテーブルに追加していきます。

$rails g migration AddUser_iconToUsers user_icon:string

invoke  active_record

create    db/migrate/20200702130354_add_user_icon_to_users.rb

class AddUserIconToUsers < ActiveRecord::Migration[6.0]
 def change
  add_column :users, :user_icon, :string
 end
end

$rails db:migrate

https://gyazo.com/c86ff3c62fd5a9eaf928fc88c1e2adef

 

chat_groupsテーブルにも追加していきます。

$rails g migration AddChat_group_iconToChat_groups chat_group_icon:string

invoke  active_record

create    db/migrate/20200702131112_add_chat_group_icon_to_chat_groups.rb

class AddChatGroupIconToChatGroups < ActiveRecord::Migration[6.0]
 def change
  add_column :chat_groups, :chat_group_icon, :string
 end
end

$rails db:migrate

https://gyazo.com/09cb4fa9cf93f2b7ac75ebe0479af2f7

 

 

 

 

③CarrierWaveの導入

Gemfile

gem 'carrierwave'

$bundle install

$rails g uploader image

create  app/uploaders/image_uploader.rb

このファイルで保存方法を設定できる。

app/models/user.rb

class User < ApplicationRecord
 # Include default devise modules. Others available are:
 # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
 devise :database_authenticatable, :registerable,
 :recoverable, :rememberable, :validatable
 has_many :tweets
 has_many :chat_group_to_users
 has_many :chat_groups, through: :chat_group_to_users

 mount_uploader :user_icon, ImageUploader
end

mount_uploader :user_icon, ImageUploaderを追加。

 

app/models/chat_groups.rb

class ChatGroup < ApplicationRecord
 has_many :chat_group_to_users
 has_many :users, through: :chat_group_to_users

 
 mount_uploader :chat_group_icon, ImageUploader
end

mount_uploader :chat_group_icon, ImageUploaderを追加。

 

✍️ mount_uploader :(カラム名), (アップローダークラス)

modelに記述することにより画像をアップロードした際にImageUploaderクラスの設定を利用できるようになります。

アップロードされた画像はpublic/uploads下へ保存されます。

 

$rails s(再起動)

これで準備完了です。

 

参照:https://qiita.com/nekotanku/items/5da43600f35eada64eac

参照:https://qiita.com/ttaka66/items/264dcb85e41f9135685c

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

 

 

 

 

 

④コントローラーの編集(chat_groups_controller.rb)

app/controllers/chat_groups_controller.rb

https://gyazo.com/400d0245070037c7d38f6c7042832705

newメソッド

@chat_group_new.users << current_user

・current_user

ログインしているユーザー

・<<

尖っている方に開いている方の情報を付け加える(@chat_group_new.usersへ情報を付け加えている)

@chat_group_new

chat_groupsテーブルのインスタンス

・.users

.usersで@chat_group_newに所属しているusersテーブルのレコードを配列[]で取得できる。

これでログインしているユーザー(current_user)を@chat_group_new(chat_groupsテーブルのインスタンス).users)に加える(<<)ことができます。

 

https://gyazo.com/f2f6f12730330cdf45386fde83acf523

ストロングパラメーターに:chat_group_iconを追加。

 

 

 

 

 

 

⑤ビューの編集(chat_groups/new.html.erb,edit.html.erb)

先にチャットグループ新規作成でアイコンを保存できるようにしたいと思います。

https://gyazo.com/ff25eafa6a342e6903bb9e50284f79c4

 

file_fieldはファイル入力ボタンを作成します。

:chat_group_icon(カラム名)を指定して、今回はchat_group_iconカラムに保存できるようにしています。

http://localhost:3000/chat_groups/new

新規作成してみます。

 

 

次は編集ページでも画像をアップロードできるようにします。

https://gyazo.com/d5b0c16d4af5786991e79889786e4ca4

http://localhost:3000/chat_groups/8/edit

ファイルを選択できるようになったので編集してみます。

編集前:

編集後:

icon_kari.png → tsuki.png へ変更できているので成功です!

 

 

 

 

⑥コントローラーの編集(users_controller.rb)

https://gyazo.com/3624de02731658ae98959c22c20132d6

 

ユーザーページから『アカウント設定』リンクをはり、ニックネームとアイコンを編集できるようにしたいので、user_pageでログインしているユーザーのidを取得し、@user_infoに代入。

editメソッドでもユーザーのidを取得しインスタンス変数へ代入することで編集ページへ情報を渡せるようにしました。

そしてupdateメソッドでも同様にユーザー情報をedit_userへ代入し、ストロングパラメーター を通して、updateメソッドで編集した内容を保存できるようにしました。

ストロングパラメーターで許可したのは編集できるようにしたいnicknameとuser_iconをpermitに設定しました。

 

 

 

 

 

⑦ルーティングの編集

https://gyazo.com/4b069503182affd9b264961a63918bac

resourcesを使って一括に設定。

その中でも今回使うのはeditアクションとupdateアクションなのでonly: [:edit, :update]とすることでこの2つのルーティングを設定しました。

また、user_pageはonlyで設定できないので、追加したいアクションを記述できるcollectionを使ってブロック内に記述しました。

しかし、これだとprefixのpathが変わってしまうのでサインアップ、ログイン後のpathを変更しないといけません。

なので、変更していきます。

 

 

 

 

⑧パスの変更

app/controllers/application_controller.rb

def after_sign_in_path_for(resource)
 users_user_page_users_path
end

 

app/views/chat_groups/index.html.erb

<div class="chat-group__user-page">
 <%= link_to 'ユーザーページへ', users_user_page_users_path %>
</div>

 

 

 

 

 

 

⑨ユーザーページの編集及び編集ページを作成

先にユーザーページの編集をします。

https://gyazo.com/701067588f35ea73d4ad0753ed18f460

編集ページへのパスは/users/:id/editなのでlink_toメソッドを使用し、パスは"/users/#{@user_info.id}/edit"としました。

app/views/users/edit.html.erbを作成。

https://gyazo.com/80380b0b39a93fa5687765ac2b5b285a

updateへのpathは/users/:idなのでurl: "/users/#{@edit_user.id}"を設定。

また、form_withのデフォルトHTTP動詞はpostなのでmethod: :patchを設定。

ユーザーページから『アカウント設定』をクリック。

編集してみます。

https://gyazo.com/662fd586bfac5a928a26f2079b1c0bba

大丈夫そう。

 

 

 

 

 

 

⑩ユーザーページのアイコンを表示

ここで注意しなければならないのはアイコンを登録してないユーザーはデフォルトアイコン画像↓

f:id:No_idea:20200703095316p:plain

でなければならないことです。

なので最初にデバッグをしながら処理内容を決めていきたいと思います。

user_page.html.erb

<%= debug @user_info.user_icon.file%>

分かりやすいように一番下でdebugをしてみます。

@user_infoにはユーザー情報が含まれています。

その中でuser_iconのfileはどうかをアイコン登録者と未登録者で比較してみます。

アイコン登録者:

未登録者:

登録してあるユーザーではfile:のところにどこにアイコン画像が保存されているか書かれています。

しかし、未登録者では...となっていて何も書いていません(nil)。

これを使ってif文で分岐させて処理させれば良さそうです。

app/controllers/users_controller.rb

def user_page
 @user_info = User.find(current_user.id)

 if @user_info.user_icon.file != nil
  @user_icon = @user_info.user_icon.url
 else
  @user_icon = 'user_icon_default.png'
 end
end

fileがある、つまり登録者は@user_iconへアイコンのurl(どこへ保存されているか)の情報を代入。

未登録者では@user_iconへデフォルトアイコン画像を代入しています。

次にビューを編集していきます。

app/views/users/user_page.html.erb

image_tagに@user_iconとコードすることでアイコンのurlを代入します。

http://localhost:3000/users/users/user_page

登録あり:

 

登録なし:

ユーザーページでのユーザーアイコンの表示は問題なさそうです。

 

 

 

 

 

 

①①チャットグループへアイコンを表示

現在のチャットグループは↓のような表示になっています。

なのでチャットグループへアイコンを表示してみたいと思います。

イメージ図:

まだチャットグループへのメンバー登録機能は実装していないので、アイコンはグループ作成者のみアイコンが表示されるようにしたいと思います。

ここでも注意することがあります。先ほどと同様にアイコンを登録していない人はデフォルトアイコンを表示させるようにしなければなりません。

また、チャットグループのアイコンも同じで登録していない場合はデフォルトの画像を表示しなければなりません。

今回使用するチャットグループデフォルトアイコンは↓のものにしようと思います。

f:id:No_idea:20200703105918p:plain
それではやっていきたいと思います。

 

最初にチャットグループのアイコンが表示できるようにします。

app/controllers/chat_groups_controller.rb

def show
 @chat_group = ChatGroup.find(params[:id])
 
 if @chat_group.chat_group_icon.file != nil
  @chat_group_icon = @chat_group.chat_group_icon.url
 else
  @chat_group_icon = 'group_icon_default.png'
 end

end

ユーザーのアイコン表示と同じようにアイコンのファイルが何もない(nil)場合= 画像がある場合は@chat_group_iconにアイコンのurlを代入。

なければ@chat_group_iconにデフォルトアイコン画像を代入。

app/views/chat_groups/show.html.erb

 

登録あり:

 

登録なし:

アイコンを表示することに成功しました。

次にユーザーアイコンを表示させます。

app/controllres/chat_groups_controller.rb


def show
@chat_group = ChatGroup.find(params[:id])
 
    .
    . (省略)
    .
@chat_members = ChatGroupToUser.where(chat_group_id: @chat_group.id)
@chat_member_info = User.find(@chat_members.ids)
end

@chat_group

ここではchat_groupsテーブルから表示する情報をidから引っ張り出してきます。

これでレコード(横{行})が取得できました。

@chat_members

ここではwhereメソッドを使用し、chat_group_idカラムの中で@chat_group.id(表示したいページのid)を中間テーブル(chat_groupとuser)から探してきます。

これで同じチャットに参加しているメンバーのidも取得できるようになりました。

@chat_members_info

先ほどの@chat_membersを使用し、参加メンバーの情報を取得します。

@chat_members.idではなく@chat_members.idsで複数のユーザーの情報を取得できます。

app/views/chat_groups/show.html.erb

https://gyazo.com/92804441949ae74f811590bf8065ab64

ユーザーページのアイコンやチャットグループのアイコンのように1つだけの画像を表示ならばコントローラーへコードしインスタンス変数を持ってくれば大丈夫なのですが、2つ以上のアイコンを表示する場合、つまり情報を一つ一つ取り出す際はhtmlの方で分岐をコードしなければいけないみたいです。

each do |〇〇|で一つずつユーザー情報を取り出す処理をしています。

今は作成者のみですが、今後メンバー追加するときにこれでメンバーのアイコンを表示することができます。

コードできたので表示されるかやってみます。

登録あり:

登録なし:

できてます。

最後にアイコンを丸くし整えます。

 

 

 

 

①②各アイコンを整える

チャットグループでのアイコン(グループアイコン、ユーザーアイコン)を丸く表示したいので、今回は@mixinと@includeを使用してスタイル(今回は大きさと丸くするスタイル)を使い回したいと思います。

@mixinと@includeはセットで使用します。

これを使うと共通のスタイルが多い場合とかにコードが楽になります。

また、コードも見やすくなり一石二鳥です✌️

参照:https://stand-4u.com/css/sass/mixin.html

 

 

app/assets/stylesheets/chat_groupsフォルダを作成。

app/assets/stylesheets/mixinフォルダを作成。

app/assets/stylesheets/chat_groups/show.scssファイルを作成。

app/assets/stylesheets/mixin/_icon_setting.scssファイルを作成。

app/assets/stylesheets/application.scss

@import "mixin/icon_setting";
@import "users/user_page";
@import "chat_groups/show";

これで使えるscssが使用できるようになりました。

app/assets/stylesheets/chat_groups/show.scss

https://gyazo.com/5755c84bb5086403be8e4b4ad88b5297

大きさと丸みの設定してみました。

これでよかったら @mixinと@includeを使用して書いていきたいと思います。

app/assets/stylesheets/mixin/_icon_setting.scss

@mixin chat_icon {
 height: 50px;
 width: 50px;
 border-radius: 50%;
}

@mixin (任意の付けたい引数名){

  (処理内容)

}

 

app/assets/stylesheets/chat_groups/show.scss

https://gyazo.com/834e69f01ecf19a5e914d3966edc624a

@inculde (@mixinで付けた引数名);

これで@mixinから@inculdeにデータが引き継がれ使えるようになります。

では、ビューを確認してみます。

完成しました。

 

 

 

 

 

 

 

次回はチャットメンバーを追加できるように実装していきたいと思います。

その際に、インクリメンタルサーチ(入力した文字に該当する候補を出してくれる機能)と非同期通信(ページを遷移せずに一部だけを更新できる機能)を使用し追加できるようにします。

この2つスクールで学習してましたが、とりあえず完成させて提出したって感じで理解できないままやってましたね^^;

そのせいで実装に苦労しました。

このブログでもう一度実装し、記憶を定着させられるようにしたいと思います。

 

インクリメンタルサーチhttps://gyazo.com/f0f6a5b5ed8ebf2d6477373d0da548f9

 

 

非同期通信:https://gyazo.com/6644ad0a2b4eca5249326856dbb20ce7

 

 

 

 

 

 

 

以上です。

Ruby on Rails: チャットグループの詳細ページ、編集、削除機能の実装...chapter14

今日やりたいこと

・チャットグループの詳細ページの作成

・チャットグループ編集機能の実装

・チャットグループ削除機能の実装

 

この3つをやろうと思います。

最初にチャットグループの詳細ページを作成します。

 

①チャットグループの詳細ページの作成

1.コントローラーの編集

app/controllers/chat_groups_controller.rb

def show
 @chat_group = ChatGroup.find(params[:id])
end

ChatGroupモデルを使用し、params[:id]を使用しchat_groupsテーブルからidを探してチャットグループ情報を取得。

@を変数につけてインスタンス変数にして@chat_groupに取得したチャットグループ情報を代入。

 

2.詳細ページの作成

app/views/chat_groups/show.html.erbを作成。

https://gyazo.com/08889858d742773eb9528663d6bd8e20

チャットグループの説明

<% if @chat_group.chat_group_description != "" %>

もしchat_groupsテーブルのchat_group_description(グループの説明)カラムが空欄なら。。。

<div class="chat-group-show__description">
 <span class="chat-group-show__description--content">説明:</span>
 <span class="chat-group-show__description--des">
  <%= @chat_group.chat_group_description %>
 </span>
</div>

説明を表示してください。

<% else %>

それ以外なら(説明文がない場合)。。。

<div class="chat-group-show__none">
説明文はありません。
</div>

『説明文はありません。』と表示してください。

<% end %>

if文終了してください。

 

3.詳細ページの確認

/説明文がない場合

//説明文がある場合

 

 

②チャットグループ編集機能の実装

現在一覧ページは↑のようになっています。

メンバーカウント数の横に編集リンクを作りたいと思います。

そして、編集フォームに保存されているグループ名と説明をフォームに表示させるようにしたいと思います。

 

1.編集リンクを作成

一覧ページに編集リンクをつけていきます。

$rails routes

  edit_chat_group GET    /chat_groups/:id/edit(.:format)                                                          chat_groups#edit

app/views/index.html.erb

http://localhost:3000/chat_groups

 

 

2.コントローラーの編集

app/controllers/chat_groups_controller.rb

def edit
 @edit_chat_group = ChatGroup.find(params[:id])
end
 
def update
 update_chat_group = ChatGroup.find(params[:id])
 update_chat_group.update(chat_group_params)
end
 
private
def chat_group_params
 params.require(:chat_group).permit(:chat_group_name, :chat_group_description, user_ids:[])
end

editアクション

先ほどの詳細ページ(showメソッド)と同じ処理。

今回はインスタンス変数を@edit_chat_groupとしました。

 

updateアクション

チャットグループを探し、変数update_chat_groupへ情報を代入。

編集して送られてきた情報をストロングパラメーター(chat_group_paramsメソッド内)にかけている情報だけを通す。

そしてupdateメソッドを使用し、内容を更新してDBへ保存。

 

3.編集ページの作成

app/views/chat_groups/edit.html.erbを作成

https://gyazo.com/07ac61e8b45b19496f41dcaabefefa48

form_withのデフォルトHTTP動詞は'post'なので、methodでpatchを指定。

url

PATCH  /chat_groups/:id(.:format)    chat_groups#update

$rails routesで確認。

url: '/chat_groups/#{@edit_chat_group.id}'

これでupdateアクションへ行けそうです。

チャットグループ一覧ページから[編集]をクリック。

これを編集してみます。

これで編集するボタンをクリックし、一覧ページへ戻ってみると。。。

 

詳細ページ:

大丈夫そうです。

 

 

 

 

③チャットグループ削除機能の実装

最後にチャットグループを削除できるようにしていきます。

 

1.コントローラーを編集

def destroy
 delete_chat_group = ChatGroup.find(params[:id])
 delete_chat_group.destroy
end

チャットグループを探して、destroyメソッドで削除を指示。

2.削除リンクを貼る

 

編集の横に削除パスを貼ります。

 

$rails routes

DELETE /chat_groups/:id(.:format)        chat_groups#destroy

パス先は"/chat_group/#{list.id}"。

3.ビューの編集

app/views/chat_groups/index.html.erb

link_toのデフォルトHTTP動詞は'get'なので methodを使用して'delete'と指定。

4.確認

http://localhost:3000/chat_groups

削除できるかやってみます。

グループ3を削除してみます。

[削除]をクリック

http://localhost:3000/chat_groups

削除できてます。

 

 

 

 

今回は過去の復習でした。

昔だったら時間をかけて作っていたと思いますが、今回はすらすら作成できました😄

 

 

 

 

 

 

 

 

 

以上です。

Ruby on Rails: チャットグループ一覧ページの作成...chapter13-4

今回やりたいこと

・グループの新規作成機能の実装

・チャットグループ一覧からチャット新規作成ページへ遷移できるようにする

・チャットグループ一覧へ所属するグループ名と参加人数を表示。

 

①chat_groups_controller.rbの編集

$rails routes

https://gyazo.com/4065f05257221c26bb9a47d043aac3ee

app/controllers/chat_groups_controller.rb

def new
 @chat_group_new = ChatGroup.new
end

ChatGroupモデルを使用し、newでインスタンスを生成。

 

 

 

 

 

 

②新規作成ページを作成(仮) + チャットグループ一覧ページから新規作成ページへリンク

app/views/chat_groups/new.html.erbを作成

app/views/chat_groups/index.html.erb

(修正前)
<div class="chat-group__new">
<%= link_to 'グループ新規作成', chat_groups_path %>
</div>
(修正後)
<div class="chat-group__new">
 <%= link_to 'グループ新規作成', new_chat_group_path %>
</div>

リロード🔁

http://localhost:3000/chat_groups

グループ新規作成クリック

これで新規作成ページに遷移できるようになりました。

 

 

 

 

 

 

 

③新規作成ページを作成

app/views/chat_groups/new.html.erb

form_withを使用しcreateアクションのパスへ飛ばしたいので、パスはchat_groups_path。

さらにmodelを使用し、どこのテーブルに情報を送りたいのかを示します。

リロード🔁

フォームは出来ました。

次にこのフォームで入力した情報を保存できるようにcreateアクションを作成し、保存できるようにします。

 

 

 

 

 

④コントローラーにcreateアクションを追加

def create
 chat_group_new = ChatGroup.new(chat_group_params)
 if chat_group_new.save
  redirect_to action: 'index', notice: 'チャットグループを作成しました'
 else
  render :new, alert: 'チャットグループ作成に失敗しました'
 end
end

private
def chat_group_params
 params.require(:chat_group).permit(:chat_group_name, :chat_group_description)
end

createアクションの処理内容

ChatGroup.newでインスタンス生成をして、変数chat_group_newに代入。

その際に、いらない情報も保存されないようにストロングパラメーターを設定。

もしchat_group_newがセーブできたら、簡易メッセージで'チャットグループを作成しました'と表示し、リダイレクト(遷移先)にindexアクションを設定。

情報をセーブできない場合はアラートとして'チャットグループ作成に失敗しました'と表示。

 

 

 

 

⑤情報を保存できるか確認

$rails s

新規作成してみると。。。

新規作成ボタンをクリックした瞬間にindexページへ遷移する。

アドレスバーにチャットグループを作成しましたと簡易メッセージが表示される。

Sequel Proでもみてみる。

保存できている。

 

しかしチャットグループを作成した場合、”チャットグループリスト表示”されないとおかしいです。

def index
 @chat_group_lists = ChatGroup.all
 @chat_group_joining = ChatGroupToUser.where(user_id: current_user.id)
 @chat_group_lists_none = "チャットグループに参加していません"
end

理由としてはこのチャットグループ一覧ページで設定したif @chat_group_joining == にあります。

これはindexアクションでの処理内容ですが、@chat_group_joining = ChatGroupToUser.where(user_id: current_user.id)でChatGroupUserToUserモデルを使用し、chat_group_usersテーブル(中間テーブル)からuser_idカラムからログインしているユーザーを探してきてと命令しています。

なのでchat_group_usersテーブルにログインしているユーザーがないと”チャットグループリスト表示”は表示されません。

 

chat_group_usersテーブルをみてみます。

やはり、保存されていません。

なので保存されるように設定していきたいと思います。

 

 

 

 

 

 

⑥保存できるように修正

app/views/chat_groups/new.html.erb

<h1>チャット新規作成</h1>
 
<%= form_with url: chat_groups_path, model: @chat_group_new do |f| %>
<%= text_field_tag 'chat_group[user_ids]', "#{current_user.id}", type: 'hidden' %>
<div class="chat-group-new__forms">
<div class="chat-group-new__forms__name">
<%= f.label :chat_group_name, 'グループ名', class: "chat-group-new__forms__name--label" %>
<%= f.text_field :chat_group_name, class: "chat-group-new__forms__name--field" %>
</div>
        ・
        ・ (省略)
        ・

text_field_tag 'chat_group[user_ids][], "#{current_user.id}", type: hidden'

text_field_tagはフォームを作成し、送りたい情報を送れるようにするメソッドです。

構成は以下のようになっています。

text_field_tag (テキストボックス名, 初期文字列, {オプション1, オプション2,,,})

 

テキストボックス名

テキストフィールドのidとnameに割り当てられる。

フォームからの値を取得するキーになる。

 

初期文字列

テキストフィールドのデフォルト値。

指定された文字列が入力された状態で表示される。

 

オプション

今回はtype: hiddenを設定。

これで情報は送れるが、フォームはなくなります。

type: hidden設定なし

 

type: hidden設定あり

これで送られている情報は↓のようになっている。

<input type="hidden" name="chat_group[user_ids][]" id="chat_group_user_ids_" value="5"
  />

これで一旦グループを作成してみる。

保存はできているが、「参加していません」になっている。

理由は

https://gyazo.com/1c55a541b0afaa610748aa26bcad6f59

ストロングパラメーターにuser_idsを受け取れるようにしていない。

とりあえず、ストロングパラメーターにuser_idsを設定してみる。

:user_idsとしたのは

Parameters: {"authenticity_token"=>"daUxVjXs0ZCF6gsdjnb1ZLDTOUJExuUKKpOtOEPB973R+V5o54jNR8P0Rkb+rfkXqhO24w+2Vt1WmvzmBY9Jvw==", "chat_group"=>{"user_ids"=>["5"], "chat_group_name"=>"グループ2", "chat_group_description"=>"グループ2"}, "commit"=>"新規作成"}

Unpermitted parameter: :user_ids

user_idsを受け取るときに配列となっている。なので、配列で受け取れるようにを設定。

これでリロードし、作成してみる。

リロード🔁

新規作成してみる。

遷移できてない。

https://gyazo.com/afeee14471c243f133441bd768bd7f42

今度はエラー内容をみてみると、

ArgumentError (wrong number of arguments (given 0, expected 1..2)):

ArgumentError(引数の数が間違っている(0の場合、1..2が必要)):

と書いてある。

また、

app/controllers/chat_groups_controller.rb:26:in `'

app/controllers/chat_groups_controller.rb:26:in `chat_group_params'

app/controllers/chat_groups_controller.rb:15:in `create'

これはこの書いてあるところが怪しいと言っています。

:user_ids→user_ids:へ変更。

リロード🔁

新規作成してみる。

https://gyazo.com/800f1e7c3dd376377105ef8c94d4aaa6

ActiveModel::UnknownAttributeError (unknown attribute 'user_ids' for ChatGroup.):

このエラーを解決していきます。

$rails c

pry> show-models

ChatGroupの

has_many :chat_group (through :chat_group_to_users)

ここが間違ってました。ここは中間テーブルのchat_group_to_usersを経由してusersテーブルと紐付けると示す場所なのにchat_groupテーブル(しかもhas_manyなのに複数形にもしてない...)に紐づけてしまっています。

なので、has_many :users (through :chat_group_to_users)と変更。

これでトライしてみます。

$rails s

チャットグループリスト表示になりました!

Sequel Proも開いて確認。

中間テーブルにも保存されています!

 

それでは次はチャットグループ一覧ページに所属するチャットグループと所属人数が

 

 

 

 

 

 

⑦グループ一覧ページに所属するチャットグループ名と所属人数を表示する。

https://gyazo.com/bac3874bccce832c6de2605713c982bf

 

<% else %>~<% end %>を変更。

@chat_group_list.each do |list| ~ end

ここで、chat_groupsテーブルに入っている情報(今回はグループ1〜3まで)を繰り返し、一つ一つ取り出してます。

 

if list.user_ids.include?(current_user.id) ~ end

そのDBに保存されているuser_id達の中にcurrent_user(ログインしている)ユーザーは含まれているかを聞いてます。

 

link_to "/chat_groups/#{list.id}" do ~ end

まだグループの詳細ページは作成していませんが、詳細ページへ飛べるように式展開を使用しリンクを貼りました。

 

list.chat_group_name

ここで、所属しているチャットグループ名を表示。

 

list.user_ids.count

所属しているuser_id達をカウント(countメソッド)してくださいと命令。

 

 

これでリロードしてみてみます。

リロード🔁

できてます。

さらにグループ4も登録してみてみます。

問題なさそうです。

 

 

 

今回はチャットグループを作成し、一覧ページに表示できるようにしました。

エラーがたくさん出て苦労しましたが、エラー構文の勉強になるので良かったかも(?)

次回はチャットグループ詳細ページ、編集、削除を実装していきたいと思います。

 

 

 

 

 

 

 

 

 

以上です。

Ruby on Rails: チャットグループ一覧ページの作成...chapter13-3

今日の完成イメージ図:

今回やること

・ユーザーページからチャットグループ一覧ページへ飛べるようにする。

・グループに参加していなければ『チャットグループに参加していません』と表示する。

 

 

①チャットグループのコントローラー作成

$rails g controller chat_groups

 

 

 

②ルーティングを設定

config/routes.rb

resources :chat_groups

 

 

 

③コントローラーのアクションの設定

 

app/controllers/chat_groups_controller.rb

class ChatGroupsController < ApplicationController

 def index
 end
end

 

 

 

④ビューの作成(仮)

app/views/chat_groups/index.html.erbを作成。

<div class="chat-group">
 <h1>チャットグループ一覧</h1>
</div>

 

 

 

 

⑤ユーザーページからチャットグループ一覧へのリンクを作成

ユーザーページのチャットからチャットグループ一覧ページへのリンクを作る。

 

$rails routes

https://gyazo.com/0b1dea5a33975709270a8040ec2fca8d

app/views/users/user_page.html.erb

(修正前)
<div class="user-page__left-link__chat">
 <%= link_to "チャット", users_user_page_path %>
</div>
(修正後)
<div class="user-page__left-link__chat">
 <%= link_to "チャット", chat_groups_path %>
</div>

$rails s

http://localhost:3000/users/user_page

チャットをクリック

チャットグループ一覧ページへの遷移できた。

 

 

 

 

 

 

⑥チャットグループ一覧のビューの作成(仮)

https://gyazo.com/16fb5d173a0d4cb0e9d90085339758f3

 

ビュー

 

 

 

⑦作成したグループがない場合、『グループに参加していません』を表示

 

app/controllers/chat_groups_controller.rb

@chat_group_joining

ここでchat_group_to_usersテーブルからログインしているユーザーのidが存在するかを探している。

app/views/chat_groups/index.html.erb

https://gyazo.com/09387b386694e14c038c116384faa1d8

$rails s

http://localhost:3000/chat_groups

 

今回はチャットグループ一覧ページへ遷移できるようにした。

前は調べながら作成していたが、調べずに作成できるようになってきた。

 

 

 

 

 

次回やりたいこと

・グループを作成できるようにする

・チャットグループ一覧からチャット新規作成ページへ遷移できるようにする

 

 

 

 

 

 

 

 

 

 

 

 

以上です。

 

Ruby on Rails: 中間テーブルを使用したチャットグループの設定...chapter13-2

今日はチャットグループの設定を行います。

 

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

①DB設計

②モデル、テーブル作成

③モデルの設定

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

 

 

①DB設計

チャットグループを作成します。

チャットグループ一つ一つにはユーザーを沢山持ち、ユーザーは沢山のチャットグループを持つことができます。

イメージ図:

これを多対多の関係と言います。

DB設計図:

しかし、これでは問題があります。

それはDBにあるテーブルに問題が生じてしまいます。

仮にchat_groupsテーブルにuser_idするためのカラムを用意してみるとすると、下の表のようになります。

だが、これは出来ません。

それはカラム一つには一つの値しか入れることが出来ないからです。

つまり、user_idに沢山のユーザーidを入れることはできないということ。

 

そこでこの問題を解決するのが中間テーブルです。

イメージ図:

DB設計図:

これでカラムには値が1つだけ入ることになるので、問題が解決されます。

 

それではREADMEにDBを設計していきます。

## usersテーブル
|Column|Type|Options|
|------|----|-------|
|nickname|string|null: false|
|email|string|null: false|
|password|string|null: false|
 


### Association
- has_many :chat_group_to_users
- has_many :chat_groups, through: :chat_group_to_users


 
  ・
  ・ (省略)
  ・


<!-- ユーザーとチャットグループの中間テーブル -->
## chat_group_to_usersテーブル
|Column|Type|Options|
|------|----|-------|
|user_id|integer|null: false, foreign_key: ture|
|chat_group_id|integer|null: false, foreign_key: ture|

### Association
- belongs_to :user
- belongs_to :chat_group




## chat_groupsテーブル
|Column|Type|Options|
|------|----|-------|
|chat_group_name|string|null: false|
|chat_group_description|text||

### Association
- has_many :chat_group_to_users
- has_many :users, through: :chat_group_to_users


 

今回はチャットグループではチャットグループ名とそのチャットグループに関する説明を付けたいと思うのでカラムはchat_group_nameとchat_group_descriptionを作成。

chat_group_nameは文字列であり、長く無いので型はString型。

さらにチャットグループ名は必ず入力しなければならないようにしたいので、null: false。

chat_group_descriptionはその作成したチャットグループの説明を入力したいので型はText型。

この説明は別に入力しなくても良いことにしたいのでオプションは付けないことにします。

 

次に中間テーブル。

中間テーブル名はchat_group_to_usersテーブル。

ここで管理するのはuser_idとchat_group_id。

この二つは整数で管理するので型はInteger。

さらにこの整数は必ずなくてはならないので空(何も無い状態)では保存できないようにnull: falseを設定。そして、この2つは外部キーとなります。

外部キーとは、他のテーブルの情報(今回はusersテーブルのid=user_idと、chat_groupsテーブルのid=chat_group_id)を使用すると言うこと。

これをforeign_keyで設定する。よって、foreign_key: trueとしてuser_idカラムとchat_groupカラムに設定。

 

次にusersテーブルとchat_groupsテーブルのアソシエーション について。

イメージ図:

まずはusersテーブルのアソシエーション について。

イメージ図をみるとusersテーブルと中間テーブルでは1対多の関係になっているので、has_many :chat_group_to_usersを設定。

さらにchat_groupsテーブルとの関係性だが、先ほども述べたように多対

多の関係性であるので、has_many :chat_groupsを設定します。しかし、このchat_groupsテーブルは一旦chat_group_to_usersテーブル(中間テーブル)を経由しての関係性なので、through :chat_group_to_usersを設定してあげます(throughの英単語の意味は『...を通って』)。

 

次にchat_groupsテーブルのアソシエーション について。

usersテーブルと同じように、chat_groupsテーブルとchat_group_to_usersテーブル(中間テーブル)との関係性は1対多。

なので、has_many :chat_group_to_usersと設定。

そして、usersテーブルとの関係性は多対多なのでhas_many :usersを設定します。そして、このhas_many :usersはchat_group_to_usersテーブルを経由しての関係なので、through :chat_group_to_usersを設定します。

 

そして最後に中間テーブルのアソシエーションについて。

中間テーブルとusersテーブルの関係性は多対1なので、belongs_to :user。

中間テーブルとchat_groupsテーブルの関係性は多対1なので、belongs_to :chat_groupと設定。

これでテーブルの設定、アソシエーションの設計が終わったので、chat_groupsテーブルとchat_group_usersテーブルの作成、モデルの作成をします。

参照:https://qiita.com/ramuneru/items/db43589551dd0c00fef9

 

 

 

 

②モデル、テーブル作成

1. chat_groupのモデルとテーブル作成

$rails g model ChatGroup chat_group_name:string chat_group_description:text

db/migrate/20200623071132_create_chat_groups.rb

class CreateChatGroups < ActiveRecord::Migration[6.0]
(修正前)
 def change
  create_table :chat_groups do |t|
   t.string :chat_group_name
   t.text :chat_group_description

   t.timestamps
  end
 
     ↓
(修正後)
 def change
  create_table :chat_groups do |t| 
   t.string :chat_group_name, null: false
   t.text :chat_group_description

   t.timestamps
  end
 
 end
end

$rails db:migrate

 

 

2.中間テーブル、モデルの作成

$rails g model ChatGroupToUser

db/migrate/20200623072426_create_chat_group_to_users.rb

class CreateChatGroupToUsers < ActiveRecord::Migration[6.0]
(修正前)
 def change
  create_table :chat_group_to_users do |t|
 
   t.timestamps
  end
 
     ↓
 
(修正後)
 def change
  create_table :chat_group_to_users do |t|
   t.references :chat_group, foregin_key: true
   t.references :user, foregin_key: true

   t.timestamps
  end
 
 end
end

references

英単語での意味『参照』。

references型を使用する目的としては、

  1. user_idやchat_group_idなど〇〇_idと言うカラムを自動で作成してくれる
  2. インデックスを自動に張ってくれる

・user_idやchat_group_idなど〇〇_idと言うカラムを自動で作成してくれる

〇〇_idと言うカラムを自動で作成してくれるので、:userとするとuser_idも作成してくれる。:chat_group→chat_group_idを自動作成してくれる。

 

・インデックスを自動に張ってくれる

インデックスとは特定のカラムからデータを取得する際に、テーブルの中の特定のカラムのデータを複製し検索しやすくしてくれるもの。インデックスを使用することでデーターの読み込みや取得を高速にしてくれる。デメリットとして書き込みが遅いと言う特徴がある。

参照:https://qiita.com/seiya1121/items/fb074d727c6f40a55f22

 

 

話を戻しますが、t.references :〇〇だけでは外部キーはつけることはできません。

reference型を設定し、外部キー(foregin_key: true)を設定することで外部キーを使用できるようになります。

参照:https://qiita.com/ryouzi/items/2682e7e8a86fd2b1ae47

 

設定が終わったので、マイグレーションファイルを実行して DBに中間テーブルを作成します。

$rails db:migrate

これでモデルとテーブルは作成できました。

次にモデルを設定していきます。

 

 

 

 

 

③モデルの設定

userモデル

class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
 devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable
 has_many :tweets
 has_many :chat_group_to_users
 has_many :chat_groups, through: :chat_group_to_users
end

 

chat_groupモデル

class ChatGroup < ApplicationRecord
 has_many :chat_group_to_users
 has_many :chat_group, through: :chat_group_to_users
end

 

chat_group_userテーブル(中間テーブル)

class ChatGroupToUser < ApplicationRecord
 belongs_to :user
 belongs_to :chat_group
end

 

これで各テーブルの関係性を示せました。

次回はチャットグループのページを作成していきます。

 

 

 

 

 

 

 

以上です。

Ruby on Rails: ルートページの修正、ユーザーページの作成やルーティングの修正...chapter13-1

今回はユーザーページとルートページ(最初に出る画面)の修正及びルーティングのコードをすっきりさせ見やすくなるように実装していきます。

ユーザーページはあくまでもチャットページとブログ(ツイート)ページへのリンクを貼るまでに今は止めておきたいと思います。

------------- 今日やりたいこと -----------------

・ルートページの修正

・ユーザーページの作成

・ルーティングのコードをすっきりさせる

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

そして次の学習ページでチャットページを実装していきます。

 

ルートページ修正後のイメージ図:

 

ユーザーページのイメージ図:

 

ルートページからの遷移イメージ図:

 

 

1.ルートページの修正

現在のビュー:

①画像の保存

最初にアプリのロゴとなる画像を保存する。

適当なフリー画像を拾ってくる(私の場合は作成した。センスは...つっこまないで欲しい...)。

f:id:No_idea:20200621130318p:plain←これをロゴと使用します。

 

画像を拾ってきたら

Finder(macの場合)を開く

自分の作成しているアプリまで移動(私の場合はrensyu1)

app/assets/imagesまで移動

貼り付けて保存

https://gyazo.com/e5c929bbdd579c13b44c18c280a24ce5

 

 

②ロゴをビューに表示する

app/views/tweets/home.html.erbを開く

image_tag

このメソッドを使用すると画像が画面に表示されるようになります。

 

'frige_logo.png'

画像の名前.拡張子(私の使った画像はpng)。

これを記述した場所を第一引数といい、ここに使用したい画像を指定します。

拡張子(ファイルの種類の目印みたいなもの)を忘れずに指定します。

 

alt

これはimage_tagのオプションとして設定しました。

ちなみにaltを設定した場所を第二引数といいます。

altは別に設定しなくても問題なく画像は表示できます。

またalt自体は画像が表示されている場合は直接的に表示されません。

検証でElementsをみると↓のようになっています。

 

✍️  altを使うとできること

画像が表示されなかった場合、altで記述した文字が画面に映し出される(Frige_logo)。

目の不自由な方が読み上げの音声機能を利用した場合に音声としてaltに記述した文字が読まれる。

インターネットでこの画像を探すときにクルーラー(インターネットを巡回して情報を集めているもの)が探しやすいようにしている = 検索でaltを設定した画像が引っかかるようになる。

 

 

拡張子について

参照:https://wa3.i-3-i.info/word1659.html

altについて

参照:https://www.asobou.co.jp/blog/web/alt

$rails s

http://localhost:3000/

 

 

 

 

2.ユーザーページを作成

ここからは前に勉強したことの復習。

ページ表示までに必要なのは。。。

・ルーティング

・コントローラー

・ビュー

+ モデル(DBを使用する場合)

 

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

 

新たに作成しなければいけないのは

users_controller.rb

user_page.html.erb(ユーザーページ用)

設定しなければならないのは

routes.rb

 

 

①コントローラーの作成

$rails g controller users

app/controller/users_controller.rb

def user_page
end

を追加。

 

 

 

 

②ルーティングの設定

get 'users/user_page', to: 'users#user_page'

を設定。

 

 

 

③user_page.html.erb(ユーザーページ)を作成

app/views/users/user_page.html.erbを作成。

https://gyazo.com/c23eaf1dd6642102f0e1092f60e01534

仮ユーザーページを作成。

app/controllers/application_controller.rb

(修正前)
def after_sign_in_path_for(resource)
 tweets_index_path
end
   ↓
(修正後)
def after_sign_in_path_for(resource)
 users_user_page_path
end

https://gyazo.com/b0ef0865fcd3dd402d6c89cb7b0d5951

ログイン後にユーザーページに遷移したいので$rails routesで確認するとprefixはusers_user_pageとなっています。

なので、after_sign_in_path_for(resource)メソッド内をusers_user_page_pathへ変更。

$rails s

http://localhost:3000/

ログインしてみる。

ログインできたので、ユーザーページを作成します。

https://gyazo.com/724ad61fac0a497e59754a66a3da1b87

アイコンとなるユーザー画像をFinder(mac)を開き、app/assets/imagesの中へ保存する。

f:id:No_idea:20200621160808p:plain←私はこの画像をアイコンとして使用します。

 

app/views/users/user_page.html.erb

https://gyazo.com/6455200a0718a0f70bbaa436fe8ea238

image_tag

image_tagを使用し、ロゴとアイコンを表示する。

 

current_user

deviseを使用すると使用できるメソッド。

current_user.nicknameでログインしているユーザーのニックネームを表示。

current_user.idでログインユーザーのidを表示できる。

 

link_to

link_toを使用し、ブログ、チャット、ログアウトにリンクをつける。

ブログへのリンクパスはtweets_index_path。

チャットは作成していないので仮のリンクパス(ユーザーページ)をコード(users_user_page_path)。

ログアウトのパスはdestroy_user_session_pathで大丈夫だが、link_toのデフォルトHTTP動詞は 'get' なのでmethod: :deleteと設定してあげます。

リロードしてみる🔁

表示できるがこれでは完成図とはズレが生じている。

完成図イメージ:

解決しなければならないこと

画像の大きさを調節。

ユーザーネーム、IDをアイコンの高さまで調節。

ユーザーネームのフォントサイズを少し大きくする。

 

④でこれらを調整します。

 

 

④ユーザーページの調整

sassとBEMを使用してビューを調整します。

sassは高級言語と呼ばれ、人間が理解できやすいように設計されたプログラミング言語です。

よって、sassを使うと人間は扱いやすいので今回使用します。

参照:https://webdesign-trends.net/entry/9323

 

BEMはBlock、Element、Modifierの3つの頭文字を取って名付けられたらしいです。

Block__Element--ModifierとこのようにElementと使用したい場合はElement前に__(アンダースコア)を2つ、Modifierを使用したい場合はModifierの前に--(ハイフン)を2つ記述します。

BEMを使用することでコードが見やすくなり、他の人(チームなど)が見たときに理解しやすくなります。

参照:https://tech-dig.jp/bem-css-html/

 

最初にuser_page.html.erbを調整できるようにstylesheetsの中にフォルダを作成し、その中にuser_page.scssを作成します。

app/assets/stylesheets/users

usersフォルダを作成。

usersフォルダ内にuser_page.scssファイルを作成。

変更前:

app/assets/stylesheets/application.css

    ↓

変更後:

このままではuser_page.scssをビューへ反映できないので、css→scssと拡張子を変更。

設定前:

app/assets/stylesheets/application.scss

 

設定後:

 

初期で書かれているコードを全て消して、@import "users/user_page";と記述します。

application.scssここに使いたいファイルを記述すると連結して(他のビューとも共通して)使えるようになります。

 

@import 〇〇;

これを使いたいファイル名の先頭に記述することでそのファイルは共有できるようになる。

そしてファイル名の記述だが、拡張子の.scssは不要。

最後に『 ;セミコロンをつける。

参照:https://diveintocode.jp/blogs/Technology/AssetPipeline

 

これで設定はできなのでビューの調整をしていきます。

 

1.画像の大きさを調整

ユーザーページで検証のElementsを開き、element.styleにコードを書きながらビューを調整し、その後、user_page.scssへ記述します。

 

 

boder-radius

画像の角の丸みを調整。

width

幅の調整。

height

高さの調整。

 

user_page.scssへ記述!と行きたいが、画像の調整は直接imgを調節しないとできないので、user_page.html.erbのアイコン設定しているimage_tagへclass名を記述。

app/views/users/user_page.html.erb

<%= image_tag "user_icon_default.png" %>から<%= image_tag "user_icon_default.png", class: "user-page__info__user-icon--img" %>へ修正。

app/assets/stylesheets/users/user_page.scss

リロード🔁 してビューができているか確認。

https://gyazo.com/191c7b7c4d2add925443d76e3b12f9e1

リロードしてみると、検証のElementsの右側に反映されているコードが表示される。

 → 

表示されたところをよく見ると灰色でapplication....urce.scss:2と書かれています。これをクリックすると、この今見ている場所(今はアイコンのところ)が、どのファイルのscssを使用しているかがわかります。

 

 

2.ユーザーネームの高さとフォントサイズの調整

ユーザーネームの高さとフォントサイズの調整を2.で一緒に記述していきます。

まずはユーザーネームの高さの調整。

〇〇さんのページ▼←ここまでを移動させたいのでclassは"user-page__info__nickname"。

https://gyazo.com/3c8496eadd23d88aea38c64bd59dca8f

位置が決まったらuser_page.scssへコード。

positon: relative;

positonで配置方法を決められます。

relativeで基準点から動かせるようにします。

 

bottom: 60px;

先ほど position: relative; で動けるようになったaaaさんのページを上に持っていきたいのでbottomを使い、基準点から60px分の高さの範囲を確保し文字を上に持ち上げるようにしました。

参照:https://www.aiship.jp/knowhow/archives/18053

 

次にユーザーネームのフォントサイズを調整します。

ユーザーネームだけを調節するためにclassを設定。

class="user-page__info__nickname--user"これに記述していきます。

大きさが決まったので。。。

app/assets/stylesheets/users/user_page.scss

&--user内にfont-sizeを設定。

大きさは20pxとした。

リロード🔁 してビューを確認。

できているので、次でIDの位置も直していきます。

 

 

3.ID:1の位置を調整

IDを調整するためにuser-page__info--idというclassを作ってあるので、これを使い調整します。その前に位置を検証のElementsを使用し決めます。

決まったらuser_page.scssにコード。

position: relative;でID:1を動けるようにして、leftとbottomで調整。

リロード🔁 して。。。

完成!

 

 

 

3.ルーティングのコードをすっきりさせる

現在のルーティング

$rails routes

https://gyazo.com/f528e174a260a72c361e57b1dd1ee708

これに継ぎ足し継ぎ足ししてしまうと見にくくなるので、tweetsの方を一括に設定します。

修正後:

$rails routes

https://gyazo.com/a8f0420974a3e2faaa63ae984c21bef7

これで一括に7つのアクションが設定できた!

しかし、注意しなくてはいけないのが$rails routesして表示されたルーティングをみるとPrefixやURI Pattern、コントローラーのアクション名のところが変わっている。。。

なので、今までリンクを作成した時のパスや、コントローラーのアクション名を修正する必要があります。

今からそのエラーが出る部分を直していきます。

 

最初はログインしてユーザーページにエラーが出ます。

ブログのところのパスを変更。

<%= link_to "ブログ", tweets_index_path %>
        ↓
<%= link_to "ブログ", tweets_path %>

 

次はブログへ行くと、投稿一覧へ遷移されます。

そして投稿したツイートの詳細へ行くと。。。

エラーが発生。

これは詳細を設定するコントローラーアクションがopenとしてあるためです。

これをshowとアクション名を変更。

def open
 @open_tweet = Tweet.find(params[:id])
end
   ↓
def show
 @open_tweet = Tweet.find(params[:id])
end

リロード🔁

これはhtmlが存在しないと言うこと。

htmlを作成する際、open.html.erbと作成。

この名前をshow.html.erbと変更。

open.html.erb → show.html.erb

リロード🔁

次のエラーはパスエラー。

一覧へ戻るのリンクパスがおかしいと言うこと。

これを修正。

_back-index.html.erb

<%= link_to '一覧へ戻る', tweets_index_path %>
         ↓
<%= link_to '一覧へ戻る', tweets_path %>

リロード🔁

あとは問題なさそうだ。

 

 

今回は新しく、users_controller.rbを作成したり、ルーティングのコードを見やすくしました。また、ビューも整えるためにSassやBEMを使ってコードしてみました。

 

 

 

次回はチャットグループを作成したいと思います。

チャットではチャットグループを作成し、ユーザー達をチャットグループへ参加させるので多対多関係になる。よって中間テーブルを必要が必要となります。

応用編としてチャレンジしていきたいと思うので温かい目で見守って欲しいです。

 

 

 

 

 

chapter13-2へ続きます。 

以上です。

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

 

 

 

 

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

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

 

 

 

 

 

 以上です。