Ask A Question

Notifications

You’re not receiving notifications from this thread.

Nested attributes

Giancarlo Corzo asked in Rails

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

Reply

Hey Giancarlo!

You generally have one of two options here:

  1. 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)
  2. 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.

Reply

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.

Reply

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.

Reply

Great

Thanks, I will do the change.

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 81,842+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2024 GoRails, LLC. All rights reserved.