Reputation: 1321
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
Upvotes: 0
Views: 549
Reputation: 17323
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/.
Upvotes: 1