#概要
- オリジナルアプリ作成にあたり、ユーザ(current_user)が他ユーザに対してパートナー申請をする画面をトップページ(toppages#index)に実装したい。
- 申請手順は以下の通りとなる。
- 自分(ユーザA)がパートナー(ユーザB)に対して招待を送る。その際にユーザAは「秘密の言葉」を設定しておく。
- パートナーのトップページに「招待が届きました」というメッセージが届き、それを「承認」か「拒否」かを選択する。承認する場合にはユーザAが設定した「秘密の言葉」を入力する必要がある。
- 承認された場合はユーザAとユーザBはパートナーとなる。
- ユーザと他ユーザがパートナーである事は中間テーブルrelationshipsに定義する。
#手順
パートナー申請フォーム作成
中間テーブルrelationshipsにて多対多の関係(ユーザと他ユーザがパートナーである状態)を表す。
- 中間テーブルrelationshipsのカラム構成
id | user_id | partner_id | status | secret_words |
---|---|---|---|---|
form_withを用い、relationshipsテーブルにデータが登録されるようにする。
relationshipsのパーシャルでパートナー申請フォームを作成する。
<div class="row">
<div class="col-sm-6 offset-sm-3">
<%= form_with(model: relationship, local: true) do |f| %>
<div class="form-group">
# relationshipテーブルに無いデータの入力の為、"f.~"ではなく"~_tag"を用いる
# 初期値をテキストボックスに表示しておきたい場合、""内に値を入れる(今回は不要の為、ブランク)
<%= label_tag :name, "パートナー申請先(ユーザ名)" %>
<%= text_field_tag :name, "", class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :secret_words, "秘密の言葉" %>
<%= f.text_field :secret_words, class: "form-control" %>
</div>
<%= hidden_field_tag :status, "承認待ち" %>
<%= f.submit "招待する", class: "btn btn-primary btn-block" %>
<% end %>
</div>
</div>
パートナー申請画面作成
relationshipsのパーシャルで作成した申請フォームをrenderで読み込む。
<div class="text-center">
<h1>パートナー申請画面</h1>
</div>
# classを跨ぐ場合はインスタンス変数を用いるとclass間で依存関係が出来てしまうので、使用しないほうが良い
<%= render "relationships/offer_form", relationship: @relationship %>
toppages controllerの実装
relationshipsのパーシャルで申請フォームを作成した為、インスタンス変数もRelationshipsControllerで定義するものだと勘違いしやすいが、それは誤りである。仮に別クラスのパーシャルであったとしてもviewに表示されているインスタンス変数はそのアクションを定義しているcontrollerに紐づいている為、今回の場合はインスタンス変数(@relationship)はtoppages#indexで定義する。
class ToppagesController < ApplicationController
def index
if logged_in?
# インスタンス変数を@relationshipとし、form_withのmodel引数に設定してあげることで
# action先をRelationshipsController#createに暗に飛ばすことが出来る
@relationship = current_user.relationships.build
end
end
end
(補足情報)
current_userとlogged_in?のメソッドはSessionsHelperにて定義している。
module SessionsHelper
def current_user
@current_user ||= User.find_by(id: session[:user_id])
end
def logged_in?
!!current_user
end
end
helperはviewでのみしか機能しないので、controllerで使用したい場合はmix-inをする。
今回、ToppagesControllerで使用したいが、他でも使用する可能性が高い為、全体に適用すべくApplicationControllerにmix-inしておく。
class ApplicationController < ActionController::Base
# SessionsHelperをmix-in
include SessionsHelper
private
def require_user_logged_in
unless logged_in?
redirect_to login_url
end
end
end