[Ruby on Rails 4] カラーミーショップで利用していた商品マスタの CSV データをインポートする

product.csv というファイルに商品マスタのデータがあり、これを参照したい。
カラーミーショップのフォーマット(らしい)。

下準備

product.csv の一行目にカラム名が日本語で収まっているので、これを参考にします。


商品ID カテゴリー(大) カテゴリー(小) 型番 商品名 商品画像URL フィーチャーフォン向けショップ用商品画像作成 その他画像1URL その他画像2URL その他画像3URL その他画像4URL その他画像5URL その他画像6URL その他画像7URL その他画像8URL その他画像9URL 販売価格 会員価格 定価 原価 在庫数 在庫管理 最小購入数量 最大購入数量 販売開始日付 販売開始時間 販売終了日付 販売終了時間 単位 重量 売切れ時の表示設定 適正在庫数 表示順 簡易説明 商品説明 フィーチャーフォン向けショップ用商品説明 スマートフォンショップ用商品説明 トラックバック受付設定 Newマーク付加設定 Newマーク画像選択 広告用カテゴリーID 広告用タグ1 広告用タグ2 広告用タグ3 広告用商品説明 ブランド JAN/ISBN(GTIN) 製品番号(MPN) 状態 性別 色 サイズ タイトル キーワード ページ概要 個別送料 掲載設定 軽減税率設定

rails g するために一つずつ書き起こしておきます。

元データは歯抜けの部分が多いため、不明な点は概ね string で、その他は想像で埋めております。
万全を期したい方は、実データと仕様をご確認ください。

rails generate scaffold ShopMasterProduct \
product_id:string \
category_1:string \
category_2:string \
model_number:string \
product_name:string \
product_image_url_main:string \
product_image_flag_for_feature_phone:string \
product_image_url_1:string \
product_image_url_2:string \
product_image_url_3:string \
product_image_url_4:string \
product_image_url_5:string \
product_image_url_6:string \
product_image_url_7:string \
product_image_url_8:string \
product_image_url_9:string \
selling_price:integer \
members_price:integer \
list_price:integer \
prime_cost:integer \
stock_quantity:integer \
stock_control_flag:string \
minimum_purchase_quantity:integer \
max_purchase_quantity:integer \
sales_start_date:date \
sales_start_time:time \
sales_end_date:date \
sales_end_time:time \
unit:string \
weight:string \
display_setting_at_sold_out:string \
appropriate_stock_quantity:integer \
display_order:integer \
simple_description:string \
product_description:text \
product_description_for_feature_phone:text \
product_description_for_smart_phone:text \
trackback_reception_setting:string \
new_mark_additional_setting:string \
new_mark_image_selection:string \
category_id_for_ad:string \
tag_1_for_ad:string \
tag_2_for_ad:string \
tag_3_for_ad:string \
product_description_for_ad:string \
brand:string \
gtin:string \
mpn:string \
condition:string \
sex:string \
color:string \
size:string \
page_title:string \
page_keyword:string \
page_description:string \
individual_shipping_fee:integer \
posting_flag:string \
reduced_tax_rate_setting:string

rails generate

scaffold を実行します。
自前でファイルを作りたい方は rails generate model でも良いかと思います。

% bundle exec rails generate scaffold ShopMasterProduct product_id:string category_1:string category_2:string model_number:string product_name:string product_image_url_main:string product_image_flag_for_feature_phone:string product_image_url_1:string product_image_url_2:string product_image_url_3:string product_image_url_4:string product_image_url_5:string product_image_url_6:string product_image_url_7:string product_image_url_8:string product_image_url_9:string selling_price:integer members_price:integer list_price:integer prime_cost:integer stock_quantity:integer stock_control_flag:string minimum_purchase_quantity:integer max_purchase_quantity:integer sales_start_date:date sales_start_time:time sales_end_date:date sales_end_time:time unit:string weight:string display_setting_at_sold_out:string appropriate_stock_quantity:integer display_order:integer simple_description:string product_description:text product_description_for_feature_phone:text product_description_for_smart_phone:text trackback_reception_setting:string new_mark_additional_setting:string new_mark_image_selection:string category_id_for_ad:string tag_1_for_ad:string tag_2_for_ad:string tag_3_for_ad:string product_description_for_ad:string brand:string gtin:string mpn:string condition:string sex:string color:string size:string page_title:string page_keyword:string page_description:string individual_shipping_fee:integer posting_flag:string reduced_tax_rate_setting:string

後日、対応するカラム名が分からなくなること必至なので、migration ファイルにコメントを追加しておきます。

下記のようになりました。

db/migrate/20200108091051_create_shop_master_products.rb
class CreateShopMasterProducts < ActiveRecord::Migration
  def change
    create_table :shop_master_products do |t|
      t.string :product_id                            # 商品ID
      t.string :category_1                            # カテゴリー(大)
      t.string :category_2                            # カテゴリー(小)
      t.string :model_number                          # 型番
      t.string :product_name                          # 商品名
      t.string :product_image_url_main                # 商品画像URL
      t.string :product_image_flag_for_feature_phone  # フィーチャーフォン向けショップ用商品画像作成
      t.string :product_image_url_1                   # その他画像1URL
      t.string :product_image_url_2                   # その他画像2URL
      t.string :product_image_url_3                   # その他画像3URL
      t.string :product_image_url_4                   # その他画像4URL
      t.string :product_image_url_5                   # その他画像5URL
      t.string :product_image_url_6                   # その他画像6URL
      t.string :product_image_url_7                   # その他画像7URL
      t.string :product_image_url_8                   # その他画像8URL
      t.string :product_image_url_9                   # その他画像9URL
      t.integer :selling_price                        # 販売価格
      t.integer :members_price                        # 会員価格
      t.integer :list_price                           # 定価
      t.integer :prime_cost                           # 原価
      t.integer :stock_quantity                       # 在庫数
      t.string :stock_control_flag                    # 在庫管理
      t.integer :minimum_purchase_quantity            # 最小購入数量
      t.integer :max_purchase_quantity                # 最大購入数量
      t.date :sales_start_date                        # 販売開始日付
      t.time :sales_start_time                        # 販売開始時間
      t.date :sales_end_date                          # 販売終了日付
      t.time :sales_end_time                          # 販売終了時間
      t.string :unit                                  # 単位
      t.string :weight                                # 重量
      t.string :display_setting_at_sold_out           # 売切れ時の表示設定
      t.integer :appropriate_stock_quantity           # 適正在庫数
      t.integer :display_order                        # 表示順
      t.string :simple_description                    # 簡易説明
      t.text :product_description                     # 商品説明
      t.text :product_description_for_feature_phone   # フィーチャーフォン向けショップ用商品説明
      t.text :product_description_for_smart_phone     # スマートフォンショップ用商品説明
      t.string :trackback_reception_setting           # トラックバック受付設定
      t.string :new_mark_additional_setting           # Newマーク付加設定
      t.string :new_mark_image_selection              # Newマーク画像選択
      t.string :category_id_for_ad                    # 広告用カテゴリーID
      t.string :tag_1_for_ad                          # 広告用タグ1
      t.string :tag_2_for_ad                          # 広告用タグ2
      t.string :tag_3_for_ad                          # 広告用タグ3
      t.string :product_description_for_ad            # 広告用商品説明
      t.string :brand                                 # ブランド
      t.string :gtin                                  # JAN/ISBN(GTIN)
      t.string :mpn                                   # 製品番号(MPN)
      t.string :condition                             # 状態
      t.string :sex                                   # 性別
      t.string :color                                 # 色
      t.string :size                                  # サイズ
      t.string :page_title                            # タイトル
      t.string :page_keyword                          # キーワード
      t.string :page_description                      # ページ概要
      t.integer :individual_shipping_fee              # 個別送料
      t.string :posting_flag                          # 掲載設定
      t.string :reduced_tax_rate_setting              # 軽減税率設定

      t.timestamps null: false
    end
  end
end

db:migrate を実行します。

% bundle exec rake db:migrate 

CSV import 機能を実装する

さて箱の用意が完了しましたので import 機能を実装していきます。

まず Ruby の csv ライブラリを利用する設定を加えます。
追加後にサーバを再起動します。

config/application.rb
require 'csv'
require 'rails'

コントローラに import アクションを追加します。

app/controllers/shop_master_products_controller.rb
  # CSV import
  def import
    ShopMasterProduct.import(params[:file])
    redirect_to shop_master_products_url, notice: 'Shop master product CSV was successfully imported.'
  end

import アクションをルーティング設定に加えます。

config/routes.rb
Rails.application.routes.draw do
  resources :shop_master_products do
    post :import, on: :collection
  end

一覧画面のビューに import ボタンを追加します。

app/views/shop_master_products/index.html.haml
= form_tag import_shop_master_products_path, multipart: true, class: 'mb-3' do
  = file_field_tag :file
  = submit_tag 'import', class: 'btn btn-primary'

モデルに import メソッドを実装します。
CSVのフォーマットは拡張 Shift JIS のようでしたので CP932 を指定します。

app/models/shop_master_product.rb
class ShopMasterProduct < ActiveRecord::Base
  def self.import(file)
    CSV.foreach(file.path, headers: true, encoding: 'CP932:UTF-8') do |row|
      ShopMasterProduct.create(
          product_id: row[0],
          category_1: row[1],
          category_2: row[2],
          model_number: row[3],
          product_name: row[4],
          product_image_url_main: row[5],
          product_image_flag_for_feature_phone: row[6],
          product_image_url_1: row[7],
          product_image_url_2: row[8],
          product_image_url_3: row[9],
          product_image_url_4: row[10],
          product_image_url_5: row[11],
          product_image_url_6: row[12],
          product_image_url_7: row[13],
          product_image_url_8: row[14],
          product_image_url_9: row[15],
          selling_price: row[16],
          members_price: row[17],
          list_price: row[18],
          prime_cost: row[19],
          stock_quantity: row[20],
          stock_control_flag: row[21],
          minimum_purchase_quantity: row[22],
          max_purchase_quantity: row[23],
          sales_start_date: row[24],
          sales_start_time: row[25],
          sales_end_date: row[26],
          sales_end_time: row[27],
          unit: row[28],
          weight: row[29],
          display_setting_at_sold_out: row[30],
          appropriate_stock_quantity: row[31],
          display_order: row[32],
          simple_description: row[33],
          product_description: row[34],
          product_description_for_feature_phone: row[35],
          product_description_for_smart_phone: row[36],
          trackback_reception_setting: row[37],
          new_mark_additional_setting: row[38],
          new_mark_image_selection: row[39],
          category_id_for_ad: row[40],
          tag_1_for_ad: row[41],
          tag_2_for_ad: row[42],
          tag_3_for_ad: row[43],
          product_description_for_ad: row[44],
          brand: row[45],
          gtin: row[46],
          mpn: row[47],
          condition: row[48],
          sex: row[49],
          color: row[50],
          size: row[51],
          page_title: row[52],
          page_keyword: row[53],
          page_description: row[54],
          individual_shipping_fee: row[55],
          posting_flag: row[56],
          reduced_tax_rate_setting: row[57]
      )
    end
  end
end

ヘッダが日本語な為、ゴリゴリにカラムを書いています。
永続的に使うのであれば .attributes_names 等を利用してヘッダ行を書き換えたり、カラム数の変更を確認するような処理を加えると良いかも知れません。

もっと良い書き方があれば是非教えてください。

補遺