LoginSignup
0
0

More than 3 years have passed since last update.

帳票をRailsで作る過程の試行錯誤

Last updated at Posted at 2019-06-24

はじめに

ユーザー ⇄ SIer ⇄ 開発者(←私) といった立ち位置で、お客さんが業務で使ってるエクセルの情報なんかをうまいことアプリケーションにしましょうというよくありそうなプロジェクト。

環境
ruby '2.5.3'
rails '5.2.2'

なにをしたかったのか

こういう帳票をWebアプリケーションで扱えるようにモデルを開発

スクリーンショット 2019-06-24 1.56.32.png

・チームは大会に紐づいている
・チームに対して、戦士/魔法使い/盗賊のメンバーを追加でき、横一列で確認できる
・ユーザーはこの形式で慣れ親しんでおり、ここから大きく変更することができない
・チームのメンバーを戦士/魔法使い/盗賊で複数人追加することもできる、その場合、一行目は空白で二行目にだけ入力があるといったケースも存在する。
・一行目は空白で二行目にだけ入力があるといったケースのとき、表示は入力された通りにしたい。

設計その1

イメージ
スクリーンショット 2019-06-24 14.08.11.png

ざっくりとしたテーブル定義
スクリーンショット 2019-06-24 14.31.48.png

モデル定義

class Tournament < ApplicationRecord
  has_many :teams, -> { order('team.order') }
  has_many :rows, through: :team
  has_many :warriors, through: :row
  has_many :wizards, through: :row
  has_many :thiefs, through: :row

  accepts_nested_attributes_for :teams
  accepts_nested_attributes_for :warriors
  accepts_nested_attributes_for :wizards
  accepts_nested_attributes_for :thiefs
end
class Team < ApplicationRecord
  belongs_to :tournament
  has_many :rows, dependent: :destroy
end
class Row < ApplicationRecord
  belongs_to :team
  has_one :warrior, dependent: :destroy
  has_one :wizard, dependent: :destroy
  has_one :thief, dependent: :destroy
end
#wizard, fhief も同様
class warrior < ApplicationRecord
  belongs_to :row
end

このモデル定義で以下のように検索がかけられる

tournament.warriors.max(:hit_point) #=> 大会に参加してる戦士の中でのmaxのHP
tournament.warriors.sum(:hit_point) #=> 大会に参加してる戦士の合計のHP

View側はfields_forでnestする

= form_with model: @tournament, url: tournament_path(@tournament), html: { role: "form"} do |f|
  = f.fields_for :teams do |team|
    # team のインプット
  = f.fields_for :warriors do |warrior|
    # warrior のインプット
  = f.fields_for :wizards do |wizard|
    # wizard のインプット
  = f.fields_for :thiefs do |thief|
    # thief のインプット

Controller側では、モデルのaccepts_nested_attributes_forを利用してtournamentのupdate_attributesに引っ掛けて、関連するteam, warriors, wizards, fhiefsすべての値が更新される

def update
  @tournament.update_attributes(params)
end

メリット
・viewとcontrollerがめちゃくちゃスッキリしている
・rowとwarrior, wizard, thiefを has_oneでリレーションしているので1行に複数データを追加できない
・大会のモデルから参加チームすべてのwarrior, wizard, thiefを横串で確認できる

設計その2

設計その1を提案したところ、以下のフィードバックを受けたので設計を修正した
・テーブルの一覧性が悪い
・戦士、魔法使い、盗賊はそれぞれに似ている項目があるので、ひとつのテーブルにまとめる

スクリーンショット 2019-06-24 14.54.35.png

テーブル定義
スクリーンショット 2019-06-24 14.57.31.png

魔法使いの専用カラムや盗賊用の専用カラムができてしまうが、単一テーブル継承で設計し直した

設計その3

設計その2を提案したところ、以下のフィードバッグを受けた
・INSERT文を書くときに、typeによって、どこのカラムを利用するのかを変えないといけなくて面倒なので、HP、攻撃力、防御力、MP、盗み成功率を、単位1,値1 ~ 単位4, 値4まで持たせて自由にかけるようにして欲しい(INSERT文...書く気なのか...)

スクリーンショット 2019-06-24 15.06.01.png

しかも、
魔法使いはkey_1にHP、key_2にMP、key_3に攻撃力、key_4に防御力
と固定化できず、
MPが入力されてない場合は、key_1にHP、key_2に攻撃力、key_3に防御力
その状態で保存し、さらにMPを追加した場合は、key_1にHP、key_2に攻撃力、key_3に防御力、key_4にMPが爆誕するという...

まだ試行錯誤中だが、DBの値からハッシュ構造を作り、対応させようかと考え中

member.point
=> {
  member.key_1: member.val_1,
  member.key_2: member.val_2,
  member.key_3: member.val_3,
  member.key_4: member.val_4
}
const HP = 1
member.point[HP]
member.attribute_for_update
=> {
 member.key_1: val_1.to_sym,
 member.key_2: val_2.to_sym,
 member.key_3: val_3.to_sym,
 member.key_4: val_4.to_sym
}
member.update_attributes = { member.attribute_for_update[HP] => 200 }

最終的にどんな実装になるやら。。。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0