未経験からエンジニア 奮闘記

未経験からエンジニアに自由に生きる途中

MENU

Rails CSV の基本 出力からアップロード Rspecまで

csv出力

  • view
<%= link_to "CSV", products_path(format: :csv) %>
  • controller
  def index
    respond_to do |format|
      format.html do
        @search = Product.ransack(params[:q])
        @products = @search.result    
      end

      format.csv do
        @products = Product.all
        data= CSV.generate do |csv|
          column_names = %w[id title product_price_id]
          csv << column_names
          @products.each do |product|
            row = [product.id, product.title, product.product_price_id]
            csv << row
          end
        end

        send_data(data, filename: 'produsts.csv')
      end
    end
  end

csv アップロード

  • gem
gem 'roo'
  • routes
  resources :products do 
    collection do 
      post :import
    end
  end
  • controller
  def import
    Product.import(params[:csv_file])
    redirect_to root_path
  end
  • model
class Product < ApplicationRecord
  belongs_to :product_price


  def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|
      product = Product.new
      product.attributes = row.to_hash.slice(*updatable_attributes)
      product.save
    end
  end

  def self.updatable_attributes
    ["title","product_price_id"]
  end
  • spec
require 'rails_helper'

RSpec.describe ProductsController, type: :controller do

  describe '#index' do
    before do
      price = ProductPrice.create(price: 2000)
      Product.create(title: "Product1", product_price_id: price.id)
    end

    it 'csv出力する' do
     get :index, format: :csv
     expect(response.body).to include "Product1"
    end

    context 'アップロード' do
      before do
        ProductPrice.create(id:1, price: 2000)
        ProductPrice.create(id:2, price: 2000)
      end
      let(:csv_file) {'test.csv'}

      subject do
        post :import, params: {
          csv_file: fixture_file_upload(csv_file, 'text/csv')
        }  
      end

      it 'aa' do
        expect{subject}.to change(Product,:count).by(2)
      end
    end
  end
end