inuinu blog(開発用)

BOT @wagagun の開発ノウハウや、IT向け?の雑記ブログです。

【Ruby on Rails7】SELECT/OPTIONタグ用のテーブルを作成

この記事では、HTMLタグ(SELECT/OPTION)を作成するためのテーブルをマイグレーションし、ビューで使用する方法を考えてきます。
さらに、cocoonで管理する方法も考えます。

テーブル構造を考える

他の(マシンの)システムで多いのは、コードテーブル、名称テーブルの類を利用する

一般論として、顧客マスターや商品マスター、社員マスターといったマスターでは、顧客マスターや商品コード、社員番号といったユニークキー(プライマリーキー)と、顧客名、商品名、社員名といった名称、さらに住所や販売価格、在庫数といった付随する情報がセットされていると思います。

どんなシステムでもコード値の存在チェックは行いますので、それを利用して、名称を表示しています。

そういったマスター以外に、細かい区分やフラグといったものに名称をつけたいといったニーズがあり(例えば、商品でしたら、1=仕入商品、2=委託商品など)、一般的には、これを名称テーブルあるいはコードテーブルといったファイル名で取り扱うケースが多々あります。

もし、これがすでに基幹システムなどに存在し、夜間バッチ等でRails用のデータベースに差し替えるようなことが可能ならば、それを利用してSELECTのOPTIONタグの表示名称として利用したいのですよね。

コードテーブルのデータ構造について

多くのケースでは、

  • コードヘッダー:コードキー(ユニークキー)と、このコードの名称や使用目的等を記述
  • コード明細:コードキー(ユニークキー)と実際の区分値とその名称や略称を保持

といった親子関係で表現されていることが多いと思います。
画面に表示される桁数には制限があるので、多くの場合は略称を持っています。

Ruby on Rails(Activerecord)の制限をもとにしたテーブル構成

もし、Railsでこれをインポートするには、以下の構造になるはずです。

  • コードヘッダー:idとコードキー(ユニークキー)と、このコードの名称や使用目的等を記述
  • コード明細:*idと、ヘッダーテーブルのid**、実際の区分値とその名称や略称を保持

Railsのプライマリーキーはidになりますので、子にはヘッダーテーブルのidを持つことで、親子関係を実現します。

上記例では、子にはコードキー(ユニークキー)は持たないようにしていますが、ActiverecordあるいはSQLの条件として持っても良いかと思います。

こちらをもとにして実装していくことにします。

(参考)夜間バッチで差し替えるには?

参考までに、ロジックを考えてみます。

プログラムその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_nameshort_nameに変更すると、略称がセットされると思います。

かなり簡単に実装できましたね。

cocoonを使って、メンテンス画面を作成する

基幹からデータ持ってくるだけでしたら、別段必要はないですが、基幹もなく、イチから用意したい場合は、cocoonを利用した管理画面を用意したほうが良いかと思います。

幸い、cocoonについてのコラムは用意していますが、それをリンクしながら、異なる点などを説明します。

cocoonのインストール

inuinu-tech.hatenablog.jp

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のエラー訂正

inuinu-tech.hatenablog.jp

tasksはcodedetailsに差し替えます。

inuinu-tech.hatenablog.jp

Task、task、tsaksはCodedetail、codedetail、codedetailsに差し替えてください。

inuinu-tech.hatenablog.jp

子の二重登録エラーは、前出のapp/helpers/application_helper.rbのパラメータ変更が行われているのならば、発生しないはずです。

子の0行エラー抑制

inuinu-tech.hatenablog.jp

Project、project、projectsはCodeheader、codeheader、codeheadersに差し替えてください。
同様に、Task、task、tsaksはCodedetail、codedetail、codedetailsに差し替えてください。

子の件数抑制

inuinu-tech.hatenablog.jp

inuinu-tech.hatenablog.jp

Project、project、projectsはCodeheader、codeheader、codeheadersに差し替えてください。
同様に、Task、task、tsaksはCodedetail、codedetail、codedetailsに差し替えてください。
(taskはTASKもありますね。)

行コピー

inuinu-tech.hatenablog.jp

inuinu-tech.hatenablog.jp

inuinu-tech.hatenablog.jp

taskのみcodedetailに読み替えてください。

子の重複チェック

inuinu-tech.hatenablog.jp

projectをcodeheaderに差し替えてください。
同様に、tsaksはcodedetailsに差し替えてください。

以上で、cocoon化は完了するかと思います。

お好みで

お好みで、ページネーションや検索、ソートを実装してみてください。

inuinu-tech.hatenablog.jp

inuinu-tech.hatenablog.jp

時間があれば、日本語化も。

inuinu-tech.hatenablog.jp

これで、ほぼほぼ良い感じになると思います。