Skip to content

Instantly share code, notes, and snippets.

@1syo
Last active August 29, 2015 14:03
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 1syo/319f237637cf522c8c9f to your computer and use it in GitHub Desktop.
Save 1syo/319f237637cf522c8c9f to your computer and use it in GitHub Desktop.
<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>
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
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
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
end
require "rails_helper"
RSpec.describe UserImport do
describe "#file" do
subject { UserImport.new(file: file) }
context "設定されていない時" do
let(:file) { nil }
it { expect(subject).to have(1).errors_on(:file) }
end
context "設定されている時" do
let(:file) { Rails.root.join("spec/fixtures/valid.csv") }
it { expect(subject).not_to have(1).errors_on(:file) }
end
context "有効なフォーマットの時" do
let(:file) { Rails.root.join("spec/fixtures/valid.csv") }
it { expect(subject).not_to have(1).errors_on(:file) }
end
context "無効なフォーマットの時" do
let(:file) { Rails.root.join("spec/fixtures/invalid.csv") }
it { expect(subject).to have(1).errors_on(:file) }
end
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
require "rails_helper"
RSpec.describe Admin::UsersController do
describe "GET index" do
before do
get :index
end
it { expect(assigns(:user_import)).to be_kind_of(UserImport) }
end
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
describe "with invalid params" do
let(:file) { Rails.root.join("spec/fixtures/invalid.csv") }
it "do not creates new Users" do
expect {
post :import, {user_import: attributes}
}.not_to change(User, :count)
end
it "re-renders the 'index' template" do
post :import, {user: attributes}
expect(response).to render_template("index")
end
end
end
end
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment