Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an object of a STI subclass using ActiveAdmin

Given the following setup(which is not working currently)

class Employee < ActiveRecord::Base
end

class Manager < Employee
end

ActiveAdmin.register Employee do
  form do |f|
    f.input :name
    f.input :joining_date
    f.input :salary
    f.input :type, as: select, collection: Employee.descendants.map(&:name)
  end
end

I would like to have a single "new" form for all employees and be able to select the STI type of the employee in the form. I am able to see the select box for "type" as intended but when I hit the "Create" button, I get the following error:

ActiveModel::MassAssignmentSecurity::Error in Admin::EmployeesController#create

Can't mass-assign protected attributes: type

Now, I am aware of the way protected attributes work in Rails and I have a couple of workarounds such as defining Employee.attributes_protected_by_default but that is lowering the security and too hack-y.

I want to be able to do this using some feature in ActiveAdmin but I can't find one. I do not want to have to create a custom controller action as the example I showed is highly simplified and contrived.

I wish that somehow the controller generated by ActiveAdmin would identify type and do Manager.create instead of Employee.create

Does anyone know a workaround?

like image 944
Sahil Avatar asked Dec 26 '22 21:12

Sahil


2 Answers

You can customize the controller yourself. Read ActiveAdmin Doc on Customizing Controllers. Here is a quick example:

controller do
  alias_method :create_user, :create
  def create
    # do what you need to here
    # then call create_user alias
    # which calls the original create
    create_user
    # or do the create yourself and don't
    # call create_user
  end
end
like image 91
sorens Avatar answered Jan 13 '23 15:01

sorens


Newer versions of the inherited_resources gem have a BaseHelpers module. You can override its methods to change how the model is altered, while still maintaining all of the surrounding controller code. It's a little cleaner than alias_method, and they have hooks for all the standard REST actions:

controller do
  # overrides InheritedResources::BaseHelpers#create_resource
  def create_resource(object)
    object.do_some_cool_stuff_and_save
  end

  # overrides InheritedResources::BaseHelpers#destroy_resource
  def destroy_resource(object)
    object.soft_delete
  end
end
like image 37
Anthony Wang Avatar answered Jan 13 '23 14:01

Anthony Wang