Rails admin import configuration for polymorphic association

January 21, 2019
Tanzina

Rails admin is a very handy tool when it comes to providing an automatic admin interface for Rails applications. Rails admin is described as a Rails engine that provides an easy-to-use interface for managing your data.

The main features are –

  • CRUD any data
  • Custom actions
  • Automatic form validations
  • Search and filter
  • Export data to CSV/JSON/XML
  • Authentication (Devise)
  • Authorization(CanCanCan, Pundit etc)
  • User action history like activity stream (PaperTrail)
  • Supported ORMs (ActiveRecord, MongoID)

While Rails admin is very useful to manage all the models, we frequently need to insert massive data directly into the tables. In this situation, rails admin import is a plugin that adds the functionality to import CSV, JSON and XLSX files to Rails admin. But while using this plugin, we faced some difficulties to handle the polymorphic associations. That is what this blog is about!

For this purpose, we will create a simple Rails application with ruby version 2.5.3 and rails version 5.2.1.1.

$ rails new upload_songs

We will then move into the project directory and include the gems, namely rails_admin and rails_admin_import.

$ gem 'rails_admin'
$ gem 'rails_admin_import'

Then we will run

$ bundle install

After adding the gem, we need to add some configuration in config/initializers/rails_admin.rb:

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

Then we will create the application models

 $ rails g model Album name:string
$ rails g model Movie name:string
$ rails g model Song name:string
$ rails g model Singer name:string
$ rails g model Lyricist name:string

Now we will create polymorphic association, along with other necessary associations, among the models. We know that with polymorphic association, one model can belong to several other models, using a single association. After this, the model files will look as follows:

In app/models/album.rb:

class Album < ApplicationRecord
has_many :songs, as: :soundable
end

In app/models/movie.rb:

class Movie < ApplicationRecord
has_many :songs, as: :soundable
end

In app/models/song.rb:

class Song < ApplicationRecord
belongs_to :soundable, polymorphic: true
belongs_to :singer
belongs_to :lyricist
end

In app/models/singer.rb:

class Singer < ApplicationRecord
has_many :songs
end

In app/models/lyricist.rb:

class Lyricist < ApplicationRecord
has_many :songs
end

Then we will add a foreign key column and a type column for the Song model as follows in the following file, db/migrate/YYYYMMDDHHMMSS_create_songs.rb:

class CreateSongs < ActiveRecord::Migration[5.2]
  def change
create_table :songs do |t|
t.string :name
t.integer :soundable_id
t.string :soundable_type
t.timestamps
end
end
end

Also we will add the root path in routes.rb to enable the routes regarding rails admin:

mount RailsAdmin::Engine => '/admin', as: 'rails_admin'

Then we will run the migration and afterwards run the server:

$ rails db:migrate
$ rails s

Then if we browse with http://localhost:3000/admin, we will see the following page:

Now in order to import the songs, we will go to the Songs menu link and will see that there is the import option. Using this we can import any file.

Then we will add some records in all the tables. Afterwards, we will try to import songs using an excel file of the following format:

Table of Rails admin import

Other associated objects are mapped with the names and are being associated normally, but not the polymorphic ones.

To handle such complex associations like polymorphic association, we will need custom logic using one of the import hooks, e.g. before_import_save in our model file app/models/song.rb:.

class Song < ApplicationRecord
belongs_to :soundable, polymorphic: true
belongs_to :lyricist
belongs_to :composer
def before_import_save(record)
source = if record[:album_movie_type].eql? 'Album'
Album.find_by_name(record[:album_movie_name])
else
Movie.find_by_name(record[:album_movie_name])
end
self.soundable_id = source.id
self.soundable_type = record[:album_movie_type] end
end

This will solve the issue with polymorphic associations.

References

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.