Skip to content

Commit 688e5e1

Browse files
authored
Merge pull request #215 from activeadmin-plugins/readme-docs
Move documentation from wiki/gh-pages into README
2 parents df5ed39 + cfb0fc2 commit 688e5e1

File tree

1 file changed

+210
-4
lines changed

1 file changed

+210
-4
lines changed

README.md

Lines changed: 210 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
The fastest and most efficient CSV import for Active Admin with support for validations, bulk inserts, and encoding handling.
1111

12-
For more about ActiveAdminImport installation and usage, check [Documentation website](http://activeadmin-plugins.github.io/active_admin_import/) and [Wiki pages](https://github.com/activeadmin-plugins/active_admin_import/wiki) for some specific cases and caveats.
13-
1412

1513
## Installation
1614

@@ -109,9 +107,217 @@ The action block is invoked via `instance_exec` with `result` and `options` as b
109107

110108
Note: which batch-result attributes are populated depends on the database adapter and the import options. `activerecord-import` returns ids reliably on PostgreSQL; on MySQL/SQLite the behavior depends on the adapter and options like `on_duplicate_key_update`. Putting the collection logic in your own subclass keeps these adapter quirks in your application code.
111109

112-
#### Wiki
113110

114-
[Check various examples](https://github.com/activeadmin-plugins/active_admin_import/wiki)
111+
#### Authorization
112+
113+
The current user must be authorized to perform imports. With CanCanCan:
114+
115+
```ruby
116+
class Ability
117+
include CanCan::Ability
118+
119+
def initialize(user)
120+
can :import, Post
121+
end
122+
end
123+
```
124+
125+
126+
#### Per-request context
127+
128+
Define an `active_admin_import_context` method on the controller to inject request-derived attributes into every import (current user, parent resource id, request IP, etc.). The returned hash is merged into the import model after form params, so it always wins for the keys it provides:
129+
130+
```ruby
131+
ActiveAdmin.register PostComment do
132+
belongs_to :post
133+
134+
controller do
135+
def active_admin_import_context
136+
{ post_id: parent.id, request_ip: request.remote_ip }
137+
end
138+
end
139+
140+
active_admin_import before_batch_import: ->(importer) {
141+
importer.csv_lines.map! { |row| row << importer.model.post_id }
142+
importer.headers.merge!(:'Post Id' => :post_id)
143+
}
144+
end
145+
```
146+
147+
148+
#### Examples
149+
150+
##### Files without CSV headers
151+
152+
```ruby
153+
ActiveAdmin.register Post do
154+
active_admin_import validate: true,
155+
template_object: ActiveAdminImport::Model.new(
156+
hint: "expected header order: body, title, author",
157+
csv_headers: %w[body title author]
158+
)
159+
end
160+
```
161+
162+
##### Auto-detect file encoding
163+
164+
```ruby
165+
ActiveAdmin.register Post do
166+
active_admin_import validate: true,
167+
template_object: ActiveAdminImport::Model.new(force_encoding: :auto)
168+
end
169+
```
170+
171+
##### Force a specific (non-UTF-8) encoding
172+
173+
```ruby
174+
ActiveAdmin.register Post do
175+
active_admin_import validate: true,
176+
template_object: ActiveAdminImport::Model.new(
177+
hint: "file is encoded in ISO-8859-1",
178+
force_encoding: "ISO-8859-1"
179+
)
180+
end
181+
```
182+
183+
##### Disallow ZIP upload
184+
185+
```ruby
186+
ActiveAdmin.register Post do
187+
active_admin_import validate: true,
188+
template_object: ActiveAdminImport::Model.new(
189+
hint: "upload a CSV file",
190+
allow_archive: false
191+
)
192+
end
193+
```
194+
195+
##### Skip CSV columns
196+
197+
Useful when the CSV file has columns that don't exist on the table. Available since 3.1.0.
198+
199+
```ruby
200+
ActiveAdmin.register Post do
201+
active_admin_import before_batch_import: ->(importer) {
202+
importer.batch_slice_columns(['name', 'last_name'])
203+
}
204+
end
205+
```
206+
207+
Tip: pass `Post.column_names` to keep only the columns that exist on the table.
208+
209+
##### Resolve associations on the fly
210+
211+
Replace an `Author name` column in the CSV with the matching `author_id` before insert:
212+
213+
```ruby
214+
ActiveAdmin.register Post do
215+
active_admin_import validate: true,
216+
headers_rewrites: { 'Author name': :author_id },
217+
before_batch_import: ->(importer) {
218+
names = importer.values_at(:author_id)
219+
mapping = Author.where(name: names).pluck(:name, :id).to_h
220+
importer.batch_replace(:author_id, mapping)
221+
}
222+
end
223+
```
224+
225+
##### Update existing records by id
226+
227+
Delete colliding rows just before each batch insert:
228+
229+
```ruby
230+
ActiveAdmin.register Post do
231+
active_admin_import before_batch_import: ->(importer) {
232+
Post.where(id: importer.values_at('id')).delete_all
233+
}
234+
end
235+
```
236+
237+
For databases that support upserts you can use `:on_duplicate_key_update` instead.
238+
239+
##### Tune batch size
240+
241+
```ruby
242+
ActiveAdmin.register Post do
243+
active_admin_import validate: false,
244+
csv_options: { col_sep: ";" },
245+
batch_size: 1000
246+
end
247+
```
248+
249+
##### Import into an intermediate table
250+
251+
```ruby
252+
ActiveAdmin.register Post do
253+
active_admin_import validate: false,
254+
csv_options: { col_sep: ";" },
255+
resource_class: ImportedPost, # write to a staging table
256+
before_import: ->(_) { ImportedPost.delete_all },
257+
after_import: ->(_) {
258+
Post.transaction do
259+
Post.delete_all
260+
Post.connection.execute("INSERT INTO posts (SELECT * FROM imported_posts)")
261+
end
262+
},
263+
back: ->(_) { config.namespace.resource_for(Post).route_collection_path }
264+
end
265+
```
266+
267+
##### Allow user input for CSV options (custom template)
268+
269+
```ruby
270+
ActiveAdmin.register Post do
271+
active_admin_import validate: false,
272+
template: 'admin/posts/import',
273+
template_object: ActiveAdminImport::Model.new(
274+
hint: "you can configure CSV options",
275+
csv_options: { col_sep: ";", row_sep: nil, quote_char: nil }
276+
)
277+
end
278+
```
279+
280+
`app/views/admin/posts/import.html.erb`:
281+
282+
```erb
283+
<p><%= raw(@active_admin_import_model.hint) %></p>
284+
285+
<%= semantic_form_for @active_admin_import_model, url: { action: :do_import }, html: { multipart: true } do |f| %>
286+
<%= f.inputs do %>
287+
<%= f.input :file, as: :file %>
288+
<% end %>
289+
290+
<%= f.inputs "CSV options", for: [:csv_options, OpenStruct.new(@active_admin_import_model.csv_options)] do |csv| %>
291+
<% csv.with_options input_html: { style: 'width:40px;' } do |opts| %>
292+
<%= opts.input :col_sep %>
293+
<%= opts.input :row_sep %>
294+
<%= opts.input :quote_char %>
295+
<% end %>
296+
<% end %>
297+
298+
<%= f.actions do %>
299+
<%= f.action :submit,
300+
label: t("active_admin_import.import_btn"),
301+
button_html: { disable_with: t("active_admin_import.import_btn_disabled") } %>
302+
<% end %>
303+
<% end %>
304+
```
305+
306+
##### Inspecting the importer in batch callbacks
307+
308+
Both `before_batch_import` and `after_batch_import` receive the `Importer` instance:
309+
310+
```ruby
311+
active_admin_import before_batch_import: ->(importer) {
312+
importer.file # the uploaded file
313+
importer.resource # the ActiveRecord class being imported into
314+
importer.options # the resolved options hash
315+
importer.headers # CSV headers (mutable)
316+
importer.csv_lines # parsed CSV rows for the current batch (mutable)
317+
importer.model # the template_object instance
318+
}
319+
```
320+
115321

116322
## Dependencies
117323

0 commit comments

Comments
 (0)