Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Admin: has_one association forms broken

When trying to create a new record with a has_one relationship (and all the inverse_of correctly specified), the form is disabled:

enter image description here

The code for this association is as follow:

class Visit < ActiveRecord::Base
  has_one :mri, dependent: :destroy, inverse_of: :visit

  accepts_nested_attributes_for :mri, update_only: true
  ...
end

class Mri < ActiveRecord::Base
  belongs_to :visit, inverse_of: :mri, touch: true
  ...
end

When I remove the whole line with accepts_nested_attributes, I get a missing form, nothing:

No form at all.

Using the rails_admin configuration to disable the nested form, as follow, gives the same result.

config.model Visit do
  edit do
    configure :mri do
      nested_form false
    end
  end
end
like image 511
Antoine Lizée Avatar asked Apr 29 '16 03:04

Antoine Lizée


1 Answers

These problems come from two bugs of Rails Admin, IMO.

It is useful to understand that Rails Admin has two kind of forms for association. One is the classic one (that opens a window for creation) and the other is the "nested_form" that displays the form in the page. The nested_form parameter can be changed directly, as shown in the question above, but is automatically set to true by Rails Admin for associations included in accepts_nested_attributes_for.

The first bug is that accepts_nested_attributes_for: ..., update_only: true get "interpreted" by rails Admin as "I don't want to give parameters at creation". This interpretation seems wrong, since the behavior that update_only changes in rails concerns solely object updates, and doesn't prevent passing nesting parameters at creation. Moreover, I would have expected a fallback to the classic form instead of a completely disabled form.

A quick - and usually detrimental - way to fix this is to change update_only to the default false.

The second bug is more surprising, because 'in your face'. As shown in the wiki, the classic (non nested) association forms for the has_one relations don't get initialized properly if you don't specify yourself the id setters and getters. Thus, if you don't have nested_attributes, you need to include lines as such in your model:

class Visit < ActiveRecord::Base
  has_one :mri, dependent: :destroy, inverse_of: :visit

    def mri_id
    self.mri.try :id
  end

  def mri_id=(id)
    self.mri = Mri.find_by_id(id)
  end

  ...
end

Finally, leveraging our understanding of the first bug gave us the most elegant solution to my initial problem. The source code of the Rails Admin templates show that Rails Admin stores an update_only parameter for the nested_form attribute of the field object. We can directly configure it in order to achieve the desired behavior (that should be the default imo):

config.model Visit do
  edit do
    configure :mri do
      nested_form[:update_only] = false
    end
  end
end

PS: This post is rather long but this simple problem ended up chasing down a rabbit hole, so I wanted to share my findings - I hope it helps. A huge thanks to the RA devs, who provide Rails with one of the most versatile and feature rich admin portal (ever). I've open a couple of gh issues.

like image 87
Antoine Lizée Avatar answered Oct 22 '22 22:10

Antoine Lizée