[rspec-users] How to stub a has_many relationship in Rails 2.3.5

David Chelimsky dchelimsky at gmail.com
Thu Mar 25 07:51:26 EDT 2010


On Wed, Mar 24, 2010 at 10:39 AM, Ben Fyvie <ben.fyvie at champsoftware.com> wrote:
> We have a test that has been working find until we upgraded to rails 2.3.5.
> I’m not too familiar with mocks/stubs so maybe there is an easy solution.
>
> Here is a simple example of our scenario.
>
> Class Person < ActiveRecord::Base
>   has_many :aliases, :dependent => :nullify
>   before_destroy :mark_aliases_as_deleted
>   def mark_aliases_as_deleted
>     self.aliases.each do |alias|
>       alias.mark_as_deleted
>     end
>   end
> end
>
> This is a test to ensure that when the Person is destroyed that all of their
> Aliases get their mark_as_deleted method called. I know this example isn’t
> very practical, but it is the simplest way I could think of to describe our
> problem.
>
> it “should trigger mark_as_deleted in related aliases” do
>   aliases = []
>   3.times do |i|
>     alias = mock(“alias #{i}”)
>     alias.should_receive(:mark_as_deleted)
>     aliases << alias
>   end
>   @person.stub!(:aliases).and_return(aliases)
>   @person.destroy
> end
>
> So the problem we are encountering in our scenario is that we get a
> NoMethodError exception (undefined method `owner_quoted_id' for
> #<Array:0x9a0608c>) when trying to destroy the Person because the stubbed
> Aliases return an array and it appears it is expecting some sort of
> association object that responds to owner_quoted_id
>
> Like I said, we didn’t have any problems until upgrading from Rails 2.3.4 to
> Rails 2.3.5
>
> In case your interested, it is the configure_dependency_for_has_many method
> that calls: "#{reflection.primary_key_name} =
> \#{record.#{reflection.name}.send(:owner_quoted_id)}"
>
> Any help would be greatly appreciated!

There are two ways I would try to go on this. One would be to add the
aliases to the actual association:

it “should trigger mark_as_deleted in related aliases” do
  3.times do |i|
    alias = mock(“alias #{i}”)
    alias.should_receive(:mark_as_deleted)
    @person.aliases << alias
  end

  @person.destroy
end

The other would be to stub owner_quoted_id on the array:

it “should trigger mark_as_deleted in related aliases” do
  aliases = []
  aliases.stub(:owner_quoted_id)

  3.times do |i|
    alias = mock(“alias #{i}”)
    alias.should_receive(:mark_as_deleted)
    aliases << alias
  end

  @person.stub!(:aliases).and_return(aliases)

  @person.destroy
end

I'm not sure that either would work :) But that's where I'd start.

HTH,
David


More information about the rspec-users mailing list