I am a Sr. Software Developer at Oracle Cloud. The opinions expressed here are my own and not necessarily those of my employer.
Cloning records in Rails
Sometimes we need to enable our users to clone their records instead of creating new ones from scratch (huge time saver). Let’s imagine a system where users have many accounts.
# app/models/user.rb
class User
has_many :accounts
end
# app/models/account.rb
class Account
belongs_to :user
field :name
end
Clone one record
ActiveRecord and Mongoid have clone
method which we can wrap like this.
# app/models/account.rb
def clone_record
new_record = self.clone
new_record.name = "#{name} CLONE"
new_record.created_at = Time.now
new_record.updated_at = Time.now
...
new_record.save!
return new_record
end
We can add more logic to clone_record
to ensure uniqueness or transform data as needed. For basic CRUD UI I like using RailsAdmin. We can create custom action to call clone_record
method.
# config/initializers/rails_admin.rb
module RailsAdmin
module Config
module Actions
class Clone < RailsAdmin::Config::Actions::Base
RailsAdmin::Config::Actions.register(self)
register_instance_option :member do true end
register_instance_option :only do [Account] end
register_instance_option :link_icon do 'fa fa-clone' end
register_instance_option :http_methods do [:get, :post] end
register_instance_option :controller do
proc do
if request.post?
new_obj = @object.clone_record
flash[:notice] = "Cloned #{@object.name}."
redirect_to show_path(id: new_obj.id)
end
end
end
end
end
end
end
RailsAdmin.config do |config|
config.actions do
dashboard
...
clone
end
end
# config/locales/en.yml
en:
admin:
actions:
clone:
title: 'Clone title'
menu: 'Clone menu'
breadcrumb: 'Clone breadcrumb'
# app/views/rails_admin/main/clone.html.erb
<h3><%= "Are you sure you want to clone '#{@object.name}'" %></h3>
<%= link_to 'Clone', clone_path, method: 'post', class: "btn btn-danger" %>
<%= link_to 'Cancel', show_path, class: "btn" %>
Making GET
request will load the clone
page where user can confirm or cancel the action. This can be extended to cloning other records in the system. Just create clone_record
method in the respective classes and add class name to register_instance_option :only do ...
.
Clone multiple records
We also might want to clone multiple records at a time. RailsAdmin supports bulk actions such as bulk_delete.
# config/initializers/rails_admin.rb
module RailsAdmin
module Config
module Actions
class BulkClone < RailsAdmin::Config::Actions::Base
RailsAdmin::Config::Actions.register(self)
register_instance_option :collection do true end
register_instance_option :bulkable? do true end
register_instance_option :only do [Account] end
register_instance_option :http_methods do [:post, :get] end
register_instance_option :controller do
proc do
if request.post?
# loads the preview page
@objects = list_entries(@model_config, :post)
render @action.template_name
elsif request.get?
@objects = list_entries(@model_config, :get)
@objects.each do |object|
object.clone_record
end
flash[:success] = "#{@model_config.label} successfully cloned."
redirect_to back_or_index
end
end
end
end
...
end
end
end
RailsAdmin.config do |config|
config.actions do
dashboard
...
clone
bulk_clone
end
end
# config/locales/en.yml
...
# app/views/rails_admin/main/bulk_clone.html.erb
...
The differences from before are register_instance_option :collection do true end
and register_instance_option :bulkable? do true end
. Also there is bulk_clone
UI page.
You can configure UI labels following this pattern. And here is bulk_delete template. Big thanks to this post for guidance on how to do custom bulk actions.