[rspec-users] Controller iterating through returned records and appending to each

Pat Maddox pergesu at gmail.com
Tue Oct 16 12:12:33 EDT 2007


On 10/16/07, Dylan Markow <dmarkow at gmail.com> wrote:
> I have a controller that gets a list of employees (which has an "include =>
> [:salaries, :incentives, :billablegoals, :reviews]"). I then need it to
> iterate through each employee and determine their current active goal based
> on the "effective date."
>
> After playing around with it a bunch, I got the following to work. Only
> problem is that if I remove the "@employees.each { |e|....." line, the test
> still passes (which means the test isn't accurate). I had to stub out
> "current_goal" and "current_goal=" because I kept getting "unexpected call"
> errors on each.
>
> Controller excerpt:
>   def employee_report
>     @employees = Employee.find_active_employees
>     @employees.each { |e| e.current_goal = e.billablegoals.empty? ? "-" :
> e.billablegoals.select { |bg| bg.effective_date <= Date.today }[0].goal }
>   end
>
> Spec:
>
>
> require File.dirname(__FILE__) + '/../spec_helper.rb'
>
> describe ManagementController, "GET /management/employee_report" do
>
>
>   before(:each) do
>     @bg1 = mock_model(Billablegoal, :effective_date => Date.today-3.months,
> :goal => 50)
>     @bg2 = mock_model(Billablegoal, :effective_date => Date.today + 1.month
> , :goal => 75)
>     @mock_employee = mock_model(Employee, :billablegoals => stub(Array,
> :select => [@bg1], :empty? => false))
>     @employees = [@mock_employee]
>     @employees.each { |f| f.stub!(:current_goal=) }
>     @employees.each { |f| f.stub!(:current_goal) }
>
> Employee.stub!(:find_active_employees).and_return(@employees)
>     login # used to bypass the restful_authentication login_required filter
>   end
>
>   def do_get
>     get :employee_report
>   end
>
>   it "should add the current billable goal to each returned employee" do
>     do_get
>     @employees[0].should respond_to(:current_goal)
>   end
>
> end
>
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>

I think you ought to push current_goal down into the model.

class Employee < ActiveRecord::Base
  has_many :billablegoals

  def current_goal
    bill_goal = billablegoals.detect {|bg| bg.effective_date <= Date.today }
    return nil if bill_goal.blank?
    bill_goal.goal
  end

  # or do it all in the db
  def current_goal
    bill_goal = billablegoals.find :first, :conditions =>
["effective_date <= ?", Date.today]
    return nil if bill_goal.blank?
    bill.goal
  end
end

Your controller spec becomes absurdly simple:

describe ManagementController, "GET /management/employee_report" do
  before(:each) do
    Employee.stub!(:find_active_employees).and_return [:active1, :active2]
  end

  def do_get
    get :employee_report
  end

  it "should find the active employees" do
    Employee.should_receive(:find_active_employees).and_return
[:active1, :active2]
    do_get
  end

  it "should assign the employees to the view" do
    do_get
    assigns[:employees].should == [:active1, :active2]
  end
end

And finally in your view you iterate through the employees, showing their goal:

<% @employees.each do |e| %>
  Goal: <%= e.current_goal || "=" %>
<% end %>



Very nice.

Pat


More information about the rspec-users mailing list