$30 off During Our Annual Pro Sale. View Details »

普通のCSVアップロードフォームを作りたい

TAKAHASHI Kazunari
July 12, 2014
2.6k

 普通のCSVアップロードフォームを作りたい

TAKAHASHI Kazunari

July 12, 2014
Tweet

Transcript

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

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

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

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

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

  6. None
  7. 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
  8. ͋Γ͕ͪͳ࣮૷

  9. 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
  10. <div class="container">! <h1>Users</h1>! <% if flash[:notice].present? %>! <div class="bg-success"><%= flash[:notice]

    %></div>! <% end %>! <%= form_tag(upload_admin_users_path, method: :post, multipart: true, role: "form", class: "form-inline") do %>! <div class="form-group">! <%= file_field_tag :data_file, class: "form-control" %>! </div>! <div class="form-group">! <%= button_tag "Upload", class: ["btn","btn-default"] %>! </div>! </div>! <% end %>! </div> JOEFYIUNMFSC
  11. ϦϦʔεͯ͠ΈͨΒ 㾎ϑΝΠϧࢦఆ͠ͳ͍ͱΤϥʔʹͳΓ·͢ 㾎ը૾͕Ξοϓϩʔυ͢ΔͱΤϥʔʹͳΓ·͢ 㾎˓˓͞ΜͷFNBJMΞυϨε͕͓͔͍͠Ͱ͢ 㾎ΤΫηϧ͔Β࡞ͬͨ$47͕औΓࠐΊ·ͤΜ 㾎ࡢ೔ొ࿥ͨ͠ϑΝΠϧΛΞοϓϩʔυͪ͠Ό͍·ͨ͠

  12. σϞ

  13. 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
  14. ཁ͕݅଍Γͯͳ͍ 㾎̎࣠ͷόϦσʔγϣϯ 㾎ϑΝΠϧϑΥʔϚοτ 㾎Ϩίʔυݸผ 㾎Ξϥʔτը໘ 㾎ςετ

  15. Ͳ͏͢Ε͹ྑ͍ͷ͔ʁ

  16. Ϟσϧʹ͢Ε͹͍͍ IUUQTHJTUHJUIVCDPNTZPGDGDDG

  17. jojo@example.com ۭ৚ ဘॿ kakyoin@example.com ՖژӃ య໌ શମ͸6TFS*NQPSUϞσϧ ֤ߦ͸6TFSϞσϧ ੹຿ΛΘ͚ͯΈΔ

  18. 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
  19. <div class="container">! <% if flash[:notice] %>! <div class="alert alert-success">! <%=

    flash[:notice] %>! </div>! <% end %>! ! <h1>Users</h1>! <%= 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? %>! <div class="alert alert-danger">! <ul>! <% @user_import.errors.full_messages.each do |msg| %>! <li><%= msg %></li>! <% end %>! </ul>! </div>! <% end %>! ! <div class="form-group">! <%= f.file_field :file, class: "form-control" %>! </div>! <div class="form-group">! <%= f.button "Upload", class: ["btn","btn-default"] %>! </div>! <% end %>! </div> JOEFYIUNMFSC
  20. 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
  21. 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
  22. 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
  23. 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
  24. σϞ

  25. ςετΛͲ͏ॻ͘ʁ

  26. 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
  27. 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
  28. 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
  29. ࣭໰ͳͲ

  30. ײ૝ر๬