Coder Social home page Coder Social logo

rails_admin_import's Introduction

Rails Admin Import

Build Status

Plugin functionality to add generic import to Rails Admin from CSV, JSON and XLSX files

Versions

Rails Admin Import 3.x is compatible with Rails Admin 3.x.

If you're still using Rails Admin 2.x, use Rails Admin Import 2.3.1

Installation

  • First, add to Gemfile:
gem "rails_admin_import", "~> 3.0"
  • Define configuration in config/initializers/rails_admin_import.rb:
RailsAdmin.config do |config|
  # REQUIRED:
  # Include the import action
  # See https://github.com/sferik/rails_admin/wiki/Actions
  config.actions do
    all
    import
  end

  # Optional:
  # Configure global RailsAdminImport options
  # Configure pass filename to records hashes
  config.configure_with(:import) do |config|
    config.logging = true
    config.pass_filename = true
  end

  # Optional:
  # Configure model-specific options using standard RailsAdmin DSL
  # See https://github.com/sferik/rails_admin/wiki/Railsadmin-DSL
  config.model 'User' do
    import do
      include_all_fields
      exclude_fields :secret_token
    end
  end
end
  • If you are using CanCanCan for authorization, add to ability.rb to specify which models can be imported:
cannot :import, :all
can :import, [User, Model1, Model2]

Usage

Model instances can be both created and updated from import data. Any fields can be imported as long as they are allowed by the model's configuration. Associated records can be looked up for both singular and plural relationships. Both updating existing records and associating records requires the use of mapping keys.

Mapping Keys

Every importable class has a mapping key that uniquely identifies its instances. The mapping key can be one or more fields. The value for these fields can then be provided in import data, either to update the existing record or to attach it through an association to another model. This concept exists because ids are often not constant when moving records between data stores.

For example, a User model may have an email field. When uploading a set of users where some already exist in our database, we can select "email" as our mapping key and then provide that field on each record in our data, allowing us to update existing records with matching emails.

Using a csv formatted example:

Email,First name,Last name
[email protected],Peter,Gibbons
[email protected],Michael,Bolton

would look for existing users with those emails. If one was found, its name fields would be updated. Otherwise, a new one would be created.

For updating building owners, the mapping key could be street_address and zip_code.

Similarly, if each user has favorite books, we could set the mapping key for Book to be isbn and then include the isbn for their books within each user record. The syntax for this is to use the name of the associated model as the field name, no matter what actual mapping key has been selected. So a user record would have one or more fields named "Book" that include each associated book's ISBN.

Again using a csv formatted example:

Email, Book, Book, Book
[email protected], 9781119997870, 9780671027032
[email protected], 9780446677479

would look up books with those ISBNs and attach them to those users.

Mapping keys can be selected on the import page. Their defaults can also be globally configured in the config file:

RailsAdmin.config do |config|
  config.model 'User' do
    import do
      mapping_key :email
      # for multiple values, use mapping_key [:first_name, :last_name]
      mapping_key_list [:email, :some_other_id]
    end
  end
end

Since in models with large number of fields it doesn't make sense to use most of them as mapping values, you can add mapping_key_list to restrict which fields can be selected as mapping key in the UI during import.

Note that a matched record must exist when attaching associated models, or the imported record will fail and be skipped.

Complex associations (has_one ..., :through or polymorphic associations) need to be dealt with via custom logic called by one of the import hooks (see below for more detail on using hooks). If we wanted to import Services and attach them to a User, but the user relationship existed through an intermediary model called ServiceProvider, we could provide a user_email field in our records and handle the actual association with an import hook:

class Service < ActiveRecord::Base
  belongs_to :service_provider
  has_one :user, through: :service_provider

  def before_import_save(record)
    if (email = record[:user_email]) && (user = User.find_by_email(email))
      self.service_provider = user.service_provider
    end
  end
end

Importing new records by id is not recommended since it ignores the sequences of ids in database. That will lead to ERROR: duplicate key value violates unique constraint in future. You can work around this issue by adding an import_id column to your model, renaming the id column in your CSV to import_id and using import_id as the update lookup field.

File format

The format is inferred by the extension (.csv, .json or .xlsx).

CSV

The first line must contain attribute names. They will be converted to lowercase and underscored (First Name ==> first_name).

For "many" associations, you may include multiple columns with the same header in the CSV file.

The repeated header may be singular or plural. For example, for a "children" association, you may have multiple "child" columns or multiple "children" column, each containing one lookup value for an associated record. Blank values are ignored.

Example

First name,Last name,Team,Team
Peter,Gibbons,IT,Management
Michael,Bolton,IT,

Blank lines will be skipped.

JSON

The file must be an array or an object with a root key the same name as the plural model name, i.e. the default Rails JSON output format with include_root_in_json on or off.

XLSX

The Microsoft Excel XLM format (XLSX) is supported, but not the old binary Microsoft Excel format (XLS).

The expected rows and columns are the same as for the CSV format (first line contains headers, multiple columns for "many" associations).

Blank lines will be skipped.

Configuration

Global configuration options

RailsAdmin.config do |config|
  config.actions do
    all
    import
  end

  # Default global RailsAdminImport options
  config.configure_with(:import) do |config|
    config.logging = false
    config.line_item_limit = 1000
    config.update_if_exists = false
    config.pass_filename = false
    config.rollback_on_error = false
    config.header_converter = lambda do |header|
      header.parameterize.underscore if header.present?
    end
    config.csv_options = {}
  end
end
  • logging (default false): Save a copy of each imported file to log/import and a detailed import log to log/rails_admin_import.log

  • line_item_limit (default 1000): max number of items that can be imported at one time.

  • update_if_exists (default false): default value for the "Update if exists" checkbox on the import page.

  • rollback_on_error (default false): import records in a transaction and rollback if there is one error. Only for ActiveRecord, not Mongoid.

  • header_converter (default lambda { ... }): a lambda to convert each CSV header text string to a model attribute name. The default header converter converts to lowercase and replaces spaces with underscores.

  • csv_options (default {}): a hash of options that will be passed to a new CSV instance

  • pass_filename (default false): Access the uploaded file name in your model actions, for example if set to true, inside each record, there will be an addtional property record[:filename_importer] which contains the file name of the currently uploaded file.

Model-specific configuration

Use standard RailsAdmin DSL to add or remove fields.

  • To change the default attribute that will be used to find associations on import, set mapping_key (default attribute is name)
RailsAdmin.config do |config|
  config.model 'Ball' do
    import do
      mapping_key :color
    end
  end
end
  • To include a specific list of fields:
RailsAdmin.config do |config|
  config.model 'User' do
    import do
      field :first_name
      field :last_name
      field :email
    end
  end
end
  • To exclude specific fields:
RailsAdmin.config do |config|
  config.model 'User' do
    import do
      include_all_fields
      exclude_fields :secret_token
    end
  end
end
  • To add extra fields that will be set as attributes on the model and that will be passed to the import hook methods:
RailsAdmin.config do |config|
  config.model 'User' do
    import do
      include_all_fields
      fields :special_import_token
    end
  end
end
RailsAdmin.config do |config|
  config.model 'User' do
    import do
      default_excluded_fields [:created_at, :updated_at, :deleted_at, :c_at, :u_at]
    end
  end
end

Import hooks

Define methods on your models to be hooked into the import process, if special/additional processing is required on the data:

# some model
class User < ActiveRecord::Base
  def self.before_import
    # called on the model class once before importing any individual records
  end

  def self.before_import_find(record)
    # called on the model class before finding or creating the new record
    # maybe modify the import record that will be used to find the model
    # throw :skip to skip importing this record
    throw :skip unless record[:email].ends_with? "@mycompany.com"
  end

  def before_import_attributes(record)
    # called on the blank new model or the found model before fields are imported
    # maybe delete fields from the import record that you don't need
    # throw :skip to skip importing this record
  end

  def before_import_associations(record)
    # called on the model with attributes but before associations are imported
    # do custom import of associations
    # make sure to delete association fields from the import record to avoid double import
    record.delete(:my_association)
    # throw :skip to skip importing this record
  end

  def before_import_save(record)
    # called on the model before it is saved but after all fields and associations have been imported
    # make final modifications to the record
    # throw :skip to skip importing this record
  end

  def after_import_save(record)
    # called on the model after it is saved
  end

  def after_import_association_error(record)
    # called on the model when an association cannot be found
  end

  def after_import_error(record)
    # called on the model when save fails
  end

  def self.after_import
    # called once on the model class after importing all individual records
  end
end

For example, you could

  • Set an attribute on a Devise User model to skip checking for a password when importing a new model.

  • Import an image into Carrierwave via a URL provided in the CSV.

def before_import_save(record)
  self.remote_image_url = record[:image] if record[:image].present?  
end
  • Skip some validations when importing.
class User < ActiveRecord::Base
  # Non-persistent attribute to allow creating a new user without a password
  # Password will be set by the user by following a link in the invitation email
  attr_accessor :allow_blank_password

  devise :validatable

  # Called by Devise to enable/disable password presence validation
  def password_required?
    allow_blank_password ? false : super
  end

  # Don't require a password when importing users
  def before_import_save(record)
    self.allow_blank_password = true
  end
end

ORM: ActiveRecord and Mongoid

The gem is tested to work with ActiveRecord and Mongoid.

Support for Mongoid is early, so if you can suggest improvements (especially around importing embedded models), open an issue.

Eager loading

Since the import functionality is rarely used in many applications, some gems are autoloaded when first used during an import in order to save memory at boot.

If you prefer to eager load all dependecies at boot, use this line in your Gemfile.

gem "rails_admin_import", "~> 3.0", require: "rails_admin_import/eager_load"

Import error due to Rails class reloading

error due to class reloading

If you get an error like Error during import: MyModel(#70286054976500) expected, got MyModel(#70286114743280), you need restart the rails server and redo the import. This is due to the fact that Rails reloads the ActiveRecord model classes in development when you make changes to them and Rails Admin is still using the old class.

Another suggestion is to set config.cache_classes = true to true in your development.rb for Rails Admin Import to work around the ActiveRecord model class reloading issue. See this comment for more information.

Customize the UI

If you want to hide all the advanced fields from the import UI, you can copy app/views/rails_admin/main/import.html.haml to your project at the same path. Add hidden class to elements you want to hide.

For example:

    <div class="form-group control-group hidden">
      <label class="col-sm-2 control-label">
        <%= t("admin.import.update_if_exists") %>
      </label>
      <div class="col-sm-10 controls">
        <%= check_box_tag :update_if_exists, '1', RailsAdminImport.config.update_if_exists, :class => "form-control" %>
        <p class="help-block">
          <%= t('admin.import.help.update_if_exists') %>
        </p>
      </div>
    </div>

Upgrading

  • Move global config to config.configure_with(:import) in config/initializers/rails_admin_import.rb.

  • Move the field definitions to config.model 'User' do; import do; // ... in config/initializers/rails_admin_import.rb.

  • No need to mount RailsAdminImport in config/routes.rb (RailsAdmin must still be mounted).

  • Update model import hooks to take 1 hash argument instead of 2 arrays with values and headers.

  • Support for importing file attributes was removed since I couldn't understand how it works. It should be possible to reimplement it yourself using post import hooks. Open an issue to discuss how to put back support for importing files into the gem.

Community-contributed translations

Run tests

  1. Clone the repository to your machine

    git clone https://github.com/stephskardal/rails_admin_import

  2. Run bundle install

  3. Run bundle exec rspec

The structure of the tests is taken from the Rails Admin gem.

Authors

Original author: Steph Skardal

Maintainer (since May 2015): Julien Vanier

Release

  • Update lib/rails_admin_import/version.rb
  • Update the install instructions at the top of the readme
  • Commit to git
  • rake release

Contributing

Everyone is encouraged to help improve this project. Here are a few ways you can help:

Copyright

Copyright (c) 2015 End Point, Steph Skardal and contributors. See LICENSE.txt for further details.

rails_admin_import's People

Contributors

agonzalezro avatar aprofiti avatar baldursson avatar chewi avatar crackcomm avatar daisukekogasaki avatar dependabot[bot] avatar dmitrypol avatar guilhermedallanol avatar higumachan avatar juandgirald avatar maksimburnin avatar monkbroc avatar moonavw avatar nanjakkun avatar olleolleolle avatar prem-prakash avatar rodinux avatar sanchojaf avatar stephskardal avatar turlockmike avatar waheedi avatar williamherry avatar wowu avatar yovasx2 avatar zaknafain avatar zrisher avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rails_admin_import's Issues

Not able to import

Dear,

I'm not able to import anything.

My Model looks like:
class Client < ActiveRecord::Base
attr_accessible :co1, :co1, :name
end

I've added this to my rails admin file
RailsAdminImport.config do |config|
config.model Client do
# excluded_fields do
# [:field1, :field2, :field3]
# end
# label "test"
# extra_fields do
# [:name, :co1]
# end
end
end

My Download file looks like this:
image

My Upload settings look like this:
image

My Upload file looks like this:
image

The output I receive is looking like this:
image

That's unfortunately wrong, I will appreciate your help.

Kind regards

Gemfil

Hello.

I have added the line into my Gemfile as in the guide but running bundle install I get the following error. Is this a known issue?

bundle install
Fetching git://github.com/stephskardal/demo.git
fatal: remote error:
Repository not found.

conflict with same column name and association name

Hi!

I have a model with email column and with has_many :emails association.

# == Schema Information
#
# Table name: users
#
#  id              :integer          not null, primary key
#  email        :string

class User < ActiveRecord::Base
  has_many :emails
end

I am getting this error when I try to import and assigned value to email field.

  Failed to create John Smith: Association not found. Email.id = [email protected]

Data associations in multi-tenant systems

Let's say you have an online shopping mall with multiple stores (https://github.com/influitive/apartment). Email must be unique w/in store but there could be duplicate emails in the Users table (unique validation on email and store_id). You also can add custom validations so user and purchase must belong to the same store.

On uploading Purchases to specify User relationship you can't just use email address. You must specify both email and store so it can find the right record in the User table. Any suggestions on how to do that?

Here are the basic models:

class Store
  include Mongoid::Document
  has_many :purchases
  has_many :users
end
class User
  include Mongoid::Document
  field :email
  belongs_to :store
  has_many :purchases
end
class Purchase
  include Mongoid::Document
  belongs_to :store
  belongs_to :user
end

Relation Detection

I have very related models but i'll use rails_admin_import for a model and i want to ignore it's relation can i do that ?

Error on trying to resolve polymorhic fields

When a model has polymorphic fields (e.g., devise's User invited_by), we get a crash trying to generate the select list for mapping.

I was using the RailsApps template for https://github.com/RailsApps/rails3-devise-rspec-cucumber as set up for the tutorial, except for Devise where I selected "Devise with Confirmable and Invitable modules"

I have never forked a project on github and I probably do not know enough to properly resolve this isssue anyway. However, so I could at least keep it from crashing I hacked my local copy of:

/home/vagrant/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/rails_admin_import-6c3946f1afb0/app/views/rails_admin/main/import.html.erb

At line 94 I added a simple begin/rescue/end to trap the error condition.

Here is the code I used:

<select name="<%= field %>">
<% begin -%>
  <% field.to_s.classify.constantize.new.attributes.keys.each do |key| -%>
    <option value="<%= key %>"><%= key %></option>
  <% end -%>
<% rescue -%>
  <option value="">Unable to resolve: <%= field -%></option>
<% end -%>
</select>

Thanks for putting this up on github!

Using associated fields as mapping_keys

I would like to update a record in mapping table using combination of two associated fields. The problem is Importer.find_or_create_object fires before import_single_association_data. So the query used to lookup record does not have proper user_id or role_id values yet. I've been stuck on this for days and was wondering if anyone encountered similar situations?

Sample models and data:

class User
  mapping_key :email  # unique
end
class Role
  mapping_key :name # unique
end
class UserRole
  # also has notes field that I want to update
  validates :user, uniqueness: {scope: :role}  
  mapping_key_list [:user, :role]        
end

CSV:
user,role,notes
[email protected],admin,updated notes here

Rails 3.2 compatibility

Are you aware of any specific reason that this may not work with Rails 3.2? I would like to try it but the gemspec restricts me to ~> 3.1.3.

RailsAdmin with Mongoid::Attributes::Dynamic

MongoDB and Mongoid support dynamic attributes allowing to store document with flexible schema. It would be an interesting feature to allow import of such documents.

Model:

class User
  include Mongoid::Document
  include Mongoid::Attributes::Dynamic
  field :name, type: String
end

CSV import. You would need different spreadsheets with different sets of dynamic attributes

name,age,hair_color
bob,30,red

Data in MongoDB:

{ 
    "_id" : ObjectId("56cf7a66f5740c6026273857"), 
    "name" : "Bob", 
    "age" : "30"
    "hair_color" : "red"
}

Import breaks sequences of ids.

If we set lookup by id and try to import records it will create new record with id that we set in import file. It ignores sequences of ids in database.
That will lead to 'ERROR: duplicate key value violates unique constraint' in future.

Integration with ActiveJob

Does anyone have experience integrating rails_admin_import with ActiveJob (DJ, Sidekiq, etc)? Does the gem support it?
Some of the files I am importing are quite large. The workflow I am thinking of is that on file upload it will queue up the job and email spreadsheet with results on completion.

Nomethod set_permalink

I get this error in the Model code. Is it a bug?

NoMethodError in RailsAdmin::MainController#import

undefined method `set_permalink' for #Food:0x007f88100d91f8
Rails.root: /Users/gugguson/rubys/foodoit4

Application Trace | Framework Trace | Full Trace
app/models/food.rb:32:in `before_import_save'

Import from RSS

Just curious if anybody else needs/is interested in importing data from an RSS feed. It's a function I'm tacking on.

But it sure would be nice to expand the the range of inputs. Currently, you can only import CSV files, but the export action can export to json and xml. And another idea: instead of uploading a file, why not a url? The import function should accept an uploaded file or a url and of many more types: xml, json, rss, yml, etc.

undefined method `excluded_fields' for #<RailsAdmin::Config::Sections::Base:0x007ffc830adc50>

I get the same error for "included_fields".

Everything else works like a charm so far :)

Below is my exact code. I want to exclude the updated_by_id/created_by_id fields since they didn't work for import as they point to AdminUser model. Only relations according to the Rails convention worked for me (named as the relational model). Or is there another way to do this?

    RailsAdmin.config do |config|
     config.model Encodement do

        included_fields do
          [:unique_name, :model_type, :name]
        end
        excluded_fields do
          [:updated_by_id, :created_by_id]
        end
       label :name
        # extra_fields do
        #   [:field3, :field4, :field5]
        # end
      end
    end

Thanks for any input!!

Specifying default values on import via UI

I could set them in model but then it will apply to everything. Or I could just modify the spreadsheet. But it would be nice to have a section in UI in Fields to import to set default value. Could be for both Model fields or Association fields.

Mongoid support

rails_admin supports both ActiveRecord and Mongoid.

I'm not sure if this is the only place that causes a problem, but the following is in import.rb and causes load problems with a Mongoid only rails setup.

class ActiveRecord::Base
  include RailsAdminImport::Import
end

Upload progress bar

Any ideas on how we could show some kind of progress bar to users (especially if they are uploading thousands of records)?

Not a Pri 1 feature but would be nice. I am totally stumped on how to do it so open to suggestions.

Check for empty columns

If I import a CSV file with an empty column, I'll receive this error:

MethodError: private method 'select' called for Nil:NilClass in rails_admin_import/lib/rails_admin_import/importer.rb line 171

It would be better to receive this error:

ImportError: Empty columns not allowed

Or better yet, this gem could ignore the empty column and simply proceed normally without it.

1000 lines limit

Why is there a limit for a 1000 lines per upload? Is it safe to change it?

ActiveSessionConnection Error?

Hey guys-

Trying to get this set up โ€” i'm using Rails Admin to support an API, so there's no Devise installed etc, and i use basic auth to prevent access to the admin tool.

Attempting to open the importer gives the following:

Completed 500 Internal Server Error in 407ms

NameError - uninitialized constant ActiveSessionConnection:
  (gem) activesupport-3.2.13/lib/active_support/inflector/methods.rb:230:in `block in constantize'
  (gem) activesupport-3.2.13/lib/active_support/inflector/methods.rb:229:in `each'
  (gem) activesupport-3.2.13/lib/active_support/inflector/methods.rb:229:in `constantize'
  (gem) activesupport-3.2.13/lib/active_support/core_ext/string/inflections.rb:54:in `constantize'
  /Users/xx/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails_admin_import-90f967a3700f/app/views/rails_admin/main/import.html.erb:94:in `block (2 levels) in ___sers_xx__rvm_gems_ruby_______p__bundler_gems_rails_admin_import___f___a____f_app_views_rails_admin_main_import_html_erb__4268958966205294772_70336714390280'
  /Users/xx/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails_admin_import-90f967a3700f/app/views/rails_admin/main/import.html.erb:90:in `each'
  /Users/xx/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails_admin_import-90f967a3700f/app/views/rails_admin/main/import.html.erb:90:in `block in ___sers_xx__rvm_gems_ruby_______p__bundler_gems_rails_admin_import___f___a____f_app_views_rails_admin_main_import_html_erb__4268958966205294772_70336714390280'
  (gem) actionpack-3.2.13/lib/action_view/helpers/capture_helper.rb:40:in `block in capture'
  (gem) actionpack-3.2.13/lib/action_view/helpers/capture_helper.rb:187:in `with_output_buffer'
  (gem) haml-4.0.1/lib/haml/helpers/action_view_xss_mods.rb:5:in `with_output_buffer_with_haml_xss'
  (gem) actionpack-3.2.13/lib/action_view/helpers/capture_helper.rb:40:in `capture'
  (gem) haml-4.0.1/lib/haml/helpers/action_view_mods.rb:59:in `capture_with_haml'
  (gem) actionpack-3.2.13/lib/action_view/helpers/form_tag_helper.rb:663:in `form_tag_in_block'
  (gem) actionpack-3.2.13/lib/action_view/helpers/form_tag_helper.rb:70:in `form_tag'
  (gem) haml-4.0.1/lib/haml/helpers/action_view_mods.rb:132:in `form_tag_with_haml'
  (gem) haml-4.0.1/lib/haml/helpers/action_view_xss_mods.rb:18:in `form_tag_with_haml_xss'
  /Users/xx/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails_admin_import-90f967a3700f/app/views/rails_admin/main/import.html.erb:78:in `___sers_xx__rvm_gems_ruby_______p__bundler_gems_rails_admin_import___f___a____f_app_views_rails_admin_main_import_html_erb__4268958966205294772_70336714390280'
  (gem) actionpack-3.2.13/lib/action_view/template.rb:145:in `block in render'
  (gem) activesupport-3.2.13/lib/active_support/notifications.rb:123:in `block in instrument'
  (gem) activesupport-3.2.13/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  (gem) activesupport-3.2.13/lib/active_support/notifications.rb:123:in `instrument'
  (gem) actionpack-3.2.13/lib/action_view/template.rb:143:in `render'
  (gem) actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:47:in `block (2 levels) in render_template'
  (gem) actionpack-3.2.13/lib/action_view/renderer/abstract_renderer.rb:38:in `block in instrument'
  (gem) activesupport-3.2.13/lib/active_support/notifications.rb:123:in `block in instrument'
  (gem) activesupport-3.2.13/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  (gem) activesupport-3.2.13/lib/active_support/notifications.rb:123:in `instrument'
  (gem) actionpack-3.2.13/lib/action_view/renderer/abstract_renderer.rb:38:in `instrument'
  (gem) actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:46:in `block in render_template'
  (gem) actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:54:in `render_with_layout'
  (gem) actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:45:in `render_template'
  (gem) actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:18:in `render'
  (gem) actionpack-3.2.13/lib/action_view/renderer/renderer.rb:36:in `render_template'
  (gem) actionpack-3.2.13/lib/action_view/renderer/renderer.rb:17:in `render'
  (gem) actionpack-3.2.13/lib/abstract_controller/rendering.rb:110:in `_render_template'
  (gem) actionpack-3.2.13/lib/action_controller/metal/streaming.rb:225:in `_render_template'
  (gem) actionpack-3.2.13/lib/abstract_controller/rendering.rb:103:in `render_to_body'
  (gem) actionpack-3.2.13/lib/action_controller/metal/renderers.rb:28:in `render_to_body'
  (gem) actionpack-3.2.13/lib/action_controller/metal/compatibility.rb:50:in `render_to_body'
  (gem) actionpack-3.2.13/lib/abstract_controller/rendering.rb:88:in `render'
  (gem) actionpack-3.2.13/lib/action_controller/metal/rendering.rb:16:in `render'
  (gem) actionpack-3.2.13/lib/action_controller/metal/instrumentation.rb:40:in `block (2 levels) in render'
  (gem) activesupport-3.2.13/lib/active_support/core_ext/benchmark.rb:5:in `block in ms'
  /Users/xx/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/benchmark.rb:296:in `realtime'
  (gem) activesupport-3.2.13/lib/active_support/core_ext/benchmark.rb:5:in `ms'
  (gem) actionpack-3.2.13/lib/action_controller/metal/instrumentation.rb:40:in `block in render'
  (gem) actionpack-3.2.13/lib/action_controller/metal/instrumentation.rb:83:in `cleanup_view_runtime'
  (gem) activerecord-3.2.13/lib/active_record/railties/controller_runtime.rb:24:in `cleanup_view_runtime'
  (gem) actionpack-3.2.13/lib/action_controller/metal/instrumentation.rb:39:in `render'
  (gem) remotipart-1.0.5/lib/remotipart/render_overrides.rb:14:in `render_with_remotipart'
  /Users/xx/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails_admin_import-90f967a3700f/lib/rails_admin_import.rb:47:in `block (2 levels) in <class:Import>'
  (eval):8:in `instance_eval'
  (eval):8:in `import'

Anyone seen this? How can I get around this, or use the same auth method I'm using in rails admin?

Example documentation on importing associations?

Is there any documentation that lays out an example of importing records with associations? I see we're supposed to select and use a "mapping key", but if I include a column in the file with the name format

"#{associated_model_name}_#{mapping_field_name}"

it doesn't seem to be picked up. For example, when importing a Service that belongs to a User, I'm placing the service.user.email in a column named user_email, similar to ActiveRecord's nested attributes syntax. But it's silently ignored.

I feel like this is something I could easily accomplish if I could read one example, but I can't find any. At this point I have to look through the code to figure out usage.

Can't import value that belongs to another class.

My status_record.rb in models file is this:

class StatusRecord < ActiveRecord::Base
extend Enumerize
  attr_accessible :absence_reason, :absence_time, :beginning, :end, :memo, :status, :student_list_id

  belongs_to :student_list
  enumerize :absence_time, in: [:halfyear, :oneyear, :other], default: :halfyear
end

and the csv file I import is like this:

 id,status,absence_time,beginning,end,absence_reason,memo,student_list_id
 1,rest,halfyear,2013-07-04,2014-01-04,sick,test_data,19191919

All value from id to memo successfully imported but the student_list_id didn't work.
It belongs to another class and I could't find a way to solve this problem.

Anyone can give me some advice?

Cannot update existing model based on model's id

ID's are included in the default excluded fields, so this looks to be expected behavior (though I couldn't find context behind that being added). It seems to follow that if you can update a model on import using other fields (which can be unreliable as they can match to multiple instances of a model and find_by used here will simply return the first) and match to associations using ids, you should be able to update based on the model's id.

In my testing, removing the :id, :_id from the array linked above worked for updating. However I think some logic would have to be added for removing these keys when creating to avoid potential issues (maybe by removing the id from field_names here).

Optionally disabling model validations on import

My models have many validations (which I normally need). However, when I am loading data via RA Import I sometimes do not need to enforce them.

It could be a useful feature to allow user to explicitly select a checkbox to disable validations just for this one upload (with appropriate text warning). Assuming the biz user knows what he/she is doing.

Create associated objects on import

Is there a way to have the import create new records for associated fields? For example if I update some record and specify a value for an associated field that doesn't exist in the database, I want it to create a new record with that value.
Is this possible? If not, would you consider adding this functionality?

rails 3.2 : bundle does not install

Hi,

I'm very very interrested by this "plugin" but I can't install it using rails 3.2. I have noticed also that the git repo in the readme is not the same as the git adress at the top.

IF I USE THE GIT ADRESS IN THE README

Fetching git://github.com/stephskardal/demo.git
github.com[0: 207.97.227.239]: errno=Connection refused
fatal: unable to connect a socket (Connection refused)
Git error: command git clone 'git://github.com/stephskardal/demo.git' "/home/florian/.rvm/gems/ruby-1.9.3-p0/cache/b undler/git/demo-bc15da634c74ddf6ea92fdc23c6cb2adaf56f6be" --bare --no-hardlinks in directory /home/florian/workspace
/reunir_admin has failed.

OR IF I USE THE TOP GIT ADRESS

Updating git://github.com/stephskardal/rails_admin_import.git
github.com[0: 207.97.227.239]: errno=Connection refused
fatal: unable to connect a socket (Connection refused)
Git error: command git fetch --force --quiet --tags 'git://github.com/stephskardal/rails_admin_import.git' "refs/hea ds/*:refs/heads/*" in directory /home/florian/.rvm/gems/ruby-1.9.3-p0/cache/bundler/git/rails_admin_import-9d3fec8c5
331b38b8fa198f7e821fd279ca1960d has failed.
If this error persists you could try removing the cache directory '/home/florian/.rvm/gems/ruby-1.9.3-p0/cache/bundle
r/git/rails_admin_import-9d3fec8c5331b38b8fa198f7e821fd279ca1960d'

Ofcourse it's probably my mistake but other gits install fine !

a++

Idea to make it faster

The associated_map will load the entire table into memory, this takes a lot of time for large tables.

      associated_map = {}
      self.belongs_to_fields.flatten.each do |field|
        associated_map[field] = field.to_s.classify.constantize.all.inject({}) { |hash, c| hash[c.send(params[field]).to_s] = c.id; hash }
      end

How about using to the below code instead during import and remove associated_map completely

   values << key.to_s.classify.constantize.where(params[key] => row[pos].strip).first_or_create

It will be 10 times faster and maybe 1000 times faster for large tables.

Right? I could have missed something.

trouble configuring to not edit header names

The attributes in the model I am trying to upload to are not lower case underscored. Some examples are.

  • SiteName
  • City
  • Phone

I tried to configure it so the header name isn't transformed at all (the user must provide the exact attribute name):

RailsAdmin.config do |config|
  config.configure_with(:import) do |config|
    config.header_converter = lambda {|attrib| attrib }
  end

  config.actions do
    all
    import
  end
end

When I try to import I'm told I didn't provide a SiteName, City etc. Am I doing this wrong? And of course there is always a possibility the problem lies somewhere else

Forcing id when importing

I have Ids that are set externally in another system, so I'd like to be able to force the id value when it's set in the CSV.
We can't mass assign id field., but we can individually set it:

user = User.new(:name => 'Test')
user.id = 12345
user.save!

or using a block

User.create!(:name => 'Test') do |user|
user.id = 12345
end

Unable to import records with polymorphic associations

Does anyone have experience with this? The relationships are left blank.

Assuming I have the following polymorphic relationships:
class Donation
include Mongoid::Document
field :amount, type: Integer
belongs_to :donor, polymorphic: true
end
class Company
include Mongoid::Document
field :name, type: String
has_many :donations, as: :donor
end
class User
include Mongoid::Document
field :name, type: String
has_many :donations, as: :donor
end

Here is my CSV import file:
amount,donor_id,donor_type
20,123,Company
10,456,User

Custom object_label_method for RailsAdmin config causes imports to error

Import for model that has a custom object_label_method defined in the RailsAdmin.config fails on private method 'custom_label_method' called for #<Model> (ActiveRecord models)

Dug into it a bit more, looks to be coming from the report_success and report_error methods on RailsAdminImport::Importer, which in turn calls the label_for_model(object) which does a public send of the abstract_model.config.object_label_method, while that method is private if/when defined in the config. A custom object_label_method can include associated models as well (as mine did), so changing to send didn't resolve the issue.

I've patched this by simply passing the rails_admin_default_object_label_method instead:

module RailsAdminImport
  class ImportModel
    def label_for_model(object)
      object.public_send(:rails_admin_default_object_label_method)
    end
  end
end

This works for my purposes, not sure the approach you'd like to take - though I'd be happy to PR this if it'd be helpful.

Uploading images via URL during import

Got another question. And the answer might be no. I am using carrierwave-mongoid and RailsAdmin generates nice upload UI. Is it possible to specify URL to image in the upload CSV file for RailsAdminImport? I am trying to use before_import_save hook but it's not working.

Here is a basic model:

class Account
  include Mongoid::Document
  field :name,  type: String
  field :image, type: String
  mount_uploader :image, MyImageUploader
  validates :name, :image, presence: true
end

And CSV:

Name, Image
Some name,http://somewebsite.com/image.jpg

Relations with class_name not working

Awesome gem, thanks for your hard work!

I have a model like this:

class Item < ActiveRecord::Base
  belongs_to :standardized_item, :class_name => 'Item'
  has_many :non_standardized_items, :class_name => 'Item', :foreign_key => 'standardized_item_id'
end

Basically, items can link to one another through a "standardized Item".

When I navigate to admin/item/import I get this error: uninitialized constant StandardizedItem and uninitialized constant NonStandardizedItem.

Is there an easy fix or a workaround?

Thanks

Can't verify CSRF token authenticity even with skip_before_action :verify_authenticity_token

I'm building a ruby API using rails admin, witch is working and rails admin import witch has this problem:

Can't verify CSRF token authenticity.

Tried to deactivate it whit

module Api::V1
class ApiController < ApplicationController
skip_before_action :verify_authenticity_token
...
class ApplicationController < ActionController::API
skip_before_action :verify_authenticity_token

But the result was the same error. Any ideas? Tank you

Also getting this when skip is added:
"status":500,"error":"Internal Server Error"
"exception":"#<ArgumentError: Before process_action callback :verify_authenticity_token has not been defined>"

Hook Problems When Importing Data

I'm trying to create an association where it does not exist before rails_admin_import gem is going to import a record.

It's not creating the association.

def before_import_save(record)
    if Collection.where(title: record[:product_collection]).empty?
      collection = Collection.create!(title: record[:product_collection], site: site)
    end
  end

An image of the error when I upload a file:

captura de pantalla 2016-04-07 a las 11 50 30 p m

What could be happening here?

hide and default import fields like 'update lookup field' and 'update if exists'

I need just one model imported and the import will be done by a user that isn't very technical so I basicaly want to make it bulletproof for this particular model by not letting them change some of the import setting fields like the mapping field (which I realise I can create a default but the user could still change it) and the boolean for update.

I haven't been able to find a way to do this with rails_admin_import - I'm hoping I have I just missed something?

Importing record associations that are related :through another model

I'm trying to import a Service that has_one :user, through: :pro, where :pro is a "role model" that holds information about that particular role a user may fulfill. I have the user's email to uniquely identify it, but I can't get the association to save.

I have:

A standard user model with an email field, which can have various role models attached:

class User < ActiveRecord::Base
  has_one :pro
  has_one :other_role_model
  has_one :some_other_role_model
  ...etc...
end

Various role models that exist for any user that fulfills that role, and holds data corresponding to that role:

class Pro < ActiveRecord::Base
  belongs_to :user
end

class OtherRoleModel < ActiveRecord::Base
  belongs_to :user
end

...etc...

And finally my Service model, which is only tied to users with a Pro role:

class Service < ActiveRecord::Base
  belongs_to :pro
  has_one :user, through: :pro
end

Now I want to import a service which belongs to a particular user via their pro role. The only unique identifier I have for that user/pro is their email, so I want to provide a csv with the format you listed above:

date,description,price,user
2016-02-12T03:21:55Z,Project sample,10000,[email protected]

This will go through fine, but each service's Pro never actually gets set, which means their User is null too.

Looking through the code, it seems like import_single_association_data will try to set service.user = user, given the service it's created and the user that it (successfully) finds. But that never sets the :through association, so service.pro is nil and of course after saving service.user becomes nil because it's accessed through service.pro.

I have a feeling I'm tripping over how ActiveRecord associations work here.

I tried setting the user's email field as a delegate in Pro:

class Pro < ActiveRecord::Base
  belongs_to :user
  delegate :email, to: :user
end

and then changing my import data to

date,description,price,pro
2016-02-12T03:21:55Z,Project sample,10000,[email protected]

But unfortunately I'm unable to select email as the mapping field for pro, even with the above delegation, probably because mapping fields are pulled directly from AR attributes.

I imagine I'm going to just work around this in the before_import_save hook. After changing the import column name to "user_email", I can write:

class Service < ActiveRecord::Base
  belongs_to :pro
  has_one :user, through: :pro

  def before_import_save(record)
    if (email = record[:user_email]) and (user = User.find_by_email(email))
      self.pro = user.pro
    end
  end
end

and it should work. But I'm wondering if there's a cleaner approach that I'm missing.

Configuirable header_converter per model

Often users have different spreadsheet column headers than your model fields. Table has "created_at" but spreadsheet has "Date" or "Created on" column. For associations purchases has "belongs_to: user" but Purchases spreadsheet has "Customer" column.

I am thinking of per model configuration with something like this:

import do
  mapping_key :some_unique_id
  model_header_converter: {
    created_at:  [:date, :created_on],
    user: [:customer, :purchasher],
    ...
  }
end

Any feedback? Is there a callback that can be done before header processing?

Issue with association fields when the class is in a module

Suppose that we have the next classes

class Blog::Post < ActiveRecord::Base
has_many :comments
belongs_to :user
end

class Blog::Comment < ActiveRecord::Base
belongs_to :post, inverse_of: :comments
end

And we want import posts.

the importation fail for the comments field.

I think that in the link below you can found what is the problem. Is not a solution is only for describe better the issues where are.

https://github.com/sanchojaf/rails_admin_import/compare/issue_class_in_module

I did some test adding rails_admin_import to a existing rails_admin demo

the original rails_admin demo is
https://github.com/bbenezech/blog_admin

below the change that I did for add rails_admin_import
https://github.com/sanchojaf/blog_admin/tree/add_import

"Your file must contain a column for the 'Update lookup field' you selected." error

However, the csv file I tried to import did indeed have a column of the same name as the Update lookup field I configured in rails_admin.rb. I modified the error message to output the lookup_field_name, so I can confirm that the expected value matches a column in the csv file. The csv file was generated by the standard rails_admin export action.

Any idea what might be going on here? Are there restrictions on csv files I'm unaware of? I tried to validate the csv file and it seems ok. But my model is pretty complicated- it includes real html and quotes, slashes, etc- and past experience has taught me that there's no real standard way to read or write csv files.

Also, the import crashed with the following error when I tried to import a csv file delimited with a semi-colon or tabs.

CSV::MalformedCSVError in RailsAdmin::MainController#import
Illegal quoting in line 2.

So it seems that rails_admin can't handle some of these csv variations.

Perhaps a better solution is to extend the importer to accept xml, or even better, json files?

Configurable downcasing association fields prior to before_import_save

I am thinking of before_import_associate and after_import_associate callbacks where developer can do custom pre-processing before associations occur. But I wanted to check in and see if anyone had better ideas?

CSV:
amount,user
10,[email protected]

But user.email in the DB is [email protected] so it doesn't find association.

When I do record[:user].downcase in before_import_save it modifies the record, but the association lookup already happened prior to that.

class User
  field :email
  has_many :purchases
  rails_admin do
    import do
      mapping_key :email
    end  
  end
end
class Purchase
  field :amount
  belongs_to :user
  validates :user, presence: true
  def before_import_save(record)
  # this doesn't work as by this point association already failed
  # self.user = User.where(email: record[:user].downcase).first
  end
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.