Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec controller tests of PUT update action on nested resource

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.

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.

The relevant routes from rake routes:

  PATCH  /members/:member_id/cardio_exercises/:id(.:format)      cardio_exercises#update
  PUT    /members/:member_id/cardio_exercises/:id(.:format)      cardio_exercises#update

routes.rb contains: resources :members do resources :cardio_exercises end

members.rb contains: has_many :cardio_exercises, :dependent => :destroy

cardio_exercises.rb contains: belongs_to :member

The relevant factories:

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

The cardio_exercises_controller.rb

class CardioExercisesController < 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

The cardio_exercises_controller_spec.rb and my attempt to set up several tests of the PUT update action:

require 'rails_helper'

RSpec.describe CardioExercisesController, :type => :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 => @member)
    @cardio_exercise_update_attributes = FactoryGirl.attributes_for(:cardio_exercise, :title => "Your Cardio Exercise", :member_id => @member)
  end

describe "GET index" do
it "assigns all cardio_exercises as @member.cardio_exercises" do
  get :index, { :member_id => @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 => @member, :id => @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 => @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 => @member, :id => @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 => @member, :cardio_exercise => @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 => @member, :cardio_exercise => @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 => @member, :cardio_exercise => @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 => @member, :id => @cardio_exercise_update_attributes }
    @member.cardio_exercise.reload                      
    put :update, { :member_id => @member, :id => @cardio_exercise_update_attributes}

  end

  it "assigns the requested cardio_exercise as @member.cardio_exercise" do
    put :update, { :member_id => @member, :cardio_exercise => @cardio_exercise_update_attributes = FactoryGirl.attributes_for(:cardio_exercise, :title => "Your Cardio Exercise", :member_id => @member)}
    expect(assigns(:cardio_exercises)).to eq(@member.cardio_exercises)
  end

  it "redirects to the cardio_exercise" do 
    put :update, { :member_id => @member, :id => @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 => @member, :id => @cardio_exercise }
  }.to change(CardioExercise, :count).by(-1)
  end

  it "redirects to the cardio_exercises list" do      
  delete :destroy, { :member_id => @member, :id => @cardio_exercise }
  expect(response).to redirect_to(member_cardio_exercises_url)
  end
end
end

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?

How do I change the set-up and/or tests of the controller's update action so that:

(1) my tests match my routes for the update action?

(2) I pass the necessary parent and child ids in the correct RSpec syntax so records can be found?

I appreciate any help!

like image 388
codeinspired Avatar asked Feb 11 '15 23:02

codeinspired


1 Answers

You must pass the member_id, the cardio_exercise's id, AND the cardio_exercise parameters to update:

put :update, { 
  :member_id => @member, 
  :id => @cardio_exercise.id, 
  :cardio_exercise => @cardio_exercise_update_attributes 
}
like image 93
infused Avatar answered Sep 29 '22 20:09

infused