Nested attributes
Hi All,
I'm working with nested forms and I'm stuck trying to create the two models and the controller to handle this association.
My models following this structure:
Survey -> recipients <- Contacts //Perhaps recipients is not the best name
So what I want to do is to create a Form for survey where you add a list of contacts, if the contact exist create a recipient using this contact and if not create the contact first and then create the recipients.
In the survey model I guess that I have to add:
accepts_nested_attributes_for :recipients
So I can create recipients elements from the survey controller but what I'm not sure is how to define the form and it's controller to handle the case that I want.
Or there is no rails magic and I have to create everything by hand.
Hope that I make sense...
Thanks
Gian
Hey Giancarlo!
You generally have one of two options here:
- A find or create select box which I talked about in an episode. This would let you search through all the existing users which you may not want depending on the application. (https://gorails.com/episodes/select-or-create-with-selectize-js)
- The other option would be to create a form object where you pass in the contacts params and just pre-process it before you save the data. You can loop through the params for those emails the user typed in and if the user exists in the database, use that record. For the ones that you don't find, you can create new recipient records and attach them to your survey.
Option 2 sounds harder than it is. Really you're just looping through like params[:survey][:recipients]
and converting those to records from your database.
Thanks Chris!
This is what I end up doing
class Survey < ApplicationRecord
before_create :set_status
has_many :survey_contacts, :dependent => :destroy
has_many :contacts, through: :recipients, foreign_key: :survey_id
validates_presence_of :name
def contacts_info
end
def contacts_info=(new_contacts)
new_contacts.split(/\r?\n/).each do |new_contact|
name, email = new_contact.split(",")
contact = Contact.find_or_initialize_by(email: email)
contact.name = name
contact.save!
survey_contacts.build(contact:contact)
end
end
So I create a virtual method in the model and use it to process the email that I got from the UI, since this method is call when I do this @survey = Survey.new(survey_params)
this allowed me to create the contacts first and then create the survey with the relationship between survey and contacts.
What do you think Chris? Is there a better way to do this?
My Ideas for this application was that evertime I create a survey I would assign it a list of contacts and use this association later on to save the answers of this person that way I don't need to create extra tables to handle the answers.
That looks pretty much like what I was thinking. 👍
One thing to note is that this will create contacts even if creating the survey fails. A solution to that would be to just build the Contact records instead of saving them. I believe you'd simply remove the contact.save!
from that method to just keep the changes in memory until the survey saves to the database.