PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Tuesday, July 26, 2022

[FIXED] How to use fields_for to link multiple models from one form?

 July 26, 2022     activeadmin, belongs-to, has-one, nomethoderror, ruby-on-rails     No comments   

Issue

I am building a registration app. There are three models: Participant, Volunteer_Detail, and Student_Detail. Participant has_one of the other two models, while they in turn belongs_to Participant. I am trying to use one form with fields_for to supply data to Participant and one of the other models.

I keep getting an error, saying that one of the attributes, intended for Student_Detail, is not a defined attribute of Participant.

I have looked at several guides on fields_for and it seems that there are several ways to define the second model your form is intended for.

The consensus seems to be that it should look like this:

         <%= f.fields_for @participant.student_details do |student_detail_field| %>
                    <%= f.label :nationality, 'Nationality:' %> 
                    <%= student_detail_field.text_field :nationality %>

However it only seems to show my form when I write :student_details as opposed to @participant.student_details.

Here is my form, showing the top section, and the section where fields_for is include(form is trimmed to save space):

                    <%= f.label :first_name, 'First:' %>
                    <%= f.text_field :first_name %>

         <%= f.fields_for :student_details do |student_detail_field| %>
                    <%= f.label :nationality, 'Nationality:' %> 
                    <%= student_detail_field.text_field :nationality %>

Here is my Participants controller:

class ParticipantsController < ApplicationController def new @participant= Participant.new end

            def new2
            @participant= Participant.new
            end

            def create
            @participant = Participant.create(participant_params)
            @participant.save
            if @participant.save
            flash[:success] = "Successfully Registered!"        

            #email notifes admin of new registration
            NotifyMailer.notify_email(@participant).deliver_later

            redirect_to '/signup'
            end
            end

            def edit
            end

            def update
            end

            def show
            end

            def index
            end

            private
            def participant_params
            params.require(:participant).permit(:first_name, :last_name, :gender, :email, :birthdate, :phone, :street_name, :city, :state, :zip, :nationality, :religion, :need_ride, 
            :has_spouse, :spouse_name, :english_level, :expectations, :length_of_stay, :exact_length, :volunteer_id, :matched, :returned_home, :participant_id, :participant_id_id)

            end


            end

Here is the server error:

    NoMethodError (undefined method `nationality' for #<Participant:0x000000000d039410>
                            Did you mean?  Rational):

                            app/controllers/participants_controller.rb:11:in `create'
                            Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
                            Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
                            Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (3.9ms)
                            Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
                            Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.0ms)
                            Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
                            Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.0ms)
                            Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (790.6ms)

Looking to see if anyone can help clarify what I'm getting wrong.

Thanks!


Solution

There are couple things that probably can help

  1. How to define has_one relationship:

    Following rails guide, since Participant has_one student_detail, then the student_detail table has to have field participant_id, also volunteer_detail has to have field participant_id

    you can set participant.rb (model) to accept nested attributes for student_detail or volunteer_detail (since you said provide one form for those tables)

    class Participant < ActiveRecord::Base
      has_one :student_detail, :dependent => :destroy
      accepts_nested_attributes_for :student_detail,   :allow_destroy => :true
      # that allow_destroy is depend with your software design
      has_one :volunteer_detail, :dependent => :destroy
      accepts_nested_attributes_for :volunteer_detail,   :allow_destroy => :true
    end
    
  2. How to setup participant_params for other tables:

    Here is sample of code that define participant params for accept nested atributes:

    def participant_params
      params.require(:participant).permit(
        :first_name, :other_participant_field_name, 
        student_detail_attributes: [:participant_id, :other_student_field_name],
        volunteer_detail_attributes: [:participant_id, :other_volunteer_field_name])
      end
    end
    

    If you want the content for student record also for volunteer_detail you can do in your controller (create method), my tip for this try to refactor/redesign to minimize data duplication in your system (student and volunteer)

    def create
      @participant = Participant.create(participant_params)
      @volunteer_detail = @participant.student_detail
      # this will pass all the content of student detail to volunteer detail
      if @participant.save
        flash[:success] = "Successfully Registered!"        
      end
    end
    

To learn more about accept nested attributes I suggest you learn from railcast 196 although it seem old but you can learn the concept



Answered By - widjajayd
Answer Checked By - Candace Johnson (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing