0
votes

I am trying to learn Rspec in a very simple CRUD Rails 3.2.8 app. I'm following the general pattern of Michael Hartl's examples and have been moderately successful with cucumber for the outside in portion. Now I want to test a Twilio SMS feature and cannot seem to get to first base, mostly because I'm not asking the right questions, so I expect to be corrected here and get back on track. My app has two models, commodity and price and they interact with each other in my cucumber tests, so it appears. I'm aware, like in cucumber, I need an object to start to test its interactions. In my prices controller, I see that I can get the commodity's prices with the below in my prices#create method:

 @price = @commodity.prices.build(params[:price])

I ultimately want to generate a factory that will have many prices for a given commodity. But I want to get to base first. Following thoughtbot's examples on their Readme I'm attempting the following in rails console:

 FactoryGirl.create(:commodity) do |price|
   Commodity.prices.build(attributes_for(:price))
 end

The result is: NoMethodError: undefined method `prices' for # Hmm, I must not be understanding either Rspec or Factory Girl. Here is my basic factories.rb:

 FactoryGirl.define do
   factory :commodity do
     name "corn"
   end

   sequence :price do |n|
     price
     date { Time.now }
   end
 end

Here are my two models:

 class Commodity < ActiveRecord::Base
   attr_accessible :description, :name
   has_many :prices
 end

 MOST_RECENT = 5
 class Price < ActiveRecord::Base
   attr_accessible :buyer, :date, :price, :quality, :commodity_id
   scope :most_recent, lambda { order("id desc").limit(MOST_RECENT) }
    belongs_to :commodity
 end

My attempt to understand this is to do it simply in Rails console but the error also appears when I run rspec as well. But why would FactoryGirl, or Rspec, not seem to use the prices method I get with Active Record? Clearly, I'm not understanding something or I would have found the answer on Stack, thanx, sam

1

1 Answers

1
votes

In your FactoryGirl.create there are a couple problems. First, the block argument should be commodity, not price. create passes the created object into the block. Second, you're trying to run prices on the Commodity class. In your object relationship, prices is an accessor associated with a specific instance. There is no Commodity#prices method, but any given instance of Commodity will have prices. You can probably use build like that, but I think the canonical way is to use the shift operator to add a Price.

Putting this together gets you:

FactoryGirl.create(:commodity) do |commodity|
  commodity.prices << FactoryGirl.create(:price, commodity: commodity)
end

I'm not sure what you're doing with the sequence in your Commodity factory definition. If you're trying to make sure that Commodities are created with Prices by default (without adding them as above), check out some of the tips at http://icelab.com.au/articles/factorygirl-and-has-many-associations/.