Skip to content

Commit 064ef88

Browse files
authored
Merge pull request #211 from activeadmin-plugins/add-import-context
Add active_admin_import_context convention for controller-provided context
2 parents c5f8ffe + 8f60ef7 commit 064ef88

File tree

5 files changed

+105
-14
lines changed

5 files changed

+105
-14
lines changed

lib/active_admin_import/dsl.rb

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ module ActiveAdminImport
2525
# +plural_resource_label+:: pluralized resource label value (default config.plural_resource_label)
2626
#
2727
module DSL
28+
CONTEXT_METHOD = :active_admin_import_context
29+
30+
def self.prepare_import_model(template_object, controller, params: nil)
31+
model = template_object.is_a?(Proc) ? template_object.call : template_object
32+
if params
33+
params_key = ActiveModel::Naming.param_key(model.class)
34+
model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
35+
end
36+
return model unless controller.respond_to?(CONTEXT_METHOD, true)
37+
context = controller.send(CONTEXT_METHOD)
38+
return model unless context.is_a?(Hash)
39+
context = context.merge(file: model.file) if model.respond_to?(:file) && !context.key?(:file)
40+
model.assign_attributes(context)
41+
model
42+
end
43+
2844
DEFAULT_RESULT_PROC = lambda do |result, options|
2945
model_name = options[:resource_label].downcase
3046
plural_model_name = options[:plural_resource_label].downcase
@@ -57,11 +73,7 @@ def active_admin_import(options = {}, &block)
5773

5874
collection_action :import, method: :get do
5975
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
60-
@active_admin_import_model = if options[:template_object].is_a?(Proc)
61-
options[:template_object].call
62-
else
63-
options[:template_object]
64-
end
76+
@active_admin_import_model = ActiveAdminImport::DSL.prepare_import_model(options[:template_object], self)
6577
render template: options[:template]
6678
end
6779

@@ -78,13 +90,9 @@ def active_admin_import(options = {}, &block)
7890
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
7991
_params = params.respond_to?(:to_unsafe_h) ? params.to_unsafe_h : params
8092
params = ActiveSupport::HashWithIndifferentAccess.new _params
81-
@active_admin_import_model = if options[:template_object].is_a?(Proc)
82-
options[:template_object].call
83-
else
84-
options[:template_object]
85-
end
86-
params_key = ActiveModel::Naming.param_key(@active_admin_import_model.class)
87-
@active_admin_import_model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
93+
@active_admin_import_model = ActiveAdminImport::DSL.prepare_import_model(
94+
options[:template_object], self, params: params
95+
)
8896
# go back to form
8997
return render template: options[:template] unless @active_admin_import_model.valid?
9098
@importer = Importer.new(
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"Body"
2+
"First comment"
3+
"Second comment"

spec/import_spec.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,4 +626,67 @@ def upload_file!(name, ext = 'csv')
626626
end.not_to change { Author.count }
627627
end
628628
end
629+
630+
context 'with active_admin_import_context defined on the controller' do
631+
before { Author.create!(name: 'John', last_name: 'Doe') }
632+
633+
let(:author) { Author.take }
634+
635+
context 'when context returns request-derived attributes' do
636+
before do
637+
author_id = author.id
638+
add_post_resource(
639+
template_object: ActiveAdminImport::Model.new(author_id: author_id),
640+
before_batch_import: lambda do |importer|
641+
ip = importer.model.request_ip
642+
a_id = importer.model.author_id
643+
importer.csv_lines.map! { |row| row << ip << a_id }
644+
importer.headers.merge!(:'Request Ip' => :request_ip, :'Author Id' => :author_id)
645+
end,
646+
controller_block: proc do
647+
def active_admin_import_context
648+
{ request_ip: request.remote_ip }
649+
end
650+
end
651+
)
652+
visit '/admin/posts/import'
653+
upload_file!(:posts_for_author)
654+
end
655+
656+
it 'merges the context into the import model so callbacks see it' do
657+
expect(page).to have_content 'Successfully imported 2 posts'
658+
expect(Post.count).to eq(2)
659+
Post.all.each do |post|
660+
expect(post.request_ip).to eq('127.0.0.1')
661+
expect(post.author_id).to eq(author.id)
662+
end
663+
end
664+
end
665+
666+
context 'when context returns parent id for a nested belongs_to resource' do
667+
let(:post) { Post.create!(title: 'A post', body: 'body', author: author) }
668+
669+
before do
670+
add_nested_post_comment_resource(
671+
before_batch_import: lambda do |importer|
672+
importer.csv_lines.map! { |row| row << importer.model.post_id }
673+
importer.headers.merge!(:'Post Id' => :post_id)
674+
end,
675+
controller_block: proc do
676+
def active_admin_import_context
677+
{ post_id: parent.id }
678+
end
679+
end
680+
)
681+
visit "/admin/posts/#{post.id}/post_comments/import"
682+
upload_file!(:post_comments)
683+
end
684+
685+
it 'automatically assigns the parent post_id to every imported comment' do
686+
expect(page).to have_content 'Successfully imported 2 post comments'
687+
expect(PostComment.count).to eq(2)
688+
expect(PostComment.where(post_id: post.id).count).to eq(2)
689+
end
690+
end
691+
end
629692
end

spec/support/admin.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,24 @@ def add_author_resource(options = {}, &block)
88
end
99

1010
def add_post_resource(options = {}, &block)
11+
cb = options.delete(:controller_block)
1112
ActiveAdmin.register Post do
1213
config.filters = false
14+
controller(&cb) if cb
15+
active_admin_import(options, &block)
16+
end
17+
Rails.application.reload_routes!
18+
end
19+
20+
def add_nested_post_comment_resource(options = {}, &block)
21+
cb = options.delete(:controller_block)
22+
ActiveAdmin.register Post do
23+
config.filters = false
24+
end
25+
ActiveAdmin.register PostComment do
26+
config.filters = false
27+
belongs_to :post
28+
controller(&cb) if cb
1329
active_admin_import(options, &block)
1430
end
1531
Rails.application.reload_routes!

spec/support/rails_template.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
create_file "app/assets/config/manifest.js", skip: true
22

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

67
inject_into_file 'app/models/author.rb', " validates_presence_of :name\n validates_uniqueness_of :last_name\n", before: 'end'
7-
inject_into_file 'app/models/post.rb', " validates_presence_of :author\n", before: 'end'
8+
inject_into_file 'app/models/post.rb', " validates_presence_of :author\n has_many :post_comments\n", before: 'end'
89

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

0 commit comments

Comments
 (0)