Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions lib/active_admin_import/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ module ActiveAdminImport
# +plural_resource_label+:: pluralized resource label value (default config.plural_resource_label)
#
module DSL
CONTEXT_METHOD = :active_admin_import_context

def self.prepare_import_model(template_object, controller, params: nil)
model = template_object.is_a?(Proc) ? template_object.call : template_object
if params
params_key = ActiveModel::Naming.param_key(model.class)
model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
end
return model unless controller.respond_to?(CONTEXT_METHOD, true)
context = controller.send(CONTEXT_METHOD)
return model unless context.is_a?(Hash)
context = context.merge(file: model.file) if model.respond_to?(:file) && !context.key?(:file)
model.assign_attributes(context)
model
end

DEFAULT_RESULT_PROC = lambda do |result, options|
model_name = options[:resource_label].downcase
plural_model_name = options[:plural_resource_label].downcase
Expand Down Expand Up @@ -57,11 +73,7 @@ def active_admin_import(options = {}, &block)

collection_action :import, method: :get do
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
@active_admin_import_model = if options[:template_object].is_a?(Proc)
options[:template_object].call
else
options[:template_object]
end
@active_admin_import_model = ActiveAdminImport::DSL.prepare_import_model(options[:template_object], self)
render template: options[:template]
end

Expand All @@ -78,13 +90,9 @@ def active_admin_import(options = {}, &block)
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
_params = params.respond_to?(:to_unsafe_h) ? params.to_unsafe_h : params
params = ActiveSupport::HashWithIndifferentAccess.new _params
@active_admin_import_model = if options[:template_object].is_a?(Proc)
options[:template_object].call
else
options[:template_object]
end
params_key = ActiveModel::Naming.param_key(@active_admin_import_model.class)
@active_admin_import_model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
@active_admin_import_model = ActiveAdminImport::DSL.prepare_import_model(
options[:template_object], self, params: params
)
# go back to form
return render template: options[:template] unless @active_admin_import_model.valid?
@importer = Importer.new(
Expand Down
3 changes: 3 additions & 0 deletions spec/fixtures/files/post_comments.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"Body"
"First comment"
"Second comment"
63 changes: 63 additions & 0 deletions spec/import_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -626,4 +626,67 @@ def upload_file!(name, ext = 'csv')
end.not_to change { Author.count }
end
end

context 'with active_admin_import_context defined on the controller' do
before { Author.create!(name: 'John', last_name: 'Doe') }

let(:author) { Author.take }

context 'when context returns request-derived attributes' do
before do
author_id = author.id
add_post_resource(
template_object: ActiveAdminImport::Model.new(author_id: author_id),
before_batch_import: lambda do |importer|
ip = importer.model.request_ip
a_id = importer.model.author_id
importer.csv_lines.map! { |row| row << ip << a_id }
importer.headers.merge!(:'Request Ip' => :request_ip, :'Author Id' => :author_id)
end,
controller_block: proc do
def active_admin_import_context
{ request_ip: request.remote_ip }
end
end
)
visit '/admin/posts/import'
upload_file!(:posts_for_author)
end

it 'merges the context into the import model so callbacks see it' do
expect(page).to have_content 'Successfully imported 2 posts'
expect(Post.count).to eq(2)
Post.all.each do |post|
expect(post.request_ip).to eq('127.0.0.1')
expect(post.author_id).to eq(author.id)
end
end
end

context 'when context returns parent id for a nested belongs_to resource' do
let(:post) { Post.create!(title: 'A post', body: 'body', author: author) }

before do
add_nested_post_comment_resource(
before_batch_import: lambda do |importer|
importer.csv_lines.map! { |row| row << importer.model.post_id }
importer.headers.merge!(:'Post Id' => :post_id)
end,
controller_block: proc do
def active_admin_import_context
{ post_id: parent.id }
end
end
)
visit "/admin/posts/#{post.id}/post_comments/import"
upload_file!(:post_comments)
end

it 'automatically assigns the parent post_id to every imported comment' do
expect(page).to have_content 'Successfully imported 2 post comments'
expect(PostComment.count).to eq(2)
expect(PostComment.where(post_id: post.id).count).to eq(2)
end
end
end
end
16 changes: 16 additions & 0 deletions spec/support/admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,24 @@ def add_author_resource(options = {}, &block)
end

def add_post_resource(options = {}, &block)
cb = options.delete(:controller_block)
ActiveAdmin.register Post do
config.filters = false
controller(&cb) if cb
active_admin_import(options, &block)
end
Rails.application.reload_routes!
end

def add_nested_post_comment_resource(options = {}, &block)
cb = options.delete(:controller_block)
ActiveAdmin.register Post do
config.filters = false
end
ActiveAdmin.register PostComment do
config.filters = false
belongs_to :post
controller(&cb) if cb
active_admin_import(options, &block)
end
Rails.application.reload_routes!
Expand Down
5 changes: 3 additions & 2 deletions spec/support/rails_template.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
create_file "app/assets/config/manifest.js", skip: true

generate :model, 'author name:string{10}:uniq last_name:string birthday:date --force'
generate :model, 'post title:string:uniq body:text author:references --force'
generate :model, 'post title:string:uniq body:text request_ip:string author:references --force'
generate :model, 'post_comment body:text post:references --force'

inject_into_file 'app/models/author.rb', " validates_presence_of :name\n validates_uniqueness_of :last_name\n", before: 'end'
inject_into_file 'app/models/post.rb', " validates_presence_of :author\n", before: 'end'
inject_into_file 'app/models/post.rb', " validates_presence_of :author\n has_many :post_comments\n", before: 'end'

# Add our local Active Admin to the load path (Rails 7.1+)
gsub_file "config/environment.rb",
Expand Down
Loading