diff --git a/lib/active_admin_import/importer.rb b/lib/active_admin_import/importer.rb index ee42798..9193f26 100644 --- a/lib/active_admin_import/importer.rb +++ b/lib/active_admin_import/importer.rb @@ -2,7 +2,8 @@ module ActiveAdminImport class Importer - attr_reader :resource, :options, :result, :headers, :csv_lines, :model + attr_reader :resource, :options, :result, :model + attr_accessor :csv_lines, :headers OPTIONS = [ :validate, @@ -85,7 +86,7 @@ def process_file end def prepare_headers - headers = self.headers.present? ? self.headers : yield + headers = self.headers.present? ? self.headers.map(&:to_s) : yield @headers = Hash[headers.zip(headers.map { |el| el.underscore.gsub(/\s+/, '_') })].with_indifferent_access @headers.merge!(options[:headers_rewrites].symbolize_keys.slice(*@headers.symbolize_keys.keys)) @headers diff --git a/spec/fixtures/files/posts_for_author.csv b/spec/fixtures/files/posts_for_author.csv new file mode 100644 index 0000000..2dacf6a --- /dev/null +++ b/spec/fixtures/files/posts_for_author.csv @@ -0,0 +1,3 @@ +"Title","Body" +"title1","some body" +"title2","some body" \ No newline at end of file diff --git a/spec/fixtures/files/posts_for_author_no_headers.csv b/spec/fixtures/files/posts_for_author_no_headers.csv new file mode 100644 index 0000000..97e55bf --- /dev/null +++ b/spec/fixtures/files/posts_for_author_no_headers.csv @@ -0,0 +1,2 @@ +"title1","some body" +"title2","some body" \ No newline at end of file diff --git a/spec/import_spec.rb b/spec/import_spec.rb index 6c39105..b617be3 100644 --- a/spec/import_spec.rb +++ b/spec/import_spec.rb @@ -4,8 +4,8 @@ shared_examples 'successful inserts' do |encoding, csv_file_name| let(:options) do - attributes = { force_encoding: encoding } - { template_object: ActiveAdminImport::Model.new(attributes) } + attributes = {force_encoding: encoding} + {template_object: ActiveAdminImport::Model.new(attributes)} end before do @@ -21,7 +21,6 @@ expect(author.last_name).to be_present end end - end def with_zipped_csv(name, &block) @@ -36,7 +35,6 @@ def with_zipped_csv(name, &block) ensure File.delete zip_file rescue nil end - end def upload_file!(name, ext='csv') @@ -48,35 +46,90 @@ def upload_file!(name, ext='csv') before do Author.create!(name: "John", last_name: "Doe") Author.create!(name: "Jane", last_name: "Roe") - add_post_resource({ - validate: true, - headers_rewrites: { - :'Author Name' => :author_id - }, - before_batch_import: ->(importer) do - authors_names = importer.values_at(:author_id) - # replacing author name with author id - authors = Author.where(name: authors_names).pluck(:name, :id) - #{"Jane" => 2, "John" => 1} - options = Hash[*authors.flatten] - importer.batch_replace(:author_id, options) - end - }) - visit "/admin/posts/import" - upload_file!(:posts) end - it "should resolve author_id by author name" do - Post.all.each do |post| - expect(Author.where(id: post.author.id)).to be_present + context "for csv for particular author" do + let(:author){ + Author.take + } + + shared_examples 'successful inserts for author' do + it "should use predefined author_id" do + expect(Post.where(author_id: author.id).count).to eq(Post.count) + end + + it "should be imported" do + expect(Post.count).to eq(2) + expect(page).to have_content "Successfully imported 2 posts" + end + end + + context "no headers" do + before do + add_post_resource({ + template_object: ActiveAdminImport::Model.new( { author_id: author.id , csv_headers: [:title, :body, :author_id] }), + validate: true, + before_batch_import: ->(importer) do + importer.csv_lines.map! { |row| row << importer.model.author_id } + end + }) + + visit "/admin/posts/import" + upload_file!(:posts_for_author_no_headers) + end + include_examples 'successful inserts for author' + end + + context "with headers" do + before do + add_post_resource({ + template_object: ActiveAdminImport::Model.new( { author_id: author.id }), + validate: true, + before_batch_import: ->(importer) do + importer.csv_lines.map! { |row| row << importer.model.author_id } + importer.headers.merge!({:'Author Id' => :author_id }) + end + }) + + visit "/admin/posts/import" + upload_file!(:posts_for_author) + end + include_examples 'successful inserts for author' end end - it "should be imported" do - expect(Post.count).to eq(2) - expect(page).to have_content "Successfully imported 2 posts" - end + context "for csv with author name" do + before do + add_post_resource({ + validate: true, + template_object: ActiveAdminImport::Model.new, + headers_rewrites: { + :'Author Name' => :author_id + }, + before_batch_import: ->(importer) do + authors_names = importer.values_at(:author_id) + # replacing author name with author id + authors = Author.where(name: authors_names).pluck(:name, :id) + #{"Jane" => 2, "John" => 1} + options = Hash[*authors.flatten] + importer.batch_replace(:author_id, options) + end + }) + visit "/admin/posts/import" + upload_file!(:posts) + end + + it "should resolve author_id by author name" do + Post.all.each do |post| + expect(Author.where(id: post.author.id)).to be_present + end + end + it "should be imported" do + expect(Post.count).to eq(2) + expect(page).to have_content "Successfully imported 2 posts" + end + end end context "authors index" do @@ -91,19 +144,14 @@ def upload_file!(name, ext='csv') find_link('Import Authors').click expect(current_path).to eq("/admin/authors/import") end - - end context "with custom block" do - - before do add_author_resource({}) do flash[:notice] = 'some custom message' end visit '/admin/authors/import' - end it "should display notice from custom block" do @@ -111,7 +159,6 @@ def upload_file!(name, ext='csv') expect(page).to have_content "some custom message" end - end context "authors already exist" do @@ -123,10 +170,10 @@ def upload_file!(name, ext='csv') context "having authors with the same Id" do before do add_author_resource({ - before_batch_import: ->(importer) do - Author.where(id: importer.values_at("id")).delete_all - end - }) + before_batch_import: ->(importer) do + Author.where(id: importer.values_at("id")).delete_all + end + }) visit "/admin/authors/import" upload_file!(:authors_with_ids) end @@ -136,13 +183,11 @@ def upload_file!(name, ext='csv') expect(Author.count).to eq(2) end - it "should replace authors by id" do + it "should replace authors by id" do expect(Author.find(1).name).to eq("John") expect(Author.find(2).name).to eq("Jane") end - end - end context "with valid options" do @@ -154,7 +199,6 @@ def upload_file!(name, ext='csv') visit '/admin/authors/import' end - it "has valid form" do form = find('#new_active_admin_import_model') expect(form['action']).to eq("/admin/authors/do_import") @@ -169,7 +213,7 @@ def upload_file!(name, ext='csv') context "with hint defined" do let(:options) do - { template_object: ActiveAdminImport::Model.new(hint: "hint") } + {template_object: ActiveAdminImport::Model.new(hint: "hint")} end it "renders hint at upload page" do expect(page).to have_content options[:template_object].hint @@ -209,17 +253,14 @@ def upload_file!(name, ext='csv') end context "BOM" do - it "should import file with many records" do upload_file!(:authors_bom) expect(page).to have_content "Successfully imported 2 authors" expect(Author.count).to eq(2) end - end context "with headers" do - it "should import file with many records" do upload_file!(:authors) expect(page).to have_content "Successfully imported 2 authors" @@ -231,16 +272,13 @@ def upload_file!(name, ext='csv') expect(page).to have_content "Successfully imported 1 author" expect(Author.count).to eq(1) end - end - context "without headers" do context "with known csv headers" do - let(:options) do - attributes = { csv_headers: ['Name', 'Last name', 'Birthday'] } - { template_object: ActiveAdminImport::Model.new(attributes) } + attributes = {csv_headers: ['Name', 'Last name', 'Birthday']} + {template_object: ActiveAdminImport::Model.new(attributes)} end it "should import file" do @@ -248,7 +286,6 @@ def upload_file!(name, ext='csv') expect(page).to have_content "Successfully imported 2 authors" expect(Author.count).to eq(2) end - end context "with unknown csv headers" do @@ -269,7 +306,6 @@ def upload_file!(name, ext='csv') end context "with invalid records" do - context "with validation" do it "should render error" do upload_file!(:author_invalid) @@ -278,23 +314,18 @@ def upload_file!(name, ext='csv') end end - context "without validation" do - let(:options) { { validate: false } } + let(:options) { {validate: false} } it "should render error" do upload_file!(:author_invalid) expect(page).to have_content "Successfully imported 1 author" expect(Author.count).to eq(1) end - end - - end context "when zipped" do context "when allowed" do - it "should import file" do with_zipped_csv(:authors) do upload_file!(:authors, :zip) @@ -302,13 +333,12 @@ def upload_file!(name, ext='csv') expect(Author.count).to eq(2) end end - end context "when not allowed" do let(:options) do - attributes = { allow_archive: false } - { template_object: ActiveAdminImport::Model.new(attributes) } + attributes = {allow_archive: false} + {template_object: ActiveAdminImport::Model.new(attributes)} end it "should render error" do with_zipped_csv(:authors) do @@ -321,9 +351,8 @@ def upload_file!(name, ext='csv') end context "with different header attribute names" do - let(:options) do - { headers_rewrites: {:'Second name' => :last_name} } + {headers_rewrites: {:'Second name' => :last_name}} end it "should import file" do @@ -334,10 +363,9 @@ def upload_file!(name, ext='csv') end context "with semicolons separator" do - let(:options) do - attributes = { csv_options: { col_sep: ";" } } - { template_object: ActiveAdminImport::Model.new(attributes) } + attributes = {csv_options: {col_sep: ";"}} + {template_object: ActiveAdminImport::Model.new(attributes)} end it "should import file" do @@ -346,21 +374,18 @@ def upload_file!(name, ext='csv') expect(Author.count).to eq(2) end end - end - context "with callback procs options" do let(:options) do { - before_import: ->(_) { true }, - after_import: ->(_) { true }, - before_batch_import: ->(_) { true }, - after_batch_import: ->(_) { true } + before_import: ->(_) { true }, + after_import: ->(_) { true }, + before_batch_import: ->(_) { true }, + after_batch_import: ->(_) { true } } end - it "should call each callback" do expect(options[:before_import]).to receive(:call).with(kind_of(ActiveAdminImport::Importer)) expect(options[:after_import]).to receive(:call).with(kind_of(ActiveAdminImport::Importer)) @@ -374,7 +399,7 @@ def upload_file!(name, ext='csv') end context "with invalid options" do - let(:options) { { invalid_option: :invalid_value } } + let(:options) { {invalid_option: :invalid_value} } it "should raise TypeError" do expect { add_author_resource(options) }.to raise_error(ArgumentError) @@ -382,5 +407,4 @@ def upload_file!(name, ext='csv') end - end \ No newline at end of file