cocoon: missing resource in complex nesting

I am sorry to file this as an issue but due to the lack of a forum I don’t know where to ask for help. Apologies!

I have a complex data model to implement and have made great strides with cocoon to dynamically add child resource forms to my parent form.

I have the following data model to implement as designed by a database person:

A party has many contact_mechansims through party_contact_mechanisms:

class Party < ActiveRecord::Base
  has_many :party_contact_mechanisms
  has_many :contact_mechanisms, -> { uniq }, through: :party_contact_mechanisms
end

And contact_mechanisms has many parties through party_contact_mechanisms has itself only a contact_mechanism_type_id and can either have a postal_address, an electronic_address, or an telecommunications_number. I have implemented the latters as has_many as using cocoon with has_one gave me trouble before… I validate the contact_mechanism_id in the three of them as unique and disable the links using javascript after adding the first one. Hints for a better solution are welcome btw.

class ContactMechanism < ActiveRecord::Base

  belongs_to :contact_mechanism_type
  has_many :postal_addresses
  has_many :electronic_addresses
  has_many :telecommunications_numbers

  has_many :party_contact_mechanisms
  has_many :parties, -> { uniq }, through: :party_contact_mechanisms

end

In my parties_controller i have this to allow the nested values to be assigned:

def party_params
      params.require(:party).permit(party_contact_mechanisms_attributes: [
                                                      :party_id,
                                                      :contact_mechanism_id,
                                                      :thru_date,
                                                      :from_date,
                                                      :party_contact_mechanism_seq_id,
                                                      :non_solicitation_ind,
                                                      :extension,
                                                      :comment,
                                                      :party_role_type_id,
                                                      contact_mechanisms_attributes: [:id, :_destroy, :contact_mechanism_type_id,
                                                      electronic_addresses_attributes: [ :id, :_destroy, :electronic_address_string, :contact_mechanism_id],
                                                      telecommunications_numbers_attributes: [ :id, :_destroy, :country_code, :area_code, :contact_number,  :contact_mechanism_id],
                                                      postal_addresses_attributes: [ :id, :_destroy, :address1, :address2, :address3, :contact_mechanism_id ]
                                                      ]
                                                      ])
end

My problem is the following. I can dynamically add to my party#new form a form for a new party_contact_mechanism.

= f.simple_fields_for :party_contact_mechanisms do |cm|
    = render 'party_contact_mechanism_fields', f: cm
  .links
    = link_to_add_association t('party.link_label.add_party_contact_mechanism'), f, :party_contact_mechanisms

The fields do show and the params hash looks alright as well. What of course I would really like to do is to add either an electronic _address, a postal_address or a telecommunications_number to my party. So I thought I could string all of these together in one call add a new party_contact_mechanims > contact_mechanims > electronic_address for e.g. en email address:

 = link_to_add_association "Email", f, :party_contact_mechanisms,
          {:'data-association-insertion-node' => '#party_contact_mechanisms_email',
          :'data-association-insertion-method' => :append, force_non_association_create: true,
          :partial => 'party_contact_mechanism_email_fields'}

 #party_contact_mechanisms_email
      .js-cocoon.electronic_address
        = f.simple_fields_for :party_contact_mechanisms do |email|
          = render 'party_contact_mechanism_email_fields', :f => email
.nested-fields
  .js-cocoon.party_contact_mechanism
    .js-datepicker
      = f.input :from_date, label: t('party_contact_mechanism.from_date'), as: :string
      = f.input :thru_date, label: t('party_contact_mechanism.thru_date'), as: :string
    =f.simple_fields_for :contact_mechanims do |cm|
    = cm.simple_fields_for :electronic_addresses do |electronic_address|
      = render 'electronic_address_fields', :f => electronic_address

The problem with this approach is, that the instance of contact_mechanism is never created and missing when submitting the form, as I don’t add the conact_mechanims manually using a cocoon link_to_add_association I think. the has submitted looks like this:

party"=>{"party_contact_mechanisms_attributes"=>{"1373638885768"=>{"from_date"=>"", "thru_date"=>"", "contact_mechanisms"=>{"electronic_addresses"=>{"electronic_address_string"=>"test@example.com"}}}}

I there a way to go with this approach? I save one click but the user experience would be so much better if I could as adding a conact_mechanism after already having added a party_contact_mechanism does not make sense to the user I am afraid.

Any help would be greatly appreciated.

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Comments: 21 (9 by maintainers)

Most upvoted comments

Had the same problem and I think I’ve found a workaround for this:

On your link_to_add_association you could use the wrap_object option to build any additional association. If you use fields_for you need a new instance for each of those associations.

For instance, in your case if you want contact_mechanism to appear in the form you must call the helper like this:

# I'm using a helper because code looks messy in the view
def link_to_add_party_contact_mechanism(form)
  wrap_object = proc do |party_contact_mechanism|
    party_contact_mechanism.build_contact_mechanism
    party_contact_mechanism
  end

  link_to_add_association "Add...", form, :party_contact_mechanisms, wrap_object: wrap_object
end

pd: posted on stackoverflow too