目的
タイトルが不自然に凝ってますが、chatGPTと話してるついでに考えてもらいました。
今回はコミュニティ機能を実装します。
ユーザーが複数のコミュニティに参加できるようにモデルを作成したいと思います。
自分の知っている範囲で考えても答えが出てこなかったので、chatGPTに相談したら中間テーブルなるものを知りました。よく分かっていないのでその理解も含め、頑張ります!
今回やること
今回の目標は以下の2つ。
- ユーザーが複数のコミュニティに参加できるようにモデルを作成
- ログイン機能を実装
環境
- windows 10
- ruby 3.0.4
- rails 6
- Bootstrap 5.0.2
いざ出陣
deviseの導入
まず最終的にやりたいこととしては、以下の要件を満たすモデルを作ることです。
- ユーザーは、複数のコミュニティに参加することができる。
- コミュニティには、複数のユーザーが参加することができる。
これらの関係を表すために、中間テーブルを作成する必要があると言われたので、最終的なモデルは3つです。
- Userモデル
- Communityモデル
- Membershipモデル
できることからやろう。
まずは、ログイン機能のを実装するためのgemとして device
を導入します。
# 追加
gem 'devise'
bundle install
rails generate devise:install # 初期設定
rails generate devise:install
を実行すると、 config/initializers/devise.rb
と config/locales/devise.en.yml
が作成され、対応すべきこと?が4つ出てきました。
-
default_url_options
の設定 -
root_url
の設定 - flashメッセージの設定
-
Devise
のビューをカスタマイズする
1は無視。
2はすでにやっている。
3と4はやります。
3. flashメッセージの設定
app > views > layouts > application.html.erbに以下のコードを追加して、flashメッセージを出せるようにします。chatGPTにapplication.html.erbのどこに追加すれば聞いたら、警告とは違うコードを追加してましたが、こっちのがかっこ良いしできそうなのでこれでいきます。
<body>
<%= yield %>
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, class: "alert #{name}" %>
<% end %>
</body>
設定ができたかを確認するために、app > controllers > users_controller.rbでflashメッセージを書いてみます。
class UsersController < ApplicationController
def index
flash[:notice] = "テストメッセージ"
end
end
4. Devise
のビューをカスタマイズする
コマンドプロンプトで以下を実行します。
rails g devise:views
これで、Deviseによって自動生成されたビューをカスタマイズするためのテンプレートファイルが作成されました。後で確認します。
Userモデルの作成
ログイン機能のあるUserモデルを作成するために以下を実行します。
rails generate controller users
rails generate devise User
rails db:migrate
すると、config > routes.rbに、以下のように追加されています。
これによってユーザー認証に関わるルーティングが作成されます。
Rails.application.routes.draw do
devise_for :users # これが追加される
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
resources :users
root 'users#index'
end
このまま動作確認をすると、 http://localhost:3000/users/sign_in
で画面は表示されますが、ログインしていなくても http://localhost:3000/users
が開けます。
ログインしていなければ、 http://localhost:3000/users/sign_in
に飛ぶようにしたいので、app > controllers > users_controller.rbに以下を追加します。
class UsersController < ApplicationController
before_action :authenticate_user! # これを追加
def index
flash[:notice] = "テストメッセージ"
end
end
画面がかわいくないのは、さっき用意したテンプレートファイルを編集して後でカスタマイズします。
Userテーブルにカラムを追加
migrationの使い方に苦しんだ...
とりあえず分かったことを箇条書きにする。
- migrationファイルを
rails db:migrate
したりrails db:rollback
したりしてモデルを変更する。 - カラムを追加するときのmigrationファイルは、
rails g migration AddDetailsToUsers
で作成する。
具体的には、以下のように作業しました。
migrationファイルの作成
rails g migration AddDetailsToUsers
カラムの追加
class AddDetailsToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :username, :string, null: false
add_column :users, :gender, :string
add_column :users, :origin_prefecture, :string, null: false
add_column :users, :residence_prefecture, :string, null: false
add_column :users, :residence_city, :string, null: false
end
end
Viewから飛んできた情報を受け取れるようにする。
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :gender, :origin_prefecture, :residence_prefecture, :residence_city])
end
end
あとはhtmlの編集で、設定したカラムを画面から登録できるようにします!
以下のコードを、追加したカラム分追記します。
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true, autocomplete: "username" %>
</div>
Communityモデルの作成
以下を実行。
rails g model Community eventname:string
eventnameのnullを却下してmigrate
# 変更前
t.string :eventname
# 変更後
t.string :eventname, null: false
rails db:migrate
他にもカラム必要だけど、いったん後で。
Membershipモデルの作成
ユーザーとコミュニティの多対多の関係を表す中間テーブルを作成するために、Membershipモデルを作成します。
rails g model Membership user:references community:references
UserモデルとCommunityモデルに、アソシエーションを定義します。
アソシエーションとは、Railsにおいてモデル間の関係を定義する仕組みのことです。
class User < ApplicationRecord
has_many :memberships # これを追加
has_many :users, through: :memberships # これを追加
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
end
class Community < ApplicationRecord
has_many :memberships # これを追加
has_many :users, through: :memberships # これを追加
end
そしてマイグレーション。
rails db:migrate
アソシエーションのメゾットには、以下のようなものがあります。
まぁ、読めはしますよね。書けはしないけど。
メソッド名 | 説明 |
---|---|
belongs_to | 他のモデルに属することを示す。 |
has_one | 他のモデルと1対1の関係を示す。 |
has_many | 他のモデルと1対多の関係を示す。 |
has_many through | 間に中間モデルを挟んで他のモデルと多対多の関係を示す。 |
余談
右上の検索ボタンのホバーしたときの文字色、ヘッダーの色と合わせよ。