テーブル構造を考える
他の(マシンの)システムで多いのは、コードテーブル、名称テーブルの類を利用する
一般論として、顧客マスターや商品マスター、社員マスターといったマスターでは、顧客マスターや商品コード、社員番号といったユニークキー(プライマリーキー)と、顧客名、商品名、社員名といった名称、さらに住所や販売価格、在庫数といった付随する情報がセットされていると思います。
どんなシステムでもコード値の存在チェックは行いますので、それを利用して、名称を表示しています。
そういったマスター以外に、細かい区分やフラグといったものに名称をつけたいといったニーズがあり(例えば、商品でしたら、1=仕入商品、2=委託商品など)、一般的には、これを名称テーブルあるいはコードテーブルといったファイル名で取り扱うケースが多々あります。
もし、これがすでに基幹システムなどに存在し、夜間バッチ等でRails用のデータベースに差し替えるようなことが可能ならば、それを利用してSELECTのOPTIONタグの表示名称として利用したいのですよね。
コードテーブルのデータ構造について
多くのケースでは、
- コードヘッダー:コードキー(ユニークキー)と、このコードの名称や使用目的等を記述
- コード明細:コードキー(ユニークキー)と実際の区分値とその名称や略称を保持
といった親子関係で表現されていることが多いと思います。
画面に表示される桁数には制限があるので、多くの場合は略称を持っています。
Ruby on Rails(Activerecord)の制限をもとにしたテーブル構成
もし、Railsでこれをインポートするには、以下の構造になるはずです。
- コードヘッダー:idとコードキー(ユニークキー)と、このコードの名称や使用目的等を記述
- コード明細:*idと、ヘッダーテーブルのid**、実際の区分値とその名称や略称を保持
Railsのプライマリーキーはidになりますので、子にはヘッダーテーブルのidを持つことで、親子関係を実現します。
こちらをもとにして実装していくことにします。
(参考)夜間バッチで差し替えるには?
参考までに、ロジックを考えてみます。
プログラムその1:コードキー(ユニークキー)が期間。Rails両者に存在する場合
親テーブルをUPDATEし、子のテーブルをDELETE/INSERTします。
その際、親のidを子にセットします。
プログラムその2:コードキー(ユニークキー)がRails側に存在しない場合
親テーブルをINSERTし、子のテーブルをINSERTします。
親テーブルのidは新規に与えられますので、コードキー(ユニークキー)で親のidにを取得し、その親idも含めた形で子をINSERTしてください。
プログラムその3:コードキー(ユニークキー)がRails側にのみ存在する場合
基幹側が削除されたとみなし、親テーブルをDELETEし、子のテーブルもDELETEします。
実装手順
親子のテーブル作成
まずは親のテーブルを作成します。
bundle exec rails g scaffold Codeheader code_key:string code_name:string
code_keyは基幹システムのプライマリーキー、code_nameはこのコード自体の名称を記述します。
のちほど、cocoonでメンテナンス画面を作成するために、g scaffold
にしておきます。
次に、このテーブルを作成します。
bundle exec rails g model Codedetail value_key:string value_name:string short_name:string codeheader:belongs_to
value_keyは区分やフラグの値、value_nameはその名称、short_nameはその略称です。
codeheader:belongs_to
で親テーブルのidをセットするカラムが作成されます(MySQLではid同様bigintとなる)。
こちらはscaffoldではなくg model
にしておきます。
モデルに追記する
app/models/codeheader.rb
に以下を追記します。
has_many :codedetails, dependent: :destroy #accepts_nested_attributes_for :codedetails, reject_if: :all_blank, allow_destroy: true accepts_nested_attributes_for :codedetails, allow_destroy: true
reject_if: :all_blank
は親のみ作成される危険性があるため、記述を除去します。
app/models/codedetail.rb
に以下を追記します。
belongs_to :codeheader
ヘルパーにSELECT/OPTION用の配列を求める関数を作成
app/helpers/application_helper.rb
に以下を追記します。
# select/optionを取得 def get_select_option(key) return Codedetail.joins(:codeheader).select("codeheaders.*, codedetails.*").where("codeheaders.code_key = ?",key) end
ビュー側でヘルパーの関数を埋め込む
_form.html.haml
に以下を追記します(追記例)。
.field.col-md-4.mb-3 = f.label :category, class: "form-label" = f.collection_select :category, get_select_option('category'), :value_key, :value_name, {prompt: "選択してください"}, :class => 'form-control', :id => 'category'
上記はcategoryというコードキーを持つ一覧を取得してOPTIONタグを生成していきます。
value_name
をshort_name
に変更すると、略称がセットされると思います。
かなり簡単に実装できましたね。
cocoonを使って、メンテンス画面を作成する
基幹からデータ持ってくるだけでしたら、別段必要はないですが、基幹もなく、イチから用意したい場合は、cocoonを利用した管理画面を用意したほうが良いかと思います。
幸い、cocoonについてのコラムは用意していますが、それをリンクしながら、異なる点などを説明します。
cocoonのインストール
「modelおよびscaffoldの作成」はこの記事のものを使用してください。
それ以降もProject、project、projectsはCodeheader、codeheader、codeheadersに差し替えてください。
同様に、Task、task、tsaksはCodedetail、codedetail、codedetailsに差し替えてください。
「コントローラーの変更」のパラメータは下記のように変更してください。
●app/helpers/application_helper.rb
# Only allow a list of trusted parameters through. def codeheader_params #params.require(:codeheader).permit(:code_key, :code_name) params.require(:codeheader).permit(:code_key, :code_name, codedetails_attributes: [:id, :value_key, :value_name, :short_name, :_destroy]) end
cocoonのエラー訂正
tasksはcodedetailsに差し替えます。
Task、task、tsaksはCodedetail、codedetail、codedetailsに差し替えてください。
子の二重登録エラーは、前出のapp/helpers/application_helper.rb
のパラメータ変更が行われているのならば、発生しないはずです。
子の0行エラー抑制
Project、project、projectsはCodeheader、codeheader、codeheadersに差し替えてください。
同様に、Task、task、tsaksはCodedetail、codedetail、codedetailsに差し替えてください。
子の件数抑制
Project、project、projectsはCodeheader、codeheader、codeheadersに差し替えてください。
同様に、Task、task、tsaksはCodedetail、codedetail、codedetailsに差し替えてください。
(taskはTASKもありますね。)
行コピー
taskのみcodedetailに読み替えてください。
子の重複チェック
projectをcodeheaderに差し替えてください。
同様に、tsaksはcodedetailsに差し替えてください。
以上で、cocoon化は完了するかと思います。
お好みで
お好みで、ページネーションや検索、ソートを実装してみてください。
時間があれば、日本語化も。
これで、ほぼほぼ良い感じになると思います。