-
Notifications
You must be signed in to change notification settings - Fork 202
Spork.trap_method Jujitsu
You can use Spork.trap_method
(for instance methods) and Spork.trap_class_method
(for class methods) as aggressive jujitsu to prevent portions of your code from being preloaded.
Some of these workarounds may make it into Spork core and be activated by default… but since it’s an aggressive monkey patch on what in many cases is a moving target, it seems best to keep this out until the target settles… or a better way to prevent preloading is worked out with that specific component (coordinating with the gem authors to give controls over when to load project deps?).
What does Spork.trap_{,class_}method
do? It makes it so all calls to the method are captured via a lambda and put into a list for later execution (after the process is forked). Since the trapped method isn’t actually executed when it is called, it’s return value is nil. This can, obviously, cause problems if a return value is expected.
Spork.trap_method is provided by spork, but many of the below examples are written Rails 3 context.
Mongoid likes to preload all of your models in rails, making Spork a near worthless experience. It can be defeated with this code, in your Spork.prefork block, before loading config/environment.rb
# Rails 3
Spork.prefork do
...
require "rails/mongoid"
Spork.trap_class_method(Rails::Mongoid, :load_models)
# Prevent main application to eager_load in the prefork block (do not load files in autoload_paths)
Spork.trap_method(Rails::Application, :eager_load!)
require File.dirname(__FILE__) + "/../config/environment.rb" # <- see this. Your hackery goes above this. After this line is too late.
# Load all railties files
Rails.application.railties.all { |r| r.eager_load! }
...
Devise likes to load the User model. We want to avoid this. It does so in the routes file, when calling devise_for :users, :path => "my_account"
. The solution? Delay route loading.
# Rails 3
Spork.prefork do
...
require "rails/application"
Spork.trap_method(Rails::Application, :reload_routes!)
require File.dirname(__FILE__) + "/../config/environment.rb"
...
Routes reloading changed in Rails 3.1 (rc5 as of this writing). Therefore you will need the following instead of the previous Spork.trap_method
:
Spork.trap_method(Rails::Application::RoutesReloader, :reload!)
Move the blueprint loading to Spork.each_run:
# Rails 3
Spork.each_run do
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
end
Factory Girl 2 does not have the auto-loading issues of previous versions, so you do not need to do anything to get Spork to work. However, if you want changes to factories to take effect on each run, you can reload them like this (in Factory Girl 2.1 or higher).
Spork.each_run do FactoryGirl.reload end
Another thing to watch out for with Factory Girl is when specifying a class for a factory, using a class constant will cause the model to be preloaded in prefork preventing reloading, whereas using a string will not.
Factory.define :user, class: 'MyUserClass' do |f| ... end
Factory Girl 1.x auto-loads the models, so it’s necessary to delay the loading of Factory Girl until each run. To do this, modify your Gemfile so that it doesn’t require factory_girl_rails:
gem 'factory_girl_rails', :require => false
Put the require in the each_run block:
Spork.each_run do require 'factory_girl_rails' end
If this doesn’t work for you, try reloading all of the models after requiring Factory Girl:
Spork.each_run do require 'factory_girl_rails' Factory.factories.clear # reload all the models Dir["#{Rails.root}/app/models/**/*.rb"].each do |model| load model end end
To reload config/locales/*
Spork.each_run do
I18n.backend.reload!
end
To reload your fabricators:
Spork.each_run do
Fabrication.clear_definitions
end
# Rails 3
Spork.prefork do
...
require 'shoulda/matchers/integrations/rspec' # after require 'rspec/rails'
...
end
Same as Factory Girl, use string references instead of class references in rails_admin.rb to not load your models:
RailsAdmin.config do |config|
config.model "Post" do # not config.model Post
...
end
end
ActiveAdmin loads all the registered models when the routes are loaded. This prevents Spork from loading changes before each run.
To fix this, you can delay route loading:
Spork.prefork do
...
require "rails/application"
Spork.trap_method(Rails::Application, :reload_routes!) # Rails 3.0
Spork.trap_method(Rails::Application::RoutesReloader, :reload!) # Rails 3.1
require File.dirname(__FILE__) + "/../config/environment.rb"
...
Check out working examples here: