Reputation: 888
I am trying to write a test to check that an associated object exists and the relevant id is stored in the database.
A panel belongs to a page. A page has many panels.
A sample of the current errors I have is this
CorporatePanel
Failure/Error: @instance = corporate_panel
ActiveRecord::RecordInvalid:
Validation failed: Corporate page does not exist, Corporate page can't be blank
# ./spec/support/project_helpers.rb:11:in `block (2 levels) in setup_factories'
# ./spec/models/corporate_panel_spec.rb:8:in `block (2 levels) in <top (required)>'
# -e:1:in `<main>'
Which I believe is caused because my test isnt creating an instance of page before a panel is created.
In my panel model I use this
validate :check_associates
private
def check_associates
associated_object_exists CorporatePage, :corporate_page_id
end
The method 'associated_model_exists' is a helper
def associated_object_exists(klass,fn,required=true)
id=self.send(fn)
id_setter=(fn.to_s+'=').to_sym
unless klass.find_by_id(id)
self.send(id_setter,nil)
id=nil
end
if required==true and id.nil?
errors.add(fn,"does not exist")
return false
end
end
The Panel test looks like this,
setup_factories
before do
@instance = corporate_panel
end
it { should belong_to(:corporate_page) }
mandatory_integer :section
mandatory_belongs_to CorporatePage
The madatory belongs_to looks like this
def mandatory_belongs_to(model)
context "#{model}" do
context "where the id is incorrect" do
before do
allow(model).to receive(:find_by_id).and_return(nil)
end
it "should be invalid" do
expect(@instance).to_not be_valid
end
end
context "where the id is correct" do
before do
allow(model).to receive(:find_by_id).and_return(true)
end
it "should be valid" do
expect(@instance).to be_valid
end
end
end
end
FactoryGirl.define do
factory :corporate_panel do
corporate_page_id 1
section 1
# position 1
panel_type "MyString"
title "MyString"
headline "MyString"
body "MyText"
workflow_state "MyString"
end
end
FactoryGirl.define do
factory :corporate_page do
title "MyString"
static_descriptor "Home"
# workflow_state "MyString"
end
end
How would I ensure that a page is created before the model, if that is even the problem?
Upvotes: 0
Views: 290
Reputation: 15992
The problem is the way you've defined your factory. It should create the appropriate association while creating the corporate panel. It should be something like this:
FactoryGirl.define do
factory :corporate_page do
title "MyString"
static_descriptor "Home"
# workflow_state "MyString"
end
end
FactoryGirl.define do
factory :corporate_panel do
corporate_page # this refers to the factory defined above!! and will create appropriate association.
section 1
# position 1
panel_type "MyString"
title "MyString"
headline "MyString"
body "MyText"
workflow_state "MyString"
end
end
Here are some links for further reading on factories: http://www.hiringthing.com/2012/08/17/rails-testing-factory-girl.html and https://github.com/brennovich/cheat-ruby-sheets/blob/master/factory_bot.md
Upvotes: 1
Reputation: 47548
You can use an association as recommended in Surya's answer. If you need more control over the creation of factories, you can also explicitly pass in the Corporate page when creating the CorporatePanel:
let(:corporate_page) { FactoryGirl.create :corporate_page }
let(:corporate_panel) { FactoryGirl.build :corporate_panel, corporate_page: corporate_page }
This might be preferable if you want to use the :corporate_panel
factory in other examples without an associated corporate_page
.
Upvotes: 0