When working with large amounts of data and with complex or detailed forms, there is often a need to bulk add new and similar items and trying to remember all the values to be included can be taxing to say the least.
What would be nice is an option on the page to copy an item and be able to edit the details for the specific instance.
This is fairly simple in Rails. The example below is for the applications resource
Create a new route in config/routes.rb
resources :applications do member do get 'copy' => 'applications#create_from_existing' post 'copy' => 'applications#create_from_existing' end end
This will capture any ‘copy’ action requests and forward them to a new ‘create_from_existing’ action in the applications controller. Including GET and POST allows the use of link_to and button_to helpers in the views.
Then, create the ‘create_from_existing’ controller action,
def create_from_existing @existing_app = Application.find(params[:id]) #create new object with attributes of existing record @application = @existing_app.dup render :new end
This simply creates an ActiveRecord duplicate of the item to be copied and renders it with the (already defined) ‘new’ action.
Finally, we create links to the copy action in our views using helpers like,
<%= link_to image_tag("copy-icon.png", :size => "22x17", :title => "Copy item"), copy_application_path %></td> <%= link_to 'copy', copy_application_path(@application) %> <%= button_to 'copy', copy_application_path(@application), :class => "button" %>
The only thing to watch out for when editing the copied item is that the button at the bottom of the form says ‘ Create …’ rather than update; on submission the id of the item being displayed should be that of a new record.
References:
- http://stackoverflow.com/questions/5711446/rails-clone-copy-or-duplicate#comment6529283_5711509 from a google search for ‘rails clone button’.
One point to note here is that has and belongs to many type associations are not included in the copy, but a wee bit of extra work in the controller action should be able to sort that. A follow up post should be able to capture that detail.
In my application, I can simply add something like:
@application.host_ids = @existing_app.host_ids
@application.app_user_ids = @existing_app.app_user_ids
to the controller because I know all the associations I want to capture. I have spent some time looking into reflections with ActiveRecord (using rails c) and while there are a couple of gems to help with this, which I don’t want to use, there doesn’t seem to be much discussion and the documentation isn’t very helpful so I will leave it for now.