shimmyShow Webアプリ開発ブログ

プログラミングスクールTECH::CAMPを73期を卒業し、紙媒体で実施されている教育の根本を変えていくためのサービスを開発中。当ブログを読めば誰でも当該サービスを開発できるようにするため軌跡を記録中。

【Ruby on Rails】gem 'ancestry'を使用する際のseedによる初期データ登録

Ruby on Railsにおいて、gem 'ancestry'を使用したテーブルへの初期データ登録にseedを活用する場合に create文を大量に記述する必要が生じる。 下記Qiitaの参考記事をもとにcreate文の記述量をできるだけ抑えたseedの記述方法を下記に示す。

概要

ancestry(親・子・孫)を活用したテーブルへの初期データ(大量)の実装

具体例

下記例は、ancestryを活用したtextsテーブルへのデータ登録処理(seeds.rb)の例  親:高等学校数学の大分類(例:数学ⅠA)  子:大分類の中の項目(例:集合と論理や2次関数など)  孫:項目の内容(例:集合の基本や部分集合、2次関数のグラフ、平方完成など)

テーブル定義(マイグレーションファイル)

class CreateTexts < ActiveRecord::Migration[5.2]
  def change
    create_table :texts do |t|
      t.text     :content,        null:false
      t.string     :ancestry
      t.timestamps
    end
  end
end

seeds.rb

#######################################
# テキストテーブルへのデータ登録処理
#######################################

def createChildAndGrandChildren(parentArray, childArray, grandChildrenArray)
  childArray.each_with_index do |child, i|
    child = parentArray.children.create(content: child)
    grandChildrenArray[i].each do |grandchild|
      child.children.create(content: grandchild)
    end
  end
end

#######################################
# 初期データ定義
#######################################

# 数学ⅠAの子カテゴリー
mathmatics_1A     = Text.create(content: '数学ⅠA')
# 数学ⅠAの子カテゴリー
mathmatics_1A_child = ["数と式","集合と論理","2次関数"]
#数学ⅠAの孫カテゴリー
mathmatics_1A_grand_children = [
  # 数と式
  ["次数は文字を掛けた回数のこと","指数法則を使いこなす","有理数と無理数","3つの連立方程式"],
  # 集合と論理
  ["集合の基本","部分集合","否定","逆, 裏, 対偶"],
  # 2次関数
  ["2次関数のグラフ","平方完成","平行移動","解の条件"]
]

# 数学ⅡBの親カテゴリー
mathmatics_2B     = Text.create(content: '数学ⅡB')
# 数学ⅡBの子カテゴリー
mathmatics_2B_child = ["複素数と方程式","三角関数","微分"]
# 数学ⅡBの孫カテゴリー
mathmatics_2B_grand_children = [
  # 複素数と方程式
  ["複素数の計算","剰余の定理","高次方程式","3乗して1になる虚数"],
  # 三角関数
  ["弧度法","加法定理","合成","三角関数の最大と最小"],
  # 微分
  ["極限","導関数"]
]

#######################################
# 初期データ登録
#######################################
createChildAndGrandChildren(mathmatics_1A, mathmatics_1A_child, mathmatics_1A_grand_children);
createChildAndGrandChildren(mathmatics_2B, mathmatics_2B_child, mathmatics_2B_grand_children);

実行コマンド

テーブルが空の場合、下記resetコマンドは不要

rails db:migrate:reset
rails db:seed

コマンド実行後テーブル

f:id:erwinmarvin:20200822145317p:plain
Texts table 初期データ登録
 

参考記事

 下記Qiita記事を参考に登録処理部分の関数化を実施  参考記事の説明が非常にわかりやすい為、上記処理を理解するためには一読すべきです。 qiita.com

Ruby on Rails 外部キー制約カラムにNULL値を許可する方法

Ruby on Railsにおいて、カラムに外部キーを設定するとNULL値を登録することができない。外部キー制約を設定しつつ、NULL値を許可する方法を下記に示す。

 

現状

下記の場合、外部キー制約が設定されたカラムにNULL値は登録できない。

productテーブルのマイグレーションファイル

 カラム:product_brandを外部キーとして設定

     null :false の設定はしていない 

class CreateProducts < ActiveRecord::Migration[5.2]
def change
create_table :products do |t|
t.references :product_brand, foreign_key: true
t.timestamps
end
end
end

 

product モデル

class Product < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :product_brand
end
 
上記状態の場合、productテーブルのカラムproduct_brandはNULL値を登録することができない。
 

修正

下記のようにoptional: trueを設定することでNULL値が登録できるようになる。
 
peoductモデル
 optional: true を設定するとproductテーブルのカラムproduct_brandにNULL値を登録することが可能となる。
class Product < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :product_brand, optional: true
end
 

都道府県テーブル作成前に確認したい gem active_hash !

都道府県名など基本的に変更が入らないデータに関しては都道府県テーブルを作成し、データベース上に登録しておいてもいいが、active_hashを用いることでデータベースへ登録する必要がなくなる。

 

具体的な導入方法

Gemの追加

Gemfileへ下記記述を追加する。

 Gemfile

  gem 'active_hash'

gemのinstall

下記コマンドを実行する。

  bundle install

 

モデルを作成

下記コマンドを実行する。

(group_dev部分は生成するモデル名のため作成したいモデル名を入力してください。)

 rails g model group_dev 

マイグレーションファイルの修正

モデルを生成するとマイグレーションファイルが生成される。

必要なカラム prefecture_idとprefecture_nameを追加する。

 db/migrate/20XXXXXXXXXXXX_create_group_devs.rb

  def change

      create_table :group_devs do |t|

        t.integer :prefecture_id

        t.string :prefecture_name

        t.timestamps

      end

   end

 

マイグレーションファイルの実行 

下記コマンドを実行する。

 rails db:migrate

 

Prefectureモデルの生成

コマンドではなく、新規ファイル生成から下記ファイルを作成する。

/app/models/prefecture.rb

class Prefecture < ActiveHash::Base

  self.data = [

      {id: 1, name: '北海道'},

      {id: 2, name: '青森県'},

      {id: 3, name: '秋田県'},

      {id: 4, name: '岩手県'},

      {id: 5, name: '宮城県'},

      {id: 6, name: '山形県'},

      {id: 7, name: '福島県'},

      {id: 8, name: '茨城県'},

      {id: 9, name: '栃木県'},

      {id: 10, name: '群馬県'},

      {id: 11, name: '埼玉県'},

      {id: 12, name: '千葉県'},

      {id: 13, name: '東京都'},

      {id: 14, name: '神奈川県'},

      {id: 15, name: '新潟県'},

      {id: 16, name: '富山県'},

      {id: 17, name: '石川県'},

      {id: 18, name: '福井県'},

      {id: 19, name: '山梨県'},

      {id: 20, name: '長野県'},

      {id: 21, name: '岐阜県'},

      {id: 22, name: '静岡県'},

      {id: 23, name: '愛知県'},

      {id: 24, name: '三重県'},

      {id: 25, name: '滋賀県'},

      {id: 26, name: '京都府'},

      {id: 27, name: '大阪府'},

      {id: 28, name: '兵庫県'},

      {id: 29, name: '奈良県'},

      {id: 30, name: '和歌山県'},

      {id: 31, name: '鳥取県'},

      {id: 32, name: '島根県'},

      {id: 33, name: '岡山県'},

      {id: 34, name: '広島県'},

      {id: 35, name: '山口県'},

      {id: 36, name: '徳島県'},

      {id: 37, name: '香川県'},

      {id: 38, name: '愛媛県'},

      {id: 39, name: '高知県'},

      {id: 40, name: '福岡県'},

      {id: 41, name: '佐賀県'},

      {id: 42, name: '長崎県'},

      {id: 43, name: '熊本県'},

      {id: 44, name: '大分県'},

      {id: 45, name: '宮崎県'},

      {id: 46, name: '鹿児島県'},

      {id: 47, name: '沖縄県'}

  ]

end

 

group_devモデルの修正

 rails g modelコマンドで生成したモデルへprefecture active_hashとのアソシエーションを記述する。

 group_dev.rb 

  class GroupDev < ApplicationRecord

    extend ActiveHash::Associations::ActiveRecordExtensions

    belongs_to_active_hash :prefecture

  end

 

準備完了

コントローラーの編集

都道府県データを登録するためにコントローラーに下記を実装する。

 class GroupDevsController < ApplicationController

   def index

     @prefecture = GroupDev.new

   end

 end

 

ビューの編集

 今回はindex.html.haml都道府県の選択ボックスを表示することにする。

 (下記のままコピー&ペーストで使用することもできるが、それぞれの環境でクラス名等の変更は実施してください。)

 index.html.haml

 .putup

   .putup__main

     .putup__main__prefecture

       %p.putup__main__prefecture__title

         都道府県

         %span.putup__main__prefecture__title__imperative

           必須

       .putup__main__prefecture__box

         = form_for @product do |f|

           = f.collection_select :prefecture_id, Prefecture.all, :id, :name, {prompt: ""}, {class: "putup__main__prefecture__box__def"}

 

cssの編集

index.html.haml用にscssも下記のように編集する。

index.scss

.putup{

  background-color: whitesmoke;

 

  &__main{

    width: 50%;

    min-width: 500px;

    height: 100vh;

    margin:0 auto;

    background-color: white;

    &__prefecture{

      padding-top: 40px;

      &__title{

        margin-left: 40px;

        font-weight: bold;

        font-size: 14px;

        &__imperative{

          border-radius: 2px;

          padding: 2px 4px;

          font-size: 12px;

          background-color:#99FFFF;

        }

      }

      &__box{

        margin: 20px 40px 0px 40px;

        height: 40px;

        border-radius: 5px;

        &__def{

          width: 100%;

          height: 40px;

        }

      }

    }

  }

}

 

上記記述が完了し、ブラウザで確認すると下記のように表示される。

f:id:erwinmarvin:20200610224849p:plain

表示

f:id:erwinmarvin:20200610224915p:plain

プルダウン表示