Search code examples
ruby-on-railsrubyruby-on-rails-4rspecdatabase-cleaner

How should I handle a Rails model record that my controller and views rely on?


I have a Rails application that deals with sports teams. There's a model, Club, that contains all the teams and they relate to Matches, etc. The application is centered around one of these clubs, and relies on the existence of that record. I've got an application helper method that defines the main club, essentially:

def main_club
  @main_club ||= Club.find_by(abbrv: 'CLB')
end

And then that gets referred to in controller logic (can do certain things for main_club that you can't for the others) and in views (displaying certain key info about upcoming matches, etc).

This feels messy to me. Hard code relying on "soft" database records? But I do need the Club to be a record, to allow for all of its relationships.

I've just sort of left it as it is, but it messes up RSpec. Even running Rails.application.load_seed in config.before(:suite), I constantly get specs failing because it can't call .matches, eg, on nil.

Is there an established practice for this sort of thing? How should I go about this?

Edit: The seed file includes all current Clubs (including the main one), with the potential for adding more in the administrative interface/controller. It's possible that the RSpec issues are coming from something DatabaseCleaner is doing wrong, but a) I'm not sure what that would be and b) my concerns about hard code relying on "soft" database records remain regardless of RSpec.


Solution

  • It is perfectly normal for an app to require rows in the database to exist to function properly, for example rows representing permissions and roles, country codes, etc.

    It may make you feel better about this if you think about how ActiveRecord relies on there being a schema, too. A Rails app depends on the database, not the other way around. Depending on there being rows in the database is not such a big leap.

    So full speed ahead on your approach. You just need to get some details right.

    One detail that might be the problem is that if you're using DatabaseCleaner with strategy :truncation, you need to tell DatabaseCleaner to not truncate your seeds. In your spec_helper.rb (RSpec 2) or rails_helper.rb (RSpec 3):

    RSpec.configure do |config|
    
      config.before(:suite) do
        DatabaseCleaner.strategy = :transaction
        DatabaseCleaner.clean_with :truncation, except: ['clubs']
      end
    
      config.around(:each) do |example|
        DatabaseCleaner.cleaning { example.run }
      end
    
    end
    

    If you want to delete additional clubs created during tests, you'd have to do that manually:

    RSpec.configure do |config|
      config.after(:each) do
        Club.where("abbrv not in(?)", %w(CLBS N YR SDS))
      end
    end
    

    If you're not using strategy :truncation, keep it simple and don't bother with DatabaseCleaner, just use config.use_transactional_fixtures = true in your spec_helper.rb/rails_helper.rb.