title: RSpec controller tests of PUT update action on nested resource
body: <p>I'm learning Rails and how to test using RSpec.  I need help completing an RSpec controller test of the PUT update action. The controller directs a nested resource.  The nested route and related program code work as expected in a web browser. I only need help writing the RSpec test for the PUT update action.  I have passing tests of the other actions performed by the controller.  </p>
  
  <p>I know that the path and both parent and child ids must be passed to the put method, but I'm confused about the following:  (1) how to properly set up the PUT update test using FactoryGirl objects, and (2) the proper RSpec syntax to pass the path and ids into the PUT method.</p>
  
  <p>The relevant routes from rake routes:</p>
  
  <pre><code>  PATCH  /members/:member_id/cardio_exercises/:id(.:format)      cardio_exercises#update
    PUT    /members/:member_id/cardio_exercises/:id(.:format)      cardio_exercises#update
  </code></pre>
  
  <p>routes.rb contains:
        resources :members do
          resources :cardio_exercises
        end</p>
  
  <p>members.rb contains:
        has_many :cardio_exercises, :dependent => :destroy</p>
  
  <p>cardio_exercises.rb contains:
        belongs_to :member</p>
  
  <p>The relevant factories:</p>
  
  <pre><code>FactoryGirl.define do
   factory :cardio_exercise do
     title "My cardio exercise"
     duration 30
     calories_burned 300
     date "2014-11-15"       
     association :member     
   end
  end
  
  
  FactoryGirl.define do
    factory :member do
      first_name {Faker::Name.first_name}
      last_name {Faker::Name.last_name}
      age 21
      height 75
      weight 195
      goal "fffff" * 5
      start_date "2014-11-15"     
    end
  end
  </code></pre>
  
  <p>The cardio_exercises_controller.rb</p>
  
  <pre><code>class CardioExercisesController &lt; ApplicationController
  
  # :get_member is defined in the private method at the bottom of this file,
  # and takes the member_id provided by the routing and
  #converts it to a @member object.
  
  before_action :get_member    
  
  # GET member/1/cardio_exercises
  # GET member/1/cardio_exercises.json
  def index
  @cardio_exercises = @member.cardio_exercises
  end
  
  # GET member/1/cardio_exercises/1
  # GET member/1/cardio_exercises/1.json
  def show
   cardio_exercise = @member.cardio_exercises.find(params[:id])
  end
  
  # GET member/1/cardio_exercises/new
  def new
    @member = Member.find(params[:member_id])
    @cardio_exercise = @member.cardio_exercises.build
  end
  
  # GET member/1/cardio_exercises/1/edit
  def edit
  @cardio_exercise = @member.cardio_exercises.find(params[:id])
  end
  
  # POST member/1/cardio_exercises
  # POST member/1/cardio_exercises.json
  def create
  @cardio_exercise = @member.cardio_exercises.build(cardio_exercise_params)
  
  if @cardio_exercise.save
  flash[:success] = "Cardio exercise was successfully created."
  redirect_to member_cardio_exercises_path(@member)
  else
  render 'new'
  end
  end  
  
  # PATCH/PUT member/1/cardio_exercises/1
  # PATCH/PUT member/1/cardio_exercises/1.json
  def update
   @cardio_exercise = @member.cardio_exercises.find(params[:id])
    if @cardio_exercise.update(cardio_exercise_params)
    flash[:success] = "Cardio exercise was successfully updated."
    redirect_to member_cardio_exercises_path(@member)
  else
  render 'edit'
  end
  end
  
  # DELETE member/1/cardio_exercises/1
  # DELETE member/1/cardio_exercises/1.json
  def destroy
  @cardio_exercise = @member.cardio_exercises.find(params[:id])
  @cardio_exercise.destroy
  respond_to do |format|
  format.html { redirect_to (member_cardio_exercises_path(@member)), notice: 'Cardio exercise was    successfully destroyed.' }
  format.json { head :no_content }
  end
  end
  
  private
  # The get_member action converts the member_id given by the routing
  # into an @member object, for use here and in the view.
  
  def get_member
  @member = Member.find(params[:member_id])
  end
  
  
  def cardio_exercise_params
  params.require(:cardio_exercise).permit(:title, :duration, :calories_burned, :date, :member_id)
  end
  end
  </code></pre>
  
  <p>The cardio_exercises_controller_spec.rb and my attempt to set up several tests of the PUT update action:</p>
  
  <pre><code>require 'rails_helper'
  
  RSpec.describe CardioExercisesController, :type =&gt; :controller do
    before :each do
      @member = FactoryGirl.create(:member)      
      @cardio_exercise = FactoryGirl.create(:cardio_exercise, member: @member)      
      @cardio_exercise_attributes = FactoryGirl.attributes_for(:cardio_exercise, :member_id =&gt; @member)
      @cardio_exercise_update_attributes = FactoryGirl.attributes_for(:cardio_exercise, :title =&gt; "Your Cardio Exercise", :member_id =&gt; @member)
    end
  
  describe "GET index" do
  it "assigns all cardio_exercises as @member.cardio_exercises" do
    get :index, { :member_id =&gt; @member  }
    expect(assigns(:cardio_exercises)).to eq(@member.reload.cardio_exercises)
  end
  end
  
  describe "GET show" do
  it "assigns the requested cardio_exercise as @cardio_exercise" do
    get :show, { :member_id =&gt; @member, :id =&gt; @cardio_exercise }    
    expect(assigns(:cardio_exercise)).to eq(@cardio_exercise)  
  end
  end 
  
  describe "GET new" do
   it "assigns a new cardio_exercise as @member.cardio_exercise" do
    get :new, { :member_id =&gt; @member }
    expect(assigns(:cardio_exercise)).to be_a_new(CardioExercise)
  end
  end
  
   describe "GET edit" do
    it "assigns the requested cardio_exercise as @member.cardio_exercise" do      
    get :edit, { :member_id =&gt; @member, :id =&gt; @cardio_exercise }
    expect(assigns(:cardio_exercise)).to eq(@cardio_exercise) 
   end
  end
  
  describe "POST create" do
    describe "with valid params" do
    it "creates a new CardioExercise" do        
      expect {          
        post :create, { :member_id =&gt; @member, :cardio_exercise =&gt; @cardio_exercise_attributes }
      }.to change(CardioExercise, :count).by(1)         
    end
  
    it "assigns a newly created cardio_exercise as @cardio_exercise" do
      post :create, { :member_id =&gt; @member, :cardio_exercise =&gt; @cardio_exercise_attributes }        
      expect(assigns(:cardio_exercise)).to be_a(CardioExercise)
      expect(assigns(:cardio_exercise)).to be_persisted
    end
  
    it "redirects to the created cardio_exercise" do
      post :create, { :member_id =&gt; @member, :cardio_exercise =&gt; @cardio_exercise_attributes }
      expect(response).to redirect_to(member_cardio_exercises_path(@member))
    end
    end
   end
  
   describe "PUT update" do
    describe "with valid params" do
  
    it "updates the requested cardio_exercise" do
      put :update, { :member_id =&gt; @member, :id =&gt; @cardio_exercise_update_attributes }
      @member.cardio_exercise.reload                      
      put :update, { :member_id =&gt; @member, :id =&gt; @cardio_exercise_update_attributes}
  
    end
  
    it "assigns the requested cardio_exercise as @member.cardio_exercise" do
      put :update, { :member_id =&gt; @member, :cardio_exercise =&gt; @cardio_exercise_update_attributes = FactoryGirl.attributes_for(:cardio_exercise, :title =&gt; "Your Cardio Exercise", :member_id =&gt; @member)}
      expect(assigns(:cardio_exercises)).to eq(@member.cardio_exercises)
    end
  
    it "redirects to the cardio_exercise" do 
      put :update, { :member_id =&gt; @member, :id =&gt; @cardio_exercise }        
      expect(response).to redirect_to(@member.cardio_exercise)
    end
   end
  
   describe "with invalid params" do
    xit "assigns the cardio_exercise as @member.cardio_exercise" do
  
    end
  
    xit "re-renders the 'edit' template" do
  
      expect(response).to render_template("edit")
    end
   end
  end
  
  describe "DELETE destroy" do
    it "destroys the requested cardio_exercise" do
    expect {
      delete :destroy, { :member_id =&gt; @member, :id =&gt; @cardio_exercise }
    }.to change(CardioExercise, :count).by(-1)
    end
  
    it "redirects to the cardio_exercises list" do      
    delete :destroy, { :member_id =&gt; @member, :id =&gt; @cardio_exercise }
    expect(response).to redirect_to(member_cardio_exercises_url)
    end
  end
  end
  </code></pre>
  
  <p>Please review my test set-up and the PUT update tests. Specifically, is my set-up the correct way to test the PUT update action?</p>
  
  <p>How do I change the set-up and/or tests of the controller's update action so that:</p>
  
  <p>(1) my tests match my routes for the update action?</p>
  
  <p>(2) I pass the necessary parent and child ids in the correct RSpec syntax so records can be found? </p>
  
  <p>I appreciate any help!</p>