refactor: BoardAccessible concernを導入し、ボード関連コントローラを整理、ターン表示ロジックをTurnモデルへ移動し、ボード提案表示をコントローラで処理するよう変更
This commit is contained in:
@@ -1,34 +1,28 @@
|
|||||||
class BoardChannel < ApplicationCable::Channel
|
class BoardChannel < ApplicationCable::Channel
|
||||||
def subscribed
|
def subscribed
|
||||||
board = Board.find_by(id: params[:board_id])
|
board = Board.find_by(id: params[:board_id])
|
||||||
|
|
||||||
unless board
|
unless board
|
||||||
reject
|
reject
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
# 権限チェック
|
|
||||||
# ゲーム参加者を取得(current_userから)
|
|
||||||
current_participant = board.game.participants.find_by(user: current_user)
|
current_participant = board.game.participants.find_by(user: current_user)
|
||||||
|
|
||||||
# 参加権限があるか(メンバー、または終了済み、または公開ボード)
|
# ゲーム参加者でなければ一律拒否
|
||||||
# コントローラの判定ロジックと合わせる
|
unless current_participant
|
||||||
# 共通掲示板は誰でも購読OK(ただしゲーム参加者に限る)
|
reject
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if board.global?
|
# 権限判定:共通掲示板/公開掲示板/メンバー/履歴モードのいずれかで許可
|
||||||
stream_from "board_#{board.id}" if current_participant
|
if board.global? || board.is_public? || board.member?(current_participant) || board.history_mode?
|
||||||
elsif board.is_public?
|
|
||||||
stream_from "board_#{board.id}" if current_participant
|
|
||||||
elsif board.member?(current_participant)
|
|
||||||
stream_from "board_#{board.id}"
|
stream_from "board_#{board.id}"
|
||||||
elsif board.history_mode?
|
|
||||||
stream_from "board_#{board.id}" if current_participant
|
|
||||||
else
|
else
|
||||||
reject
|
reject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unsubscribed
|
def unsubscribed
|
||||||
# Any cleanup needed when channel is unsubscribed
|
# cleanup
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class BoardMembershipsController < ApplicationController
|
class BoardMembershipsController < ApplicationController
|
||||||
|
include BoardAccessible
|
||||||
|
|
||||||
before_action :require_login
|
before_action :require_login
|
||||||
before_action :set_game
|
before_action :set_game
|
||||||
before_action :set_board
|
before_action :set_board
|
||||||
@@ -25,11 +27,6 @@ class BoardMembershipsController < ApplicationController
|
|||||||
@board.board_memberships.create!(participant_id: target_participant_id, joined_at: Time.current)
|
@board.board_memberships.create!(participant_id: target_participant_id, joined_at: Time.current)
|
||||||
end
|
end
|
||||||
|
|
||||||
# メンバー構成が変わったので、他の掲示板と重複していないかチェックが必要だが、
|
|
||||||
# モデルのバリデーションは「作成時」を想定しているため、ここでは簡易チェックに留めるか、
|
|
||||||
# あるいはバリデーションエラーをハンドリングする。
|
|
||||||
# ここではsave成功/失敗で判断
|
|
||||||
|
|
||||||
redirect_to game_board_path(@game, @board), notice: "メンバーを追加しました"
|
redirect_to game_board_path(@game, @board), notice: "メンバーを追加しました"
|
||||||
rescue ActiveRecord::RecordInvalid => e
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
redirect_to game_board_path(@game, @board), alert: "メンバー追加に失敗しました: #{e.message}"
|
redirect_to game_board_path(@game, @board), alert: "メンバー追加に失敗しました: #{e.message}"
|
||||||
@@ -49,18 +46,4 @@ class BoardMembershipsController < ApplicationController
|
|||||||
redirect_to game_board_path(@game, @board), alert: "退出に失敗しました"
|
redirect_to game_board_path(@game, @board), alert: "退出に失敗しました"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_game
|
|
||||||
@game = Game.find(params[:game_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_board
|
|
||||||
@board = @game.boards.find(params[:board_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_current_participant
|
|
||||||
@current_participant = @game.participants.find_by(user: current_user)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class BoardPostsController < ApplicationController
|
class BoardPostsController < ApplicationController
|
||||||
|
include BoardAccessible
|
||||||
|
|
||||||
before_action :require_login
|
before_action :require_login
|
||||||
before_action :set_game
|
before_action :set_game
|
||||||
before_action :set_board
|
before_action :set_board
|
||||||
@@ -13,11 +15,9 @@ class BoardPostsController < ApplicationController
|
|||||||
@post = @board.board_posts.new(post_params)
|
@post = @board.board_posts.new(post_params)
|
||||||
@post.participant = @current_participant
|
@post.participant = @current_participant
|
||||||
|
|
||||||
# フェーズ情報の付与
|
# フェーズ情報の付与(latest_turnアソシエーションを使用)
|
||||||
# 最新のターン情報を取得してセットする
|
if @game.latest_turn
|
||||||
latest_turn = @game.turns.order(number: :desc).first
|
@post.phase = @game.latest_turn.phase
|
||||||
if latest_turn
|
|
||||||
@post.phase = latest_turn.phase
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if @post.save
|
if @post.save
|
||||||
@@ -29,18 +29,6 @@ class BoardPostsController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_game
|
|
||||||
@game = Game.find(params[:game_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_board
|
|
||||||
@board = @game.boards.find(params[:board_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_current_participant
|
|
||||||
@current_participant = @game.participants.find_by(user: current_user)
|
|
||||||
end
|
|
||||||
|
|
||||||
def post_params
|
def post_params
|
||||||
params.require(:board_post).permit(:body)
|
params.require(:board_post).permit(:body)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class BoardProposalsController < ApplicationController
|
class BoardProposalsController < ApplicationController
|
||||||
|
include BoardAccessible
|
||||||
|
|
||||||
before_action :require_login
|
before_action :require_login
|
||||||
before_action :set_game
|
before_action :set_game
|
||||||
before_action :set_board
|
before_action :set_board
|
||||||
@@ -13,13 +15,9 @@ class BoardProposalsController < ApplicationController
|
|||||||
@proposal.proposer = @current_participant
|
@proposal.proposer = @current_participant
|
||||||
@proposal.status = "pending"
|
@proposal.status = "pending"
|
||||||
|
|
||||||
# フェーズ情報の保存
|
# フェーズ情報の保存(latest_turnアソシエーションを使用)
|
||||||
latest_turn = @game.turns.max_by(&:number)
|
latest_turn = @game.latest_turn
|
||||||
if latest_turn
|
@proposal.phase = latest_turn&.phase || "S1901M"
|
||||||
@proposal.phase = latest_turn.phase
|
|
||||||
else
|
|
||||||
@proposal.phase = "S1901M" # 初期値
|
|
||||||
end
|
|
||||||
|
|
||||||
if @proposal.save
|
if @proposal.save
|
||||||
redirect_to game_board_path(@game, @board), notice: "提案を作成しました"
|
redirect_to game_board_path(@game, @board), notice: "提案を作成しました"
|
||||||
@@ -31,12 +29,6 @@ class BoardProposalsController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
@proposal = @board.board_proposals.find(params[:id])
|
@proposal = @board.board_proposals.find(params[:id])
|
||||||
|
|
||||||
# 承認・拒否権限:
|
|
||||||
# 提案者本人以外が承認/拒否できるべきか、あるいは全員できるべきか?
|
|
||||||
# 通常は「相手」が承認するものだが、多国間の場合は?
|
|
||||||
# ここでは「メンバーであれば誰でもステータス変更可能」とする(簡易実装)
|
|
||||||
# ただし、提案者本人が自分で承認するのは変なので、他者のみとするのがベター
|
|
||||||
|
|
||||||
unless @board.member?(@current_participant)
|
unless @board.member?(@current_participant)
|
||||||
return redirect_to game_board_path(@game, @board), alert: "権限がありません"
|
return redirect_to game_board_path(@game, @board), alert: "権限がありません"
|
||||||
end
|
end
|
||||||
@@ -44,7 +36,6 @@ class BoardProposalsController < ApplicationController
|
|||||||
new_status = params[:board_proposal][:status]
|
new_status = params[:board_proposal][:status]
|
||||||
if %w[accepted rejected].include?(new_status)
|
if %w[accepted rejected].include?(new_status)
|
||||||
@proposal.update!(status: new_status)
|
@proposal.update!(status: new_status)
|
||||||
# ログにも残す(投稿として自動投稿しても良いが、今回はステータス変更のみ)
|
|
||||||
redirect_to game_board_path(@game, @board), notice: "提案を#{new_status == 'accepted' ? '承認' : '拒否'}しました"
|
redirect_to game_board_path(@game, @board), notice: "提案を#{new_status == 'accepted' ? '承認' : '拒否'}しました"
|
||||||
else
|
else
|
||||||
redirect_to game_board_path(@game, @board), alert: "不正なステータスです"
|
redirect_to game_board_path(@game, @board), alert: "不正なステータスです"
|
||||||
@@ -53,18 +44,6 @@ class BoardProposalsController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_game
|
|
||||||
@game = Game.find(params[:game_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_board
|
|
||||||
@board = @game.boards.find(params[:board_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_current_participant
|
|
||||||
@current_participant = @game.participants.find_by(user: current_user)
|
|
||||||
end
|
|
||||||
|
|
||||||
def proposal_params
|
def proposal_params
|
||||||
params.require(:board_proposal).permit(:body)
|
params.require(:board_proposal).permit(:body)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class BoardsController < ApplicationController
|
class BoardsController < ApplicationController
|
||||||
|
include BoardAccessible
|
||||||
|
|
||||||
before_action :require_login
|
before_action :require_login
|
||||||
before_action :set_game
|
before_action :set_game
|
||||||
before_action :set_board, only: [ :show, :toggle_public ]
|
before_action :set_board, only: [ :show, :toggle_public ]
|
||||||
@@ -14,21 +16,19 @@ class BoardsController < ApplicationController
|
|||||||
|
|
||||||
if @game.status == "finished"
|
if @game.status == "finished"
|
||||||
# 履歴モード:かつて参加していた掲示板をすべて表示
|
# 履歴モード:かつて参加していた掲示板をすべて表示
|
||||||
# (共通掲示板は全員参加扱いなので含む)
|
@boards = @game.boards.includes(:participants, :board_posts, :board_memberships)
|
||||||
@boards = @game.boards.select { |b| b.member?(@current_participant) || b.global? }
|
.select { |b| b.member?(@current_participant) || b.global? }
|
||||||
.sort_by { |b| [ b.global? ? 0 : 1, b.created_at ] }
|
.sort_by { |b| [ b.global? ? 0 : 1, b.created_at ] }
|
||||||
else
|
else
|
||||||
return redirect_to game_path(@game), alert: "参加者ではないためアクセスできません" unless @current_participant
|
return redirect_to game_path(@game), alert: "参加者ではないためアクセスできません" unless @current_participant
|
||||||
|
|
||||||
# 進行中:参加中の掲示板のみ
|
# 進行中:参加中の掲示板のみ(eager load で N+1 防止)
|
||||||
@boards = @current_participant.boards.includes(:participants, :board_posts).order(created_at: :desc)
|
@boards = @current_participant.boards.includes(:participants, :board_posts, :board_memberships).order(created_at: :desc)
|
||||||
# 共通掲示板がまだ紐付いていない場合のフォールバック(通常は作成時に紐づくはずだが念の為)
|
# 共通掲示板のフォールバック
|
||||||
global_board = @game.boards.global.first
|
global_board = @game.boards.global.first
|
||||||
if global_board && !@boards.include?(global_board)
|
if global_board && !@boards.include?(global_board)
|
||||||
# 表示上追加するが、DBには保存しない(閲覧時に参加処理をする作りも考えられるが、createタイミングで保証する前提)
|
|
||||||
@boards = [ global_board ] + @boards
|
@boards = [ global_board ] + @boards
|
||||||
end
|
end
|
||||||
# 先頭に共通掲示板を持ってくる
|
|
||||||
@boards = @boards.sort_by { |b| b.global? ? 0 : 1 }
|
@boards = @boards.sort_by { |b| b.global? ? 0 : 1 }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -36,7 +36,6 @@ class BoardsController < ApplicationController
|
|||||||
def show
|
def show
|
||||||
@current_participant = @game.participants.find_by(user: current_user)
|
@current_participant = @game.participants.find_by(user: current_user)
|
||||||
|
|
||||||
# アクセス制御
|
|
||||||
# アクセス制御
|
# アクセス制御
|
||||||
access_allowed = false
|
access_allowed = false
|
||||||
|
|
||||||
@@ -72,11 +71,12 @@ class BoardsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
@posts = @board.board_posts.includes(:participant).order(created_at: :desc)
|
@posts = @board.board_posts.includes(:participant).order(created_at: :desc)
|
||||||
|
@proposals = @board.board_proposals.includes(:proposer).order(created_at: :desc)
|
||||||
@new_post = BoardPost.new
|
@new_post = BoardPost.new
|
||||||
@new_proposal = BoardProposal.new
|
@new_proposal = BoardProposal.new
|
||||||
@active_members = @board.active_memberships.includes(:participant).map(&:participant)
|
@active_members = @board.active_memberships.includes(:participant).map(&:participant)
|
||||||
|
|
||||||
# メンバー追加用:招待可能なプレイヤー一覧(自分と既に参加している人を除く)
|
# メンバー追加用:招待可能なプレイヤー一覧
|
||||||
if @board.negotiation? && !@board.history_mode?
|
if @board.negotiation? && !@board.history_mode?
|
||||||
existing_member_ids = @board.board_memberships.where(left_at: nil).pluck(:participant_id)
|
existing_member_ids = @board.board_memberships.where(left_at: nil).pluck(:participant_id)
|
||||||
@candidates = @game.participants.where.not(id: existing_member_ids).where.not(power: nil)
|
@candidates = @game.participants.where.not(id: existing_member_ids).where.not(power: nil)
|
||||||
@@ -135,35 +135,17 @@ class BoardsController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_game
|
|
||||||
@game = Game.find(params[:game_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_board
|
|
||||||
@board = @game.boards.find(params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def board_params
|
def board_params
|
||||||
# パラメータは特にないが、将来的にタイトルなど追加するかも
|
|
||||||
params.fetch(:board, {}).permit(:is_public)
|
params.fetch(:board, {}).permit(:is_public)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_diplomacy_matrix
|
def build_diplomacy_matrix
|
||||||
# 外交関係マップ構築
|
|
||||||
# Matrix: { "FRANCE" => { "GERMANY" => true, "ENGLAND" => false }, ... }
|
|
||||||
# 全組み合わせの初期化
|
|
||||||
powers = @game.participants.where.not(power: nil).pluck(:power)
|
powers = @game.participants.where.not(power: nil).pluck(:power)
|
||||||
matrix = {}
|
matrix = {}
|
||||||
powers.each { |p| matrix[p] = [] }
|
powers.each { |p| matrix[p] = [] }
|
||||||
|
|
||||||
# 参加中の全掲示板を走査(自分が参加していないものも含めたいが、
|
# 自分が参加している掲示板・公開された掲示板の関係を表示
|
||||||
# DB設計上 board_memberships を見る必要がある)
|
visible_boards = @game.boards.negotiation.includes(:participants, :board_memberships)
|
||||||
# is_publicなもの、または自分が参加しているものについて情報を開示?
|
|
||||||
# 仕様書には「どの国とどの国が掲示板を持っているか」とあるが、
|
|
||||||
# 秘密交渉なので、本来は「自分が見えている範囲」あるいは「公開宣言されたもの」のみ?
|
|
||||||
# ここでは「自分が参加している掲示板」および「公開された掲示板」の関係を表示する。
|
|
||||||
|
|
||||||
visible_boards = @game.boards.negotiation.includes(:participants)
|
|
||||||
|
|
||||||
visible_boards.each do |board|
|
visible_boards.each do |board|
|
||||||
# アクセス権チェック(簡易)
|
# アクセス権チェック(簡易)
|
||||||
|
|||||||
21
app/controllers/concerns/board_accessible.rb
Normal file
21
app/controllers/concerns/board_accessible.rb
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# 掲示板関連コントローラの共通ロジック
|
||||||
|
# set_game, set_board, set_current_participant を提供する
|
||||||
|
module BoardAccessible
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_game
|
||||||
|
@game = Game.find(params[:game_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_board
|
||||||
|
@board = @game.boards.find(params[:board_id] || params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_current_participant
|
||||||
|
@current_participant = @game.participants.find_by(user: current_user)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,6 +1,19 @@
|
|||||||
class Turn < ApplicationRecord
|
class Turn < ApplicationRecord
|
||||||
belongs_to :game
|
belongs_to :game
|
||||||
|
|
||||||
|
SEASON_MAP = { "S" => "春", "F" => "秋", "W" => "冬" }.freeze
|
||||||
|
PHASE_TYPE_MAP = { "M" => "移動", "R" => "撤退", "A" => "調整" }.freeze
|
||||||
|
|
||||||
|
# フェーズコードを日本語表示に変換(例: "S1901M" → "1901年 春 (移動)")
|
||||||
|
def display_phase
|
||||||
|
return nil unless phase.present? && phase.length >= 6
|
||||||
|
|
||||||
|
year = phase[1..4]
|
||||||
|
season = SEASON_MAP[phase[0]] || ""
|
||||||
|
type = PHASE_TYPE_MAP[phase[-1]] || ""
|
||||||
|
"#{year}年 #{season} (#{type})"
|
||||||
|
end
|
||||||
|
|
||||||
# 特定の国の実行可能な命令を取得
|
# 特定の国の実行可能な命令を取得
|
||||||
# 例: turn.possible_orders_for("FRANCE")
|
# 例: turn.possible_orders_for("FRANCE")
|
||||||
def possible_orders_for(power_name)
|
def possible_orders_for(power_name)
|
||||||
|
|||||||
@@ -65,7 +65,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-1 overflow-hidden">
|
<div class="flex flex-1 overflow-hidden">
|
||||||
<!-- 左: チャットエリア -->
|
|
||||||
<!-- 左: チャットエリア -->
|
<!-- 左: チャットエリア -->
|
||||||
<div class="flex-1 flex flex-col bg-white border border-gray-200 rounded-lg shadow-sm mr-4 overflow-hidden">
|
<div class="flex-1 flex flex-col bg-white border border-gray-200 rounded-lg shadow-sm mr-4 overflow-hidden">
|
||||||
|
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
条約・提案
|
条約・提案
|
||||||
</div>
|
</div>
|
||||||
<div class="p-3 space-y-3">
|
<div class="p-3 space-y-3">
|
||||||
<% @board.board_proposals.order(created_at: :desc).each do |proposal| %>
|
<% @proposals.each do |proposal| %>
|
||||||
<div class="border rounded p-2 text-sm <%= proposal.status == 'accepted' ? 'bg-green-50 border-green-200' : (proposal.status == 'rejected' ? 'bg-red-50 border-red-200' : 'bg-white border-gray-200') %>">
|
<div class="border rounded p-2 text-sm <%= proposal.status == 'accepted' ? 'bg-green-50 border-green-200' : (proposal.status == 'rejected' ? 'bg-red-50 border-red-200' : 'bg-white border-gray-200') %>">
|
||||||
<div class="flex justify-between items-start mb-1">
|
<div class="flex justify-between items-start mb-1">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -81,42 +81,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% # ゲーム画面(games/show)と統一されたデザインでターン情報を表示 %>
|
<% # ゲーム画面(games/show)と統一されたデザインでターン情報を表示 %>
|
||||||
<%
|
<% target_turn = defined?(display_turn) && display_turn ? display_turn : game.latest_turn %>
|
||||||
target_turn = defined?(display_turn) && display_turn ? display_turn : game.latest_turn
|
|
||||||
%>
|
|
||||||
<% if target_turn && target_turn.phase.present? %>
|
<% if target_turn && target_turn.phase.present? %>
|
||||||
<%
|
|
||||||
# フェーズ名パース (例: S1901M)
|
|
||||||
phase = target_turn.phase
|
|
||||||
year = phase[1..4]
|
|
||||||
season_code = phase[0]
|
|
||||||
type_code = phase[-1]
|
|
||||||
|
|
||||||
season = case season_code
|
|
||||||
when 'S' then '春'
|
|
||||||
when 'F' then '秋'
|
|
||||||
when 'W' then '冬'
|
|
||||||
else ''
|
|
||||||
end
|
|
||||||
|
|
||||||
type = case type_code
|
|
||||||
when 'M' then '移動'
|
|
||||||
when 'R' then '撤退'
|
|
||||||
when 'A' then '調整'
|
|
||||||
else ''
|
|
||||||
end
|
|
||||||
|
|
||||||
display_date = "#{year}年 #{season} (#{type})"
|
|
||||||
%>
|
|
||||||
|
|
||||||
<div class="bg-white shadow overflow-hidden sm:rounded-lg border border-gray-200 mb-6">
|
<div class="bg-white shadow overflow-hidden sm:rounded-lg border border-gray-200 mb-6">
|
||||||
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center bg-gray-50">
|
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center bg-gray-50">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-2xl font-bold text-gray-900"><%= display_date %></h2>
|
<h2 class="text-2xl font-bold text-gray-900"><%= target_turn.display_phase %></h2>
|
||||||
<div class="mt-1 flex items-center space-x-4 text-sm text-gray-600">
|
<div class="mt-1 flex items-center space-x-4 text-sm text-gray-600">
|
||||||
<span>ターン: <%= target_turn.number %></span>
|
<span>ターン: <%= target_turn.number %></span>
|
||||||
<span class="text-gray-400">|</span>
|
<span class="text-gray-400">|</span>
|
||||||
<span>フェーズ: <%= phase %></span>
|
<span>フェーズ: <%= target_turn.phase %></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -131,3 +105,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user