Rails not loading fixtures in test with similar names with STI - ruby-on-rails

I have 3 classes with STI and I want to load fixtures for each:
Employee
Admin < Employee
OtherEmployee < Employee
My test_helper files has fixtures :all
and the fixtures are in:
employees.yml
admins.yml
other_employees.yml
and yet only the data from other_employees.yml is loaded into the database. Any idea why or how to fix this?
Fixtures:
#employees.yml
one:
id: 1
name: Name1
full_name: FName1
type: Admin
two:
name: Name2
full_name: FName2
type: Admin
three:
name: Name3
full_name: FName3
type: OtherEmployee
#admins.yml
adminone:
name: Admin1
full_name: FAdmin1
type: Admin
admintwo:
name: Admin2
full_name: FAdmin2
type: Admin
#other_employees.yml
oeone:
name: Oemp1
full_name: FOemp1
type: OtherEmployee
oetwo:
name: Oemp2
full_name: FOemp2
type: OtherEmployee

Which version of Rails are you using? It appears that this was a bug and was fixed in Rails 5 and 4.2
https://github.com/rails/rails/issues/18492
There is also some info in the last comment that may be helpful.
https://github.com/rails/rails/issues/18492#issuecomment-218479248
For anyone still running into this problem you need to add a type
attribute to your fixtures, which represents the STI attribute on your
model. For the provided example this would be:
#teachers.yml
presto:
name: Test Teacher
type: Teacher
#students.yml
testo:
name: Test Person
teacher: presto
type: Student

Related

Nil Associations with Rails Fixtures... how to fix?

I have a Rails 5.1 project using rspec/fixtures and I am having trouble getting fixtures to load objects associated with belongs_to/has_one/has_many: the object I requested the fixture for comes back with its _id columns filled with a seemingly-random number and ActiveRecord sees the association as nil. This occurs on large classes with many associations as well as small data classes with only a few fields.
If, in my test code, I assign those associations with normal Ruby code, objects behave as normal and my tests pass. However when loading the same data through fixtures, associated records are not available and tests that require data spanning across associations fail.
As an example, here are two affected classes:
#app/models/location.rb
class Location < ActiveRecord::Base
has_many :orders
has_many :end_user
belongs_to :retailer
belongs_to :depot
end
#app/models/retailer.rb
class Retailer < ActiveRecord::Base
has_many :locations
end
And here are two corresponding fixtures files:
#spec/fixtures/locations.yml
loc_paris:
retailer: ret_europe (Retailer)
name: "Paris"
nickname: "paris"
loc_washington:
retailer: ret_usa (Retailer)
name: "Washington"
nickname: "washington"
#spec/fixtures/retailers.yml
ret_europe:
name: "AcmeCo France"
nickname: "acmecofr"
currency_type: "EUR"
ret_usa:
name: "AcmeCo USA"
nickname: "acmecousa"
currency_type: "USD"
With the above data, running pp locations(:loc_paris) results in:
#<Location:0x0000000006eee1d8
id: 35456173,
name: "Paris",
nickname: "paris",
retailer_id: 399879241,
created_at: Wed, 23 May 2018 22:39:56 UTC +00:00,
updated_at: Wed, 23 May 2018 22:39:56 UTC +00:00>
Those id numbers are consistent through multiple calls, at least in the same RSpec context. (I put pp locations(:loc_paris) in a let block.) Yet pp locations(:loc_paris).retailer returns nil.
I tried using FactoryBot however we had to switch away from it. I am trying to give fixtures an honest shake but it seems like we are best off simply building data objects in the actual test code... because that solutions works without complaining :/
Am I doing something wrong here? Are we asking too much of fixtures?
Thank you!
Tom
Problem with fixtures
Looking at what you've done, locations(:loc_paris) will find the record described in locations.yml, but locations(:loc_paris).retailer won't.
Rails Associations work like this:
locations(:loc_paris).retailer will look for the retailer with retailer_id mentioned in locations(:loc_paris) record. In your case retailer_id: 399879241 and there is no reseller with this id that's why it returns Nil.
Solution:
Describe fixtures like this:
#spec/fixtures/locations.yml
loc_paris:
retailer_id: 1
name: "Paris"
nickname: "paris"
loc_washington:
retailer_id: 2
name: "Washington"
nickname: "washington"
#spec/fixtures/retailers.yml
ret_europe:
id: 1
name: "AcmeCo France"
nickname: "acmecofr"
currency_type: "EUR"
ret_usa:
id: 2
name: "AcmeCo USA"
nickname: "acmecousa"
currency_type: "USD"
Now, locations(:loc_paris).retailer will look for the retailer with retailer_id mentioned in locations(:loc_paris) record i.e. retailer_id: 1 and there is a reseller ret_europe with this id. Problem Solved
When you run rspec, at first rspec saves these fixtures into your database with some auto-generated id values (if id not provided explicitly), that's why id and reseller_id are some random values. If you don't want the id of locations.yml record to be some random value, you can provide it yourself like this:
loc_paris:
id: 1
retailer_id: 1
name: "Paris"
nickname: "paris"
Tips:
As rspec runs in test environment (mentioned in app/spec/rails_helper.rb) and as I mentioned earlier whenever you run rspec, at first it saves the fixtures into your database. If your local and test database are same, fixtures will replace the actual database records of your database. In your case, records in locations and resellers table record will be completely erased and replaced with these fixtures. So, make different database for test environment.
Hope this answer is helpful

How to return matched results in ActiveRecord and then remainder?

Say we have data like
< id: 1, name: "Bill", type: "Lemur" >
< id: 2, name: "Bob", type: "Cow" >
< id: 3, name: "Nancy", type: "Lemur" >
< id: 4, name: "Jack", type: "Seagull" >
< id: 5, name: "Jill", type: "Seagull" >
< id: 6, name: "Jake", type: "Cow" >
< id: 7, name: "Jess", type: "Lemur" >
< id: 8, name: "Nick", type: "Lemur" >
< id: 9, name: "Jacky", type: "Cow" >
< id: 10, name: "Jerry", type: "Cow" >
< id: 11, name: "Samuel", type: "Seagull" >
< id: 12, name: "Tessa", type: "Lemur" >
I want to return all results where type is Lemur first and then return the rest of the results in any order. I thought I could use the group method of ActiveRecord but I don't think I understood that correctly and it's doing something else. I've tried doing Animal.order('Field(type, "Lemur")') after seeing another Stack Overflow answer but that didn't work either. I need a relation returned as I'm going to pass this on to Kaminari to paginate. Anyone know how to do this?
To make things more complicated we actually want to do this on an hstore column but I wanted to figure out the general answer first.
This is on Rails 3.2 with Postgres 9.3.
Since Postgres doesn't have an "ORDER BY FIELD(some_column, 'Zebra', 'Hipo')" like MySQL does - you could try to use "Order by bang!", like such:
Animal.order("type!='Lemur', type!='Cow', type!='Seagull'")
As suggested on this post:
Simulating MySQL's ORDER BY FIELD() in Postgresql
There is a SQL way to do it:
Animal.order("CASE animals.type WHEN 'Seagull' THEN 'a' ELSE 'z' END ASC, animals.name ASC")
This query puts all the animals of type 'Seagull' first, then order the rest based on the animal's name.
Thanks to the basic switch case ;)
I doubt you can do this via a GROUP BY clause.
All I can think of is this which may be a bit unelegant:
Lemur.all.concat Animal.all.reject{ | a | a.type == 'Lemur' }
Edit: That way only worked if you are fine with an array. Here's how you can do it with ActiveRecord::Relation (Rails 4 necessary for where.not(condition)).
Animal.where(type: 'Lemur') + Animal.where.not(type: 'Lemur')
Edit: Ooops, it seems the latter will also return an array.

Categories and subcategories with seeds.rb

I have a form and want to be able to select category & subcategory.
This is an automatic example from seeds.rb:
Examples:
cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
Mayor.create(name: 'Emanuel', city: cities.first)
There is cities.first - but can you do it for cities.sixth or cities.twelfth...?
Is there a different way to do it and connect subcategories with categories in the file?
I would personally advise against using positions to assign subcategories. The possibility exists that there is data on another devs machine or a server.
I generally do it something like:
city = City.find_or_create_by_name(
name: "Chicago"
)
mayor = Mayor.find_or_create_by_city_id(
city_id: city.id,
name: 'Emanuel')

Doctrine: Define many-to-many relation inline in fixture

I want to know the correct way of defining many-to-many relations inline in a Doctrine Fixture. Consider sfDoctrineGuardPlugin for example. The schema can be found here
I'm defining a fixture like:
I already have 2 groups in the sfGuardGroup table, so I wish to refer the group_id
sfGuardUser:
soc-sfUser-1:
first_name: Mrs
last_name: Balasubramanium
email_address: balasubramanium#gmail.com
username: balasubramanium#gmail.com
password: admin
Groups: [{group_id: 2}]
is_active: 1
Is this correct?
If you are also defining the groups in that fixture, you can reference them by name:
sfGuardGroup:
GroupAdmin: ...
GroupEditor: ...
sfGuardUser:
...
Groups: [GroupEditor]
If you want to specify an actual ID you should write it this way:
sfGuardUser:
foo:
first_name: Foo
last_name: Bar
...
sfGuardUserGroup: [{group_id: 2}]
Why? If you take a look at the schema.yml file of sfDoctrineGuardPlugin you can see a refClass property on sfGuardUser relations:
relations:
Groups:
...
refClass: sfGuardUserGroup
It's a little tricky and not so well documented in Doctrine, but it seems to work.

Labeled fixtures for associations in Rails 3 broken

After upgrading to Rails 3, fixtures that refer to other labelled fixtures (for relationships) stop working. Instead of finding the actual fixture with that name, the fixture label is interpreted as a string.
Example:
# Dog.yml
sparky:
name: Sparky
owner: john
# Person.yml
john:
name: John
Where Dog "belongs to" person.
The error message is:
SQLite3::SQLException: table dogs has no column named 'owner'
Try
# Dog.yml
sparky:
name: Sparky
owner: john (Person)
# Person.yml
john:
name: John
See the "polymorphic belongs_to" section of http://api.rubyonrails.org/classes/Fixtures.html
try this:
sparky:
name: Sparky
owner: john (Person)

Resources