Slide 1

Slide 1 text

ී௨ͷ $47Ξοϓϩʔυ ϑΥʔϜΛ࡞Γ͍ͨ !TZP :PLPIBNBSC

Slide 2

Slide 2 text

࠷ۙͷϚΠɾϒʔϜ 㾎IVCPUTDSJQU 㾎"JSCSBLF 㾎5SBWJT$* 㾎1JWPUBM5SBDLFS

Slide 3

Slide 3 text

Ͳ͏͖ 㾎ೖ໳ॻʹ৐ͬͯͳ͍ 㾎ೖ໳ॻͷ͕࣍গͳ͍ 㾎3BJMT$BTU͘Β͍ 㾎ྑ͍։ൃݱ৔ͰͷΈڞ༗͞Ε͍ͯΔ

Slide 4

Slide 4 text

Θ͔Δ͜ͱ 㾎'BU$POUSPMMFSͱ͸ͳʹ͔ʁ 㾎Ͳ͏͢Ε͹4LJOOZ$POUSPMMFSʹͳΔͷ͔ʁ

Slide 5

Slide 5 text

γφϦΦ 㾎؅ཧऀ͕Ұׅͯ͠ొ࿥ 㾎ෳ਺ͷϢʔβʔ৘ใ͕$47ϑΝΠϧʹ͋Δ 㾎$47ϑΝΠϧͷத਎͸ࢯ໊ͱFNBJM

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

class CreateUsers < ActiveRecord::Migration! def change! create_table :users do |t|! t.string :first_name, null:false! t.string :last_name, null:false! t.string :email, null:false! t.timestamps! end! ! add_index :users, :email, unique: true! end! end 6TFST

Slide 8

Slide 8 text

͋Γ͕ͪͳ࣮૷

Slide 9

Slide 9 text

class Admin::UsersController < ApplicationController! def index! end! ! def upload! f = params[:data_file]! flash[:notice] = 'Upload successful'! CSV.open(f.path, 'rb', encoding: 'UTF-8').each do |row|! User.create(email: row[0], first_name: row[1], last_name: row[2])! end! redirect_to action: :index! end! end "ENJO6TFST$POUSPMMFS

Slide 10

Slide 10 text

!

Users

! <% if flash[:notice].present? %>!
<%= flash[:notice] %>
! <% end %>! <%= form_tag(upload_admin_users_path, method: :post, multipart: true, role: "form", class: "form-inline") do %>!
! <%= file_field_tag :data_file, class: "form-control" %>!
!
! <%= button_tag "Upload", class: ["btn","btn-default"] %>!
!
! <% end %>! JOEFYIUNMFSC

Slide 11

Slide 11 text

ϦϦʔεͯ͠ΈͨΒ 㾎ϑΝΠϧࢦఆ͠ͳ͍ͱΤϥʔʹͳΓ·͢ 㾎ը૾͕Ξοϓϩʔυ͢ΔͱΤϥʔʹͳΓ·͢ 㾎˓˓͞ΜͷFNBJMΞυϨε͕͓͔͍͠Ͱ͢ 㾎ΤΫηϧ͔Β࡞ͬͨ$47͕औΓࠐΊ·ͤΜ 㾎ࡢ೔ొ࿥ͨ͠ϑΝΠϧΛΞοϓϩʔυͪ͠Ό͍·ͨ͠

Slide 12

Slide 12 text

σϞ

Slide 13

Slide 13 text

class Admin::UsersController < ApplicationController! def index! end! ! def upload! f = params[:data_file]! if f.blank?! flash[:notice] = 'File not found'! redirect_to action: :index! return! end! ! flash[:notice] = 'Upload successful'! CSV.open(f.path, 'rb', encoding: 'UTF-8').each do |row|! unless row[0] =~ /\A[a-z.-_]+@[a-z.-_]+\z/! next! end! ! User.create(email: row[0], first_name: row[1], last_name: row[2])! end! redirect_to action: :index! end! end "ENJO6TFST$POUSPMMFS

Slide 14

Slide 14 text

ཁ͕݅଍Γͯͳ͍ 㾎̎࣠ͷόϦσʔγϣϯ 㾎ϑΝΠϧϑΥʔϚοτ 㾎Ϩίʔυݸผ 㾎Ξϥʔτը໘ 㾎ςετ

Slide 15

Slide 15 text

Ͳ͏͢Ε͹ྑ͍ͷ͔ʁ

Slide 16

Slide 16 text

Ϟσϧʹ͢Ε͹͍͍ IUUQTHJTUHJUIVCDPNTZPGDGDDG

Slide 17

Slide 17 text

[email protected] ۭ৚ ဘॿ [email protected] ՖژӃ య໌ શମ͸6TFS*NQPSUϞσϧ ֤ߦ͸6TFSϞσϧ ੹຿ΛΘ͚ͯΈΔ

Slide 18

Slide 18 text

class Admin::UsersController < ApplicationController! def index! @user_import = UserImport.new! end! ! def import! @user_import = UserImport.new(params[:user_import])! if @user_import.save! redirect_to url_for(action: :index), notice: 'Upload successful'! else! render :index! end! end! end BENJOVTFST@DPOUSPMMFSSC

Slide 19

Slide 19 text

! <% if flash[:notice] %>!
! <%= flash[:notice] %>!
! <% end %>! !

Users

! <%= form_for(@user_import, url: import_admin_users_path,! html: {method: :post, multipart: true, role: "form", class: "form-inline"}) do |f| %>! <% if @user_import.errors.any? %>!
!
    ! <% @user_import.errors.full_messages.each do |msg| %>!
  • <%= msg %>
  • ! <% end %>!
!
! <% end %>! !
! <%= f.file_field :file, class: "form-control" %>!
!
! <%= f.button "Upload", class: ["btn","btn-default"] %>!
! <% end %>!
JOEFYIUNMFSC

Slide 20

Slide 20 text

class User < ActiveRecord::Base! validates :first_name, length: { maximum: 100 }, presence: true! validates :last_name, length: { maximum: 100 }, presence: true! validates :email, length: { maximum: 100 }, presence: true, uniqueness: true! end VTFSSC

Slide 21

Slide 21 text

class UserImport! CSV_OPTIONS = {encoding: 'UTF-8'}.freeze! include ActiveModel::Model! ! attr_accessor :file! ! validates :file, presence: true! validate :csv_format, if: Proc.new { |m| m.file.present? }! ! def save! end! ! private! def csv_format! end! ! def path! end! end VTFS@JNQPSUSC

Slide 22

Slide 22 text

def save! return false unless valid?! ! User.transaction do! CSV.read(path, "r", CSV_OPTIONS).each_with_index do |row, index|! user = User.new(email: row[0], first_name: row[1], last_name: row[2])! unless user.save! errors.add("line #{index+1} : ", user.errors.full_messages.join(" , "))! end! end! ! if errors.any?! raise ActiveRecord::Rollback! end! end! ! !errors.any?! end VTFS@JNQPSUSC

Slide 23

Slide 23 text

private! def csv_format! CSV.open(path, "r", CSV_OPTIONS) { |csv| }! rescue! errors.add(:file, "is invalid csv format")! end! ! def path! if file.respond_to? :path! file.path! else! file! end! end VTFS@JNQPSUSC

Slide 24

Slide 24 text

σϞ

Slide 25

Slide 25 text

ςετΛͲ͏ॻ͘ʁ

Slide 26

Slide 26 text

RSpec.describe UserImport do! describe "#file" do! ! …! end! ! describe "#save" do! subject { UserImport.new(file: file) }! context "༗ޮͳϑΥʔϚοτͷ࣌" do! let(:file) { Rails.root.join("spec/fixtures/valid.csv") }! let(:error_count) { CSV.read(file).count }! it { expect(subject.save).to be_truthy }! it { expect { subject.save }.to change(User, :count).by(error_count) }! end! ! context "ແޮͳϑΥʔϚοτͷ࣌" do! let(:file) { Rails.root.join("spec/fixtures/invalid.csv") }! it { expect(subject.save).to be_falsey }! end! ! context "UserϞσϧͰΤϥʔͰ͕͋Δ࣌" do! let(:file) { Rails.root.join("spec/fixtures/valid.csv") }! let(:errors) { double(add: nil, clear: nil, empty?: nil) }! before do! allow_any_instance_of(User).to receive(:save) { false }! expect(subject).to receive(:errors) { errors }.twice! end! it { expect(subject.save).to be_falsey }! it { expect { subject.save }.not_to change(User, :count) }! end! end! end VTFS@JNQPSU@TQFDSC

Slide 27

Slide 27 text

RSpec.describe UserImport do! describe "#save" do! subject { UserImport.new(file: file) }! context "UserϞσϧͰΤϥʔͰ͕͋Δ࣌" do! let(:file) { Rails.root.join("spec/fixtures/valid.csv") }! let(:errors) { double(add: nil, clear: nil, empty?: nil) }! before do! allow_any_instance_of(User).to receive(:save) { false }! expect(subject).to receive(:errors) { errors }.twice! end! it { expect(subject.save).to be_falsey }! it { expect { subject.save }.not_to change(User, :count) }! end! end! end VTFS@JNQPSU@TQFDSC

Slide 28

Slide 28 text

RSpec.describe Admin::UsersController do! describe "POST import" do! let(:attributes) { { file: Rack::Test::UploadedFile.new(file, "text/plan") } }! ! describe "with valid params" do! let(:file) { Rails.root.join("spec/fixtures/valid.csv") }! let(:record_count) { CSV.read(file).count }! ! it "creates new Users" do! expect {! post :import, {user_import: attributes}! }.to change(User, :count).by(record_count)! end! ! it "redirects to the created user" do! post :import, {user_import: attributes}! expect(response).to redirect_to(action: :index)! end! end! end! end BENJOVTFST@DPOUSPMMFS@TQFDSC

Slide 29

Slide 29 text

࣭໰ͳͲ

Slide 30

Slide 30 text

ײ૝ر๬