12

In my Rails application I have a file sample_data.rb inside /lib/tasks as well as a bunch of test files inside my /spec directory.

All these files often share common functionality such as:

def random_address
  [Faker::Address.street_address, Faker::Address.city].join("\n")
end

Where should I put those helper functions? Is there some sort of convention on this?

Thanks for any help!

Tintin81
  • 9,821
  • 20
  • 85
  • 178

3 Answers3

10

You could create a static class, with static functions. That would look something like this:

class HelperFunctions

     def self.random_address
          [Faker::Address.street_address, Faker::Address.city].join("\n")
     end

     def self.otherFunction
     end
end

Then, all you would need to do is:

  1. include your helper class in the file you want to use
  2. execute it like:

    HelperFunctions::random_address(anyParametersYouMightHave)
    

When doing this, make sure you include any dependencies in your HelperFunctions class.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
BlackHatSamurai
  • 23,275
  • 22
  • 95
  • 156
7

If you're sure it's rake only specific, you also can add in directly in RAILS_ROOT/Rakefile (that's probably not the case for the example you use).

I use this to simplify rake's invoke syntax :

#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path('../config/application', __FILE__)

def invoke( task_name )
  Rake::Task[ task_name ].invoke
end

MyApp::Application.load_tasks

That way, I can use invoke "my_namespace:my_task" in rake tasks instead of Rake::Task[ "my_namespace:my_task" ].invoke.

kik
  • 7,867
  • 2
  • 31
  • 32
  • Exactly why I ended up here! Wanted to know where to put a wrapper for `Rake::Task['namespace:task'].reenable; Rake::Task['namespace:task'].invoke`. – jibiel Dec 20 '15 at 19:57
1

You share methods in a module, and you place such a module inside the lib folder.

Something like lib/fake_data.rb containing

module FakeData
  def random_address
    [Faker::Address.street_address, Faker::Address.city].join("\n")
  end

  module_function 
end

and inside your rake task just require the module, and call FakeData.random_address.

But, if it is like a seed you need to do every time you run your tests, you should consider adding this to your general before all.

E.g. my spec_helper looks like this:

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }

RSpec.configure do |config|
  config.use_transactional_fixtures = true
  config.infer_base_class_for_anonymous_controllers = false
  config.order = "random"

  include SetupSupport

  config.before(:all) do
    load_db_seed
  end
end

and the module SetupSupport is defined in spec/support/setup_support.rb and looks as follows:

module SetupSupport

  def load_db_seed
    load(File.join(Rails.root, 'db', 'seeds.rb'))
  end

end

Not sure if you need to load the seeds, or are already doing this, but this is the ideal spot to also generate needed fake data.

Note that my setup support class is defined in spec/support because the code is only relevant to my specs, I have no rake task also needing the same code.

nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • in order to make your `FakeData` module example code work, it would appear the `module_function` statement should be inserted *before* defining the `random_address` function, rather than *after*. – wehal3001 Aug 15 '16 at 14:50