サービスの論理設計とRailsで複数モデルを使用する画面の実装

 工数管理システムを題材にRails開発の練習を始めています。まずはDFD、ER、テーブル定義と画面のモックアップを作成し、最初の1画面を実装します。実装面では今回は複数テーブルを扱えるようにフォーム用モデルを扱えるようにします。

 最初に設計をしていますが、これは実装を迷わないようにする意味が大きいです。実装をする段階で矛盾、誤りがあれば見直していきます。まずはDFDとERとテーブル定義です。最初にこれだけのものをざっと設計してしまうのは、実装時に迷わないようにするため、もう少し言えば、データフローがつながらない(=機能・画面が足らない、遷移が足らない)かを検討しています。つながらなくなってしまうのは、DFD上の「プロセス」(マルの部分)が不足していたり、ER上の関係が適切ではなく、インプットからその時その時で必要な情報が辿れないといことが考えられます。*1

 

ある程度イけそうだという確証が持てたら実装に入っていきます。

f:id:s06068ss:20191021103116p:plain

DFD

f:id:s06068ss:20191021103122p:plain

ER

f:id:s06068ss:20191021103947p:plain

テーブル定義

 

DFD上のプロセスはおおよそ画面と一致するように書いています。トップページは遷移だけで何もデータは触りません。工数表新規作成が事実上の最初のページで、まずはここから作ります。

<モックアップ>

f:id:s06068ss:20191021103126p:plain

f:id:s06068ss:20191021103130p:plain

<実際の画面>

f:id:s06068ss:20191021123941j:plain

f:id:s06068ss:20191021123951j:plain

作ったコントローラとトップページ

私の直感では、DFD上のプロセス1つにつき1コントローラが作られる、と思っています。トップページと、そのうち作るであろうヘルプページ用に、静的ページを扱うコントローラを1つ、新規作成画面を扱うコントローラを1つ定義しました。ルータの定義でいえば下記のようにしてあります。

 

root ‘statics#index’

#工数票を新規作成
resources :app_initializes, only: [:new, :create]

 トップページは工数票の新規作成に向けてリンクしています。

<%= link_to “新たに工数表を作成する”, new_app_initialize_path, class:”btn btn-primary” %>

 

 工数表新規作成のページ

ネーミングセンスがちと怪しいですが、事実上このページがアプリの初期化処理に相当するので「AppInitializesController」としました。 画面を作るにあたっては下記の点を、このアプリにおけるルールにしました。2つ目以降のルールは次以降の記事に続きます。

 

フォーム用の「モデル」を定義する

 画面とコントローラ間でデータをやり取りするためのモデルは基本必ず定義することにします。Railsチュートリアルでは、テーブルと対になるモデル(=例えばUser)をフォームデータとしても扱っていました。テーブルとは関係ないデータの受け渡しの例はログインフォームのところで出てきます。

https://railstutorial.jp/chapters/basic_login?version=5.1#code-login_form

しかし、「form_for(:session, url: login_path)」のように「:xxxx」としているので、View→Controllerへの受け渡しはできますが(params[:session][:hogehoge])、その逆はできないと思われます。さりとて、1画面で3テーブルを扱う以上はテーブルと対になるモデルは使えません。そこで、フォーム用のモデルを「form」ディレクトリに定義します。(関係ないものは省略)

ec2-user:~/environment/man_hour_app/app/models (second-step) $ ls -laR
.:
total 52
drwxrwxr-x 4 ec2-user ec2-user 4096 Oct 12 09:19 .
drwxrwxr-x 10 ec2-user ec2-user 4096 Sep 21 13:14 ..
-rw-rw-r– 1 ec2-user ec2-user 345 Oct 12 05:31 account.rb
-rw-rw-r– 1 ec2-user ec2-user 78 Sep 21 13:14 application_record.rb
drwxrwxr-x 2 ec2-user ec2-user 4096 Oct 12 10:02 form
-rw-rw-r– 1 ec2-user ec2-user 1763 Oct 14 13:40 user.rb

./form:
total 16
drwxrwxr-x 2 ec2-user ec2-user 4096 Oct 12 10:02 .
drwxrwxr-x 4 ec2-user ec2-user 4096 Oct 12 09:19 ..
-rw-rw-r– 1 ec2-user ec2-user 372 Oct 12 05:31 form_app_initializes.rb

 

form_app_initializes.rb

class FormAppInitializes
include ActiveModel::Model
attr_accessor :user_name, :email, :password, :default_man_hour

validates( :password, presence: true, length:{ minimum:6 }, confirmation: true )
validates( :email, confirmation: true )

validates( :user_name, presence:true , length:{maximum:50} )
validates( :default_man_hour, length:{maximum:50} )

end

 attr_accessorは画面項目の分だけ作っています。確認欄はvalidatesに「confirmation: true 」を定義しているので、自動的に「_confirmation」の項目が定義されます。*2

 

 formディレクトリに入れているのは、後々モデルがいっぱいになってしまいそうだからですが、このままではこのディレクトリがパスに入っていないため認識されません。認識されるように「config/application.rb 」に下記を追加します。

Rails.application.config.eager_load_paths += Dir[Rails.application.config.root.join(‘app’,’models’,’form’)]

 (rails cで「Rails.application.config.eager_load_paths」で確認)

 

これで、ViewとControllerの間でやり取りするためのフォーム用モデルが使えるようになりました。 

 

次回は、項目やValidate時のエラーメッセージの日本語化をやっていきます。

 

メモ:

モックアップやDFD、ERの作図に使用したツール

https://pencil.evolus.vn/

Web屋さんが使うツールではないと思いますが、 SI屋さんが使うには使いやすいんじゃないでしょうか。

 

 

*1:DFDを、GETやセッションから受け取るパラメータのレベルまで詳細に書くともはや立派な詳細設計書です。私が以前いた現場では、新人に「詳細なDFD」を書くよう推奨していました。書かなくても実装できるならともかく、新人だとテンパってしまって書けなくなるので、実装で迷わない為というのが目的です。

*2:個人的には、Railsチュートリアルをしている時からテーブル≠画面なのですから、「画面項目のモデル」に「確認欄」のValidateをかけるなら理解できるが、「テーブルの1行を表すモデル」に「確認項目」のValidateがあるというのが「違うんじゃないか?」と思っていました…。どうなんでしょうね。