I have a Deal model with a model Step associated. a deal has_many Steps and a step belongs to a Deal.
I create a Deal Factory:
let!(:deal1) { create(:deal,
partner: partner,
title: "Deal1" ) }
For specific reasons related to validations and the use of the gem rspec-retry I can't create the associated Steps by using the "usual" after_create or Transients provided by Factory Girl, and it's Ok because my technique so far worked on all my tests. Her's what I do to create 5 associated Steps for Deal1:
(0..4).each do |n|
let!(:"deal1_step#{n}") {
FactoryGirl.create(:step,
order_nb: n,
message_content: "this is message #{n}",
background_asset_filename: "campaigns/assets_for_tests/backgroundimage#{n}.jpg",
deal: deal)
}
end
This creates deal1_step0, deal1_step1, deal1_step2, deal1_step3 and deal1_step4, just as I need and it's working today on all my tests
My issue comes because I now must add to each deal1 steps attributes that differ and can't just be put in the code above as they are completely different from each other each time PLUS they only begin being present on step1 (step0 can't have a video). These attributes I need to send data to are:
video_url
video_x
video_y
1st attempt:
I tried the code below but it fails and gives me the error: deal1_step0.video_url = nil # there can't be any video on step0 (a validation is set for this)
`deal1_step1` is not available on an example group (e.g. a `describe` or `context` block). It is only available from within individual examples (e.g. `it` blocks) or from constructs that run in the scope of an example (e.g. `before`, `let`, etc).
deal1_step0.video_url = nil
deal1_step0.video_x = nil
deal1_step0.video_y = nil
deal1_step1.video_url = "https://www.facebook.com/rihanna/videos/10155221800656676/"
deal1_step1.video_x = 500
deal1_step1.video_y = 500
deal1_step2.video_url = "https://www.facebook.com/ClaraLionelFoundation/videos/1821445664574948/"
deal1_step2.video_x = 500
deal1_step2.video_y = 300
deal1_step3.video_url = "https://www.facebook.com/rihanna/videos/10155330511896676/"
deal1_step4.video_x = 250
deal1_step4.video_y = 500
2nd attempt:
I also tried something like but got a similar error like above: deal1_step1.update_attributes( video_url:
"https://www.facebook.com/rihanna/videos/10155221800656676/",
video_x: 500,
video_y: 500 )
3rd attempt:
I tried then to create sort of symbols:
let(:video0) { nil }
let(:video1) { "https://www.facebook.com/rihanna/videos/10155221800656676/" }
let(:video2) { "https://www.facebook.com/ClaraLionelFoundation/videos/1821445664574948/" }
let(:video3) { "https://www.facebook.com/rihanna/videos/10155330511896676/" }
(0..4).each do |n|
let!(:"deal1_step#{n}") {
FactoryGirl.create(:step,
video_url: :"video#{n}",
video_x: 500,
video_y: 500,
st_background_asset_filename: "campaigns/042017/assets_for_tests_and_dev/backgroundimage#{n}.jpg",
deal: deal1)
}
end
This time I got no error on the test that was able to be run BUT it does not work as the view thinks all those video_url are nil, it seems i don't manage to inject/update those attributes.
Is there a clean/proper way to update the attributes of deal1_step0, deal1_step1, deal1_step2, deal1_step3 and deal1_step4 ?
The easiest solution to this is to just define arrays of the changing values and use those in your FactoryGirl steps
urls = [nil, "https://www.facebook.com/rihanna/videos/10155221800656676/", ...]
xs = [nil, 500, ...]
ys = [nil, 200, ...]
(0..4).each do |n|
let!(:"deal1_step#{n}") {
FactoryGirl.create(:step,
video_url: urls[n],
video_x: xs[n],
video_y: ys[n],
st_background_asset_filename: "campaigns/042017/assets_for_tests_and_dev/backgroundimage#{n}.jpg",
deal: deal1)
}
end
For anything else you need to understand how let
/ let!
works. let
defines a method (named by the symbol passed in) on the example (it's actually on a module that gets mixed in, same effect) which memoizes the response of the block passed to it. let!
calls let
and then defines a before block that calls the method let
defined so it has already been run before the test example is. That's why you're getting the error ' deal1_step1
is not available on an example group (eg a ...', because the method is defined on the example, not on the group.
Therefore, if you don't want to do something like the arrays example above then you'd need to do your attribute updating in a block that gets run in the example context, so a before
block - like
(0..4).each do |n|
let!(:"deal1_step#{n}") {
FactoryGirl.create(:step,
order_nb: n,
message_content: "this is message #{n}",
background_asset_filename: "campaigns/assets_for_tests/backgroundimage#{n}.jpg",
deal: deal)
}
end
before do
deal1_step1.video_url = "https://www.facebook.com/rihanna/videos/10155221800656676/"
deal1_step1.video_x = 500
deal1_step1.video_y = 500
# may need to save deal1_step1 depending on exactly what you're looking for
deal1_step2.update_attributes(video_url: "https://www.facebook.com/rihanna/videos/10155221800656676/", video_x: 500, video_y: 500 )
...
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.