简体   繁体   中英

How to load fixtures in a specific order in Rails 5

I have two interdependent models, account and user. An account is always created by a user, whose id is thus stored in the account's creator_id attribute, and a user necessarily belongs to an account (but there's no limit on the number of users belonging to an account), this information being stored in user's account_id attribute. The same user can have created different accounts.

I expressed these rules this way :

User model :

belongs_to :account, inverse_of: :users
has_many :created_accounts, class_name: "Account", :foreign_key => "creator_id"

Account model :

 belongs_to :creator, class_name: 'User', optional: true
 has_many :users, inverse_of: :account

As they are interdependent, I used a dirty workaround to be able to instantiate them : I create first the account, and following that action I force the user to create their profile, and their user_id is added to the account as creator_id in an update.

That's why I have, in Account model :

validate :require_actual_creator_id, on: :update
------------------------------------------------
 def require_actual_creator_id
    User.find(creator_id)
  end

I was working on an authentication system only involving the user model, so I had these lines commented out until yesterday when I uncommented them.

I ran db:migrate:reset, db:seed and db:migrate RAILS_ENV=test without any problem, both models have a normal behavior in the console, but when it comes to fixtures (eg testing or db:fixtures:load), I got the following error :

NoMethodError: undefined method `id' for nil:NilClass
/home/vincent/workspace/bam-rails/test/fixtures/users.yml:16:in `get_binding'

Here is one typical fixture causing the problem, the line 16 being the commented one :

michael:
  id: 1
  handle: Michael Example
  email: michael@example.com
  encrypted_password: <%= User.generate_encrypted_token('password') %>
  role_id: <%= User::ADMIN %>
  is_activated: true
  activated_at: <%= DateTime.now %>
  #account_id: <%#= Account.first.id %>

When I comment this last line, there's no problem anymore. However, I'd like to load proper fixtures for my tests, because for example the user created here is not valid.

I read in this post that the fixtures load in the alphabetical order. If this is right, I can't get why I have to comment this line, because accounts is supposed to be loaded before users.

I foundthat solution to work but it's not from the official documentation and it's quite old, dated back to 2007. I am afraid this would stop working from one day to the next.

Does anyone know how to properly load the fixtures in a custom order in Rails 5, or has another solution to my problem ? Thank you in advance.

The problem you have is entirely stemming from how you organized your code. That work around where you create the first account is where you are having an issue. So the fact that by the time your user is instantiated your account does not exist first because the fixtures are not loaded yet; of this I am sure you are aware. Fixtures are notoriously brittle this is why people often move away from them the more complex their code gets. In this case though the are helping you expose a code smell, anytime the order or running you test or basic non test case specific set up causes issues that means you have an issue with your code. I would suggest you find a way around using this "dirty work around".

Now if for some reason you are married to the way your code is currently organized I suggest maybe switching to factory girl , it will give you a little more flexibility to control the point at which your mock objects are instantiated that way you wont run into this issue. I will however say this will just enable you to continue you down this path that will more than likely just lead to more issues down the road, your best bet is to reimplement the feature.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM