Rails 5: How do I point fixtures to other fixtures? - ruby-on-rails

I three models Comment, User and Project. Project and Comment need to point to other objects in order to be valid. For example, a comment needs to point to an author (user) and a project.
The associated fixture files look like this:
# comments.yml
test_comment:
author: users(:test_user)
project: projects(:test_project)
# users.yml
test_user:
name: 'test user'
# projects.yml
test_project:
name: 'Test'
description: 'This is a test'
owner: users(:test_user)
However, I've found that my fixtures are probably set up incorrectly. Rails returns false if I try to save the comment:
assert_equal true, comments(:test_comment)
#=> false
I can see that there are foreign keys for a project and author:
=> #<Comment:0x00007f9b1661f3d8
id: 137725605,
body: "",
project_id: 745075726,
author_id: "31ceee04-5307-5059-91db-0dc2068a780c",
created_at: Fri, 22 Feb 2019 13:17:58 UTC +00:00,
updated_at: Fri, 22 Feb 2019 13:17:58 UTC +00:00>
But when I interrogate them, Rails returns nil.
> comments(:test_comment).author
=> nil
> comments(:test_comment).project
=> nil
I expected that one would return users(:test_user) and the other would return projects(:test_project). I thought perhaps I needed to use ERB in my yaml:
test_comment:
author: <%= users(:test_user) %>
project: <%= projects(:test_project) %>
But that results is a stream of errors when I run my tests:
NoMethodError: undefined method `users' for #<#<Class:0x00007f9b17692ff8>:0x00007f9b17692dc8>
What do I need to do to point fixtures to other fixtures? Can it be done? What have I done wrong?

In the Rails guide on Testing with YAML fixtures, you can see that you don't need users(:test_user) to refer to some other object. Instead, you can simply write test_user:
# comments.yml
test_comment:
author: test_user
project: test_project
# users.yml
test_user:
name: 'test user'
# projects.yml
test_project:
name: 'Test'
description: 'This is a test'
owner: test_user
Hope this helps!

Related

rails PaperTrail gem causing duplicate version entries starting with version 6

Here is a piece of rspec code defining a risk_action :
let(:risk_action) {
risk_action = risk.risk_actions.new({name: 'action 1', user: user, action_status_id: created.id, due_date: '2018-02-10', owner_email: user.email, org: org})
risk_action.org = org
risk_action.assigned_to = user
risk_action.save!
risk_action
}
Both in rails 4 & 5, this behaves as I expect (it creates and persists the risk_action without error). Later in the rspec, I have a test case which runs a controller method and eventually calls this risk_action. I can confirm nothing has manipulated the object in the meantime (largely because my test case which is checking it via papertrail is working correctly) :
it "correctly assigns the Paper_Trail whodunnit type", versioning: true, focus: true do
session = RiskActionSession.create({risk_action: risk_action})
expect(session).to be_valid
expect(session.status).to eq('CREATED')
jwt = session.generate_jwt
#request.env["HTTP_AUTHORIZATION"] = "JWT #{jwt}" # <-- DOES NOT WORK
get :update_action, id: session.id, risk_action: {action_status_id: closed.id}, token: jwt
expect(response.status).to eq(200)
# there should be 2 versions [create, update]
versions = risk_action.versions
expect(versions.length).to eq(2)
# 1 update event
ver = versions.where(event: "update")
expect(ver.length).to eq(1)
#whodunnit_type should be set to 'User'
expect(ver[0].whodunnit_type).to eq("User")
end
end #describe "update_action [PUT]" do
Then, after retrieving the risk_action and calling versions on it, I would expect to see a single create entry. Instead, I see two, precise duplicated except for the id (of the version object) :
[#<PaperTrail::Version:0x0000000006b1a930
id: 24328,
item_type: "RiskAction",
item_id: 44074,
event: "create",
whodunnit: "543076",
object: nil,
created_at: Mon, 15 Aug 2022 16:14:45 UTC +00:00,
object_changes:
"---\nname:\n- \n- action 1\nuser_id:\n- \n- 543076\naction_status_id:\n- \n- 66607\ndue_date:\n- \n- '2018-02-10 00:00:00'\nowner_email:\n- ''\n- foo1#example.com\norg_id:\n- \n- 642273\nassigned_to_id:\n- \n- 543076\nassigned_to_type:\n- \n- User\nid:\n- \n- 44074\n",
whodunnit_type: nil,
comments: nil,
transaction_id: 24322>,
#<PaperTrail::Version:0x0000000006b1a430
id: 24329,
item_type: "RiskAction",
item_id: 44074,
event: "create",
whodunnit: "543076",
object: nil,
created_at: Mon, 15 Aug 2022 16:14:45 UTC +00:00,
object_changes:
"---\nname:\n- \n- action 1\nuser_id:\n- \n- 543076\naction_status_id:\n- \n- 66607\ndue_date:\n- \n- '2018-02-10 00:00:00'\nowner_email:\n- ''\n- foo1#example.com\norg_id:\n- \n- 642273\nassigned_to_id:\n- \n- 543076\nassigned_to_type:\n- \n- User\nid:\n- \n- 44074\n",
whodunnit_type: nil,
comments: nil,
transaction_id: 24322>]
This behaviour starts occurring with the papertrail gem version 6 on rails 4.2.10. The behaviour continues into rails 5.2.8 and papertrail gem versions 9 thru 11, the latter of which is where I'm trying to end up.
I am not sure why the behaviour begins here, there is nothing in the changelog (at least, that's obvious to me) why this would be the case. Any help is appreciated -- thank you.

Airborne GET from test environment

Using Airborne, how can I use GET to return values from test environment?
For example, I have the following test:
it 'should foo the bar' do
product = FactoryGirl.create(:product)
get "/v1/products"
pp product
pp body
expect_status 200
end
The output of product is:
#<Product:0x007f9dfe601078
id: 847,
ref: "038-71-8140174268593",
name: "Adipisci Sqryujdcoefpthnzbvagwlxikm",
description:
"Lorem ipsum...",
created_at: Tue, 01 Nov 2016 15:48:25 UTC +00:00,
updated_at: Tue, 01 Nov 2016 15:48:25 UTC +00:00>
But the output of body is:
"{\"data\":[]}"
I have rails server running test environment with rails s -e test
If I run rails server with development environment, the body returns all products from dev environment with no problems.
I was running the test with RSpec.describe ProductResource, type: :resource do instead of RSpec.describe 'Products', type: :request do.

in rspec, why do I need the '[]' in expect().to eq([])?

Rails app, writing specs:
RSpec.describe AdvertisementsController, :type => :controller do
let(:my_ad) { Advertisement.create!(title: 'title', copy: 'copy text', price: 10)}
describe 'GET #index' do
...
...
it 'renders my_ad' do
get :index, {id: my_ad.id}
expect(assigns[:advertisements]).to eq(my_ad)
end
end
...
...
end
I wrote the above, which gave the error below.
1) AdvertisementsController GET #index renders my_ad
Failure/Error: expect(assigns[:advertisements]).to eq(my_ad)
expected: #<Advertisement id: 1, title: "title", copy: "copy text", price: 10, created_at: "2016-02-26 02:39:20", updated_at: "2016-02-26 02:39:20">
got: #<ActiveRecord::Relation [#<Advertisement id: 1, title: "title", copy: "copy text", price: 10, created_at: "2016-02-26 02:39:20", updated_at: "2016-02-26 02:39:20">]>
(compared using ==)
Diff:
## -1,8 +1,8 ##
-#<Advertisement:0x007ff6995e19f0
- id: 1,
- title: "title",
- copy: "copy text",
- price: 10,
- created_at: Fri, 26 Feb 2016 02:39:20 UTC +00:00,
- updated_at: Fri, 26 Feb 2016 02:39:20 UTC +00:00>
+[#<Advertisement:0x007ff6994f9560
+ id: 1,
+ title: "title",
+ copy: "copy text",
+ price: 10,
+ created_at: Fri, 26 Feb 2016 02:39:20 UTC +00:00,
+ updated_at: Fri, 26 Feb 2016 02:39:20 UTC +00:00>]
With this code, the test will pass. All it seems to do is add [..] around the variable, as such (| & ^ to emphasize location):
Why does that work?
RSpec.describe AdvertisementsController, :type => :controller do
let(:my_ad) { Advertisement.create!(title: 'title', copy: 'copy text', price: 10)}
describe 'GET #index' do
...
...
it 'renders my_ad' do
get :index, {id: my_ad.id}
expect(assigns[:advertisements]).to eq([my_ad])
end ^ ^
end | |
...
...
end
of note I can see that the objects have different identifying id's, so I think that's part of the reason and the [..]'s either ignore the mismatch or something, but I'd like to understand it.
-#<Advertisement:0x007ff6995e19f0 vs . +[#<Advertisement:0x007ff6994f9560
[] is Ruby syntax for an array. So your test is expecting to assign an array of advertisements (or in this case, something that behaves like an array, such as an ActiveRecord::Relation), containing just one element, my_ad.
Your code also sounds quite strange in that you're providing an ID to the index action, expecting only that record to be returned. Index actions are for listing out groups of records - a show action is for showing the details of a single record.

RSpec/Mongoid inheritance of defaults completely different result in test/development

This is one of those ones that makes you think you're going insane...
I have a class Section, and a DraftSection that inherits from it:
(Trimmed for brevity)
class Section
include Mongoid::Document
belongs_to :site
field :name, type: String
end
And
class DraftSection < Section
field :name, type: String, default: "New Section"
end
All simple stuff... console proves (again, trimmed for brevity):
004 > site = Site.first
=> #<Site _id: initech, name: "INITECH">
005 > site.sections.build
=> #<Section _id: 1, site_id: "initech", name: nil>
006 > site.draft_sections.build
=> #<DraftSection _id: 2, site_id: "initech", name: "New Section">
As you can see - the draft section name correctly defaults to "New Section" as it is overridden in the subclass.
Now when I run this spec:
describe "#new" do
it "should return a draft section" do
get 'new', site_id: site.id, format: :json
assigns(:section).should == "Something..."
end
end
Which tests this controller method:
def new
#section = #site.draft_sections.build
respond_with #section
end
Which fails (as expected), but with this:
Failure/Error: assigns(:section).should == "Something..."
expected: "Something..."
got: #<DraftSection _id: 1, site_id: "site-name-4", name: nil> (using ==)
What gives???
Update:
I figured it might be an issue with the different environment settings, so I looked at the mongoid.yml config file and saw this in the options:
# Preload all models in development, needed when models use
# inheritance. (default: false)
preload_models: true
I added it to the test environment settings too, but still no joy :(
Update 2 - the plot thickens...
Thought I'd try loading up the console in the test environment and trying the same as before:
001 > site = Site.first
=> #<Site _id: initech, name: "INITECH">
002 > site.draft_sections.build
=> #<DraftSection _id: 1, site_id: "initech", name: "New Section">
WTF?
Ok, no one's listening, but I'll post the solution here for future reference anyway...
For some reason, some time ago I had a debug session that meant I had left this code in my Spork.each_run block
# Reload all model files when run each spec
# otherwise there might be out-of-date testing
# require 'rspec/rails'
Dir["#{Rails.root}/app/controllers//*.rb"].each do |controller|
load controller
end
Dir["#{Rails.root}/app/models//*.rb"].each do |model|
load model
end
Dir["#{Rails.root}/lib//*.rb"].each do |klass|
load klass
end
This was causing the models to get reloaded on each run of a spec. Not surprisingly, this screwed up the way the classes were set up in memory whilst the specs were running.
Definitely explains why it was such a hard one to debug...
So for future googlers with similar inheritance problems in Rspec only - make sure that there's nothing reloading models anywhere in the test stack.

RSpec fixtures not loading

I am taking over a code base and am trying to run the tests. I am
somewhat new to RSpec so this might be a trivial problem.
Basically I can tell that the fixtures are not getting loaded. All 100
tests fail with a similar error.
But I don't know why. Below is the code. Where can I start looking?
In spec_helper.rb, which I know is running, I see:
Spec::Runner.configure do |config|
config.global_fixtures = :all
end
One of the tests in spec/controllers/downloads_controller_spec.rb
is below. I know it is running and I know that before the 'describe',
Partner.count == 0, so no fixture.
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe DownloadsController do
integrate_views
describe "when PDF is ready" do
before(:each) do
#registrant = Factory.create(:step_5_registrant)
stub(#registrant).merge_pdf { `touch #{#registrant.pdf_file_path}`
}
#registrant.generate_pdf
#registrant.save!
end
it "provides a link to download the PDF" do
get :show, :registrant_id => #registrant.to_param
assert_not_nil assigns[:registrant]
assert_response :success
assert_template "show"
assert_select "span.button a[target=_blank]"
assert_select "span.button a[onclick]"
end
after(:each) do
`rm #{#registrant.pdf_file_path}`
end
end
And here is what in various directories:
spec/fixtures/partners.yml - which contains 2 yaml records:
sponsor:
id: 1
username: rtv
email: rocky#example.com
crypted_password:
"c8e5b51b237344fe0e72539af0cac7197f094a5e933ffacf6e7fa612363c5933f520710c6427ac31fc4c68a2d7bb48eae601c74b96e7838f9ca1a0740b67576a"
password_salt: "Y4PPzYx2ert3vC0OhEMo"
name: Rocky
organization: Rock The Vote
url: http://rockthevote.com
address: 123 Wherever
city: Washington
state_id: 9
zip_code: 20001
phone: 555-555-1234
survey_question_1_en: "What school did you go to?"
survey_question_2_en: "What is your favorite musical group?"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
# TODO: remove partner 2 in production
partner:
id: 2
username: bull_winkle
email: bull_winkle#example.com
crypted_password:
"c8e5b51b237344fe0e72539af0cac7197f094a5e933ffacf6e7fa612363c5933f520710c6427ac31fc4c68a2d7bb48eae601c74b96e7838f9ca1a0740b67576a"
password_salt: "Y4PPzYx2ert3vC0OhEMo"
name: Bullwinkle
organization: Bullwinkle, Inc.
url: http://example.com
address: 123 Wherever
city: Washington
state_id: 9
zip_code: 20001
phone: 555-555-1234
survey_question_1_en: "What school did you go to?"
survey_question_2_en: "What is your favorite musical group?"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
Maybe this is done automatically now and you have solved it, but have you checked that your "spec/spec_helper.rb" contains:
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
Cheers

Resources