We’ve had a few projects at Panoptic Development recently that made use of the RailsAdmin gem. Out of the box, RA satisfied about 95% of what we needed to do to complete each project, but there were a few edge requirements that we either had to make do without or find workarounds for. Don’t get me wrong, RA is a wonderful utility for quickly spinning up an administrative area for your Rails app. It’s loaded with really slick bells-and-whistles, and it has an incredibly flexible DSL for configuration. However, there are a few things it just doesn’t seem to be able to handle as-is and for which I’ve searched high and low for solutions for the last 9 months. I’m happy to report that I finally cracked one of these problems, and it wasn’t even all that complicated in the end.
The problem was this: For any given Changeset#model
value, only a few values are valid for the Change#field
attribute. Let’s start with the two models: Changeset
and Change
:
[gist id=82713f9847187b3f2be7 file=changeset.rb]
[gist id=82713f9847187b3f2be7 file=change.rb]
In RailsAdmin lingo, both of the Changeset#model
and Change#field
attributes are presented as enum
fields. Here’s how this looks in RailsAdmin:
Out-of-the-box, you can provide RA with a list of possible values for any given enum field and it will create a <select>
 element with those values as options, then transform it into a combobox widget. When the enum field is part of a nested has_many
association form, the <select>
element and options are drawn once in a hidden “blueprint” <div>
which is then copied for each new associated object you add. In other words, the enum values are evaluated once at runtime, and that’s that. What I needed was for these two enum fields to be linked, with the options available in the select lists of the children to be dependent on the selected value of the select list in the parent, and to do it dynamically.
The first step in solving this was to create a way that we can get a list of valid Change#field
values for a given Changeset#model
:
[gist id=82713f9847187b3f2be7 file=changes_controller.rb]
[gist id=82713f9847187b3f2be7 file=routes.rb]
With that done it was then just a matter of reading through the RA source code, reverse engineering how it implements its filtered select widget and rebuilding the Change#field
 <select>
elements with the new options:
[gist id=82713f9847187b3f2be7 file=ui.coffee]
updateAttributes
accepts one argument, selects
, which defaults to all of the nested Change#field
fields in the form. We setup a couple events so that it will be called anytime either of the two enum fields’ value changes. When it is called it fires off an AJAX request to our new controller method and sets up a promise to to be run if the AJAX request completes successfully. When that happens it iterates over the array of valid field
values that were returned and creates new <option>
tags for each of them. Finally there’s a pretty long chain of function calls that: destroys the existing filteredSelect widget, finds and then removes all of the current <option>
tags in the select except for the first one (it’s an empty option), appends the new <option>
elements, creates a new filteredSelect widget (which picks up the new options), and sets the selected value to whatever was selected before.
The two change event triggers handle a couple different scenarios. The first case is if the Changeset#model
field changes, in which case we update all existing nested Change#field
<select>
elements. The second case is when RA’s custom nested:fieldAdded
event is triggered after a new nested association fieldset is generated (i.e. after the “Add a new Changed Field” button is pressed), and we update only that new Change#field
field.
Perhaps this could be spun off into a new custom field type for RailsAdmin at some point. For now, I’m just happy it works for this particular project.
Hello Christopher,
I have a doubt in my project have 3 models, which relate, which are sales, sales_product and product, the model sales_product have a valor_unitario field, and the valor_unitario I want to receive already in the product model. how do this in rails admin?
Hi Denys, thanks for taking the time to read and comment. Rails Admin has the ability to nest forms for associations. It sounds to me like your setup is a `has_many :through` association. I suggest you checkout the following pages in the RA wiki: Associations basics and Has-many :through association
Hello Christopher,
just wanted to give you huge kudos for posting this. Being new to rails_admin, these kind of things can even halt the development process and while reading RA source code is immensely helpful, sometimes it's not enough and input from other developers like this article is just invaluable. Thank you!
Glad you found it useful, Dmitry!