Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RoR nested attributes produces duplicates when edit

I'm trying to follow Ryan Bates RailsCast #196: Nested model form part 1. There're two apparent differences to Ryans version: 1) I'm using built-in scaffolding and not nifty as he's using, and 2) I'm running rails 4 (I don't really know what version Ryans using in his cast, but it's not 4).

So here's what I did

rails new survey2 cd survey2 bundle install rails generate scaffold survey name:string rake db:migrate rails generate model question survey_id:integer content:text rake db:migrate 

Then I added the associations to the models like so

class Question < ActiveRecord::Base   belongs_to :survey end 

and so

class Survey < ActiveRecord::Base   has_many :questions   accepts_nested_attributes_for :questions end 

Then I added the nested view part

<%= form_for(@survey) do |f| %>   <!-- Standard rails 4 view stuff -->    <div class="field">     <%= f.label :name %><br>     <%= f.text_field :name %>   </div>   <div class="field">     <%= f.fields_for :questions do |builder| %>       <div>         <%= builder.label :content, "Question" %><br/>         <%= builder.text_area :content, :rows => 3 %>       </div>     <% end %>   </div>   <div class="actions">     <%= f.submit %>   </div> <% end %> 

and finally the controller so that 3 questions are created whenever a new survey is instantiated

class SurveysController < ApplicationController   before_action :set_survey, only: [:show, :edit, :update, :destroy]    # Standard rails 4 index and show     # GET /surveys/new   def new     @survey = Survey.new     3.times { @survey.questions.build }     Rails.logger.debug("New method executed")   end    # GET /surveys/1/edit   def edit   end    # Standard rails 4 create    # PATCH/PUT /surveys/1   # PATCH/PUT /surveys/1.json   def update     respond_to do |format|       if @survey.update(survey_params)         format.html { redirect_to @survey, notice: 'Survey was successfully updated.' }         format.json { head :no_content }       else         format.html { render action: 'edit' }         format.json { render json: @survey.errors, status: :unprocessable_entity }       end     end   end    # Standard rails 4 destroy    private     # Use callbacks to share common setup or constraints between actions.     def set_survey       @survey = Survey.find(params[:id])     end      # Never trust parameters from the scary internet, only allow the white list through.     def survey_params       params.require(:survey).permit(:name, questions_attributes: [:content])     end end 

So, creating a new survey with three questions is fine. However, if I try to edit one of the surveys, the original three questions are maintained, while an additional three more are created. So instead of having 3 questions for the edited survey, I now have 6. I added

Rails.logger.debug("New method executed") 

to the new method in the controller, and as far as I can tell, it is not executed when I'm doing an edit operation. Can anyone tell me what I'm doing wrong?

Any help is greatly appreciated!

like image 316
conciliator Avatar asked Sep 22 '13 17:09

conciliator


1 Answers

So I figured it out. I had to add :id to the permitted params in the survey_params method. It now looks like this:

# Never trust parameters from the scary internet, only allow the white list through. def survey_params   params.require(:survey).permit(:name, questions_attributes: [:id, :content]) end 

which works perfectly. I'm a RoR newbie, so please take my analysis of this with a grain of salt, but I guess that new id's where generated instead of being passed to the update action. Hope this helps someone else out there.

like image 179
conciliator Avatar answered Sep 18 '22 12:09

conciliator