前回のアウトプットから、だいぶ間が空いたが、今回から暫く、基本情報技術者試験問題に向き合う。
コンサートチケットの予約販売サイト、特にチケット販売サブシステムを用いる問題だった。
特に、今回のスクールの大成すべく、問3は実際にDBのみならず、Appも作成したい。
出典: 平成30年度 秋期 基本情報技術者試験(FE)試験区分 午後 問1 問3
#DB仕様、ER図
Cacooを用いてみた。カラム名が冗長な気がする。
#販売サブシステムの(引用、一部編集)
- コンサートの席種はS,A,Bがあり、コンサート毎にその価格と発売席数は異なる。
- 取り扱うコンサートの席種(S,A,B)毎の販売可能な席数を管理する。
- 会員が購入申込すると、一意な販売IDを生成して販売表にレコード追加
- 会員が支払いをすると、決済処理として決済表に追加。
- 決済期限の翌日に、決済期限を過ぎた販売表中のレコードと販売IDが同じレコードが決済表にない場合、購入申込は取り消され、バッチ処理として、決済表に当該販売IDを主キーとして決済表に決済日をnull、決済額を-1としてレコード追加
- バッチ処理は毎夜0~4時の販売サイトのシステムメンテナンス時に行う
- 購入申込席数が販売可能な席数を上回る場合は、販売終了と表示し、購入申込を受け付けない
等々。。。
※注意事項
コンサート席種のカラムが、商品詳細表と販売表に1つずつあり、重複していて気持ち悪いが、
試験問題がそうなっており、敢えてそうしてる模様なので、そのままにする。
その意図を反映するため、席種の商品詳細表側はinteger、販売表側はstringにしておく。
#使用環境
- ホストOS: Windows10 Home
- 仮想環境OS: Ubuntu Bento/Bionic
- Ruby:2.51
- Rails: 5.2.2
- 暫定追加gem : devise
- DB: PostgreSQL
##rails gコマ
今回もdeviseを利用することを、頭に入れておきたい。
rails new concert_ticket -d postgesql
# miniracerをアンコメント
gem 'miniracer'
# authentication
gem 'devise'
bundle
username: admin
password: 〇×△
host: localhost
rails db:create
# deviseのインストール
rails g devise:install
# Userモデルにdeviseを追加。モデルなので、単数形
rails g devise User name:string email:string point:integer
# 商品表と商品詳細表テーブルはscaffoldを用いる
rails g scaffold Concert concert_info:text concert_date:datetime
rails g scaffold ConcertDetail concert:references seat_grade:integer seat_price:integer tickets_total:integer
# Saleモデルの追加
# カラムが多い。販売表モデル 商品表外部キー 会員表外部キー 席種 席数 販売日 販売額 決済期限日 使用ポイント
rails g model Sale concert:references user:references seat_grade:string seats_total:integer sale_date:datetime sales_total:integer payment_deadline:datetime used_point:integer
# 決済表モデルを追加
rails g model Payment sale:references payment_date:datetime payment_total:integer added_point:integer
##関連付け
has_many :concert_detail
has_many :sale
belongs_to :concert
has_many :sale
has_one :payment
belongs_to :concert
belongs_to :user
belongs_to :sale
##userテーブルにadminカラム追加
単に入れ忘れた。
rails g migration AddAdminToUser admin:boolean
class AddAdminToUser < ActiveRecord::Migration[5.2]
def change
add_column :students, :admin, :boolean,default: false
end
end
##validation追加
後からさらに追加していくと思うが、次のデータ入力の為に。
なお、ファイル中のvalidation前後のコードは省略。
# name の空欄不可
validates :name, presence: true
# emailの空欄不可、一意指定
validates :email, presence: true, uniqueness: true
# emailの構成文字の大文字小文字の区別はしない
# あとで、正規表現込みのvalidation追加等するが、あとまわし。
validates :email, presence: { case_sensitive: false }
# 購入席数の空欄不可
validates :seats_total, presence: true
# 購入席数は4席まで。(試験問題には無いけど)
validates :seats_total, numericality: {less_than_or_equal_to: 4}
##初期データ作成 (seeds.rb使用)
普段はコンソールからが多いが、rails tutorialをやって、seeds.rbの方が勝手が良かったので。
あと、gem Fakerは、SAOなど『遊び』があって、好きだが、rubyメソッドの勉強にならないので、今回はパス
###ユーザ作成
カラムは氏名とemailアドレス
# 管理者
User.create!(name: 'おりばー', email: 'ないしょ@gmail.com', password: 'ないしょ', admin: true)
# 一般ユーザ。とりあえず、20人作る。
20.times do |i|
name = (1..5).map { ('あ'..'ん').to_a[rand(20)] }.join
email = ('a'..'z').to_a.shuffle[1..5].join
User.create!(name: name, email: "#{email}-#{i}@gmail.com", password: SecureRandom.base64)
end
###商品表と商品詳細表の作成
(まだ足りないと思うが)リファクタリングの結果、コードが合わさったので、纏めて表示。
なお、qiita用に、一部コードの順序を変えてある、が、見づらい。
# concert
# 20回分のコンサート、20組分のアーティストを作成
require 'active_support/all'
concert_name = %w[雅楽 令和 ジャズ ラスト ロック アニソン]
local = %w[東京 札幌 名古屋 大阪 広島 宮崎 台南 Cebu Perth]
artists = []
# 20回分のコンサート、20組分のアーティストを作成
(1..20).each do |n|
# コンサート開催日として、期間s1 ~ s2までのランダムな年月日を作成
s1 = Date.new(2019,5,31)
s2 = Date.new(2020,3,31)
s = Random.rand(s1..s2)
# 出演アーティストをランダムで作成して、配列に入れる。
# 作成した配列の並びをシャッフルし、先頭から1~5アーティストを取得し、カンマで繋げた文字列に。
artists << (1..3).map { ('A'..'Z').to_a[rand(20)] }.join.to_s
who_join = artists.shuffle.take(rand(5)+1).join('、')
# 試験問題の"クリスマスコンサート2018 in 東京 出演:Xバンド・・・"の表記に沿ってあげる。
infomation = "#{concert_name.sample}コンサート #{s.strftime('%Y')} in #{local.sample} 出演:#{who_join}"
# コンサート情報の開催年と、開催日時が合致するようにした。
Concert.create!(concert_info: infomation, concert_date: s.strftime('%Y-%-m-%-d'))
concert = Concert.find(n)
(0..2).each do |i|
# seat_price S > A > B
# prices = [price_s , price_a , price_b]
# capacity= [sの席数、aの席数、bの席数]
prices = [[40000, 35000, 30000], [28000, 25000, 23000, 19000], [18000, 15000, 13000, 11000, 9000]]
capacity = [rand(10..50), rand(100..500), rand(500..1000)]
ConcertDetail.create!(concert:concert,seat_grade:i, seat_price:prices[i].sample, tickets_total: capacity[i-1])
end
end
###actrive_recordを使おう
参照
##初期データ投入
ralis db:seed
##カラム名を変更しよう
思った。非常に分かりづらい。controller作成時に疲れそう。
会員表(User)テーブルはパス。あと、コードは一部省略
商品表(Concert)テーブル
現状カラム:コンサート情報:concert_info , 開催日時:concert_date
=>infomation , date
create_table :concerts do |t|
t.text :infomation
t.datetime :date
t.timestamps
end
商品詳細表(ConcertDetail)テーブル
現状:席種:seat_grade , 販売価格:seat_price , 販売席数:ticket_total
=> grade , price , capacity
create_table :concert_details do |t|
t.references :concert, foreign_key: true
t.integer :grade
t.integer :price
t.integer :capacity
t.timestamps
end
販売表(Sale)テーブル
席種:seat_grade、席数:seats_total、販売日:sale_date、販売額:sales_total、決済期限日:payment_deadline、使用ポイント:used_point
=> grade , number_of_seats , date , amount , payment_deadline , used_point
このテーブルは安易にリネームすると尚更分かりづらくなるので、注意した。
販売額amountとごっちゃにならず、席数に最適な短い訳が思いつかないので、一応英語に従った。、
create_table :sales do |t|
t.references :concert, foreign_key: true
t.references :user, foreign_key: true
t.string :grade
t.integer :number_of_seats
t.datetime :date
t.integer :amount
t.datetime :payment_deadline
t.integer :used_point
t.timestamps
end
決済表(Payment)テーブル
決済日:payment_date、決済額:payment_total、付与ポイント:added_point
=> date , amount , added_point
create_table :payments do |t|
t.references :sale, foreign_key: true
t.datetime :date
t.integer :amount
t.integer :added_point
t.timestamps
end
seeds.rbファイルもカラム名を使用しているので、一部変更
rails db:migrate:reset
rails db:migrate
rails db:seed
あとは、controllerとviewを弄っていくか。