1
0
Fork 0
mirror of https://github.com/thoughtbot/factory_bot_rails.git synced 2022-11-09 11:49:18 -05:00
thoughtbot--factory_bot_rails/lib/factory_bot_rails/reloader.rb

46 lines
838 B
Ruby
Raw Normal View History

Allow reloading of factory definitions Closes #236 This commit uses ActiveSupport's FileUpdateChecker to allow reloading FactoryBot of definitions whenever a file in `FactoryBot.definition_file_paths` gets updated. This is similar to reloading for [I18n](https://github.com/rails/rails/blob/ced104d57997c7bceef3d1e6c8a713431363c3bb/activesupport/lib/active_support/i18n_railtie.rb#L60-L70) and [react rails](https://github.com/reactjs/react-rails/blob/83b6175460b6fd19d667854ebea4777d8c73705a/lib/react/rails/railtie.rb#L35-L41) This allows us to get rid of any Spring-specific logic in the railtie, since [Spring hooks into the application reloader](https://github.com/rails/spring/blob/0c711ff10b4ad7dcc34282b5e08573c2ce1e668a/lib/spring/application.rb#L161). This partly solves #211, since we no longer call `FactoryBot.reload` at all in `after_initialize`. Instead, we will only call it when one of the files in `definition_file_paths` gets updated. I say it partly solves #211 because once a definition file gets updated, reloading would still give warnings about redefining any constants in the definition files. I wonder how common it is to define constants in the same file as factory definitions. It's probably better to keep constants in the autoload path, allowing Rails to handle unloading and reloading them in development. I would want to see some specific examples before worrying too much about it. I would also like to offer a better way to configure the definition file paths (see #165 and #166) and possibly an option to opt out of loading definitions at all (could help with issues like #192). A couple of quirks here: * the to_prepare block could potentially get [called multiple times](https://github.com/rails/rails/issues/28108). It shouldn't matter, since `execute_if_updated` is a no-op if no updates have been made. * I noticed that the first time I call `reload!` in the console the factory definitions get reloaded even when I made no updates to the definition files. I think it is related to [this](https://github.com/rails/rails/blob/f7c5a8ce262cf16ad8d7c0b0d631a4b88afec414/activesupport/lib/active_support/evented_file_update_checker.rb#L18). After the first call `reload!` works as expected, only reloading the factory definitions if the definition files were updated. * Rails uses execute rather than execute_if_updated for the [route reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L133) and for the [watchable file reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L173). This means that changes to factory definitions will cause reloading of the whole application. I think this is fine.
2018-07-16 18:31:25 -04:00
# frozen_string_literal: true
require "factory_bot_rails/definition_file_paths"
module FactoryBotRails
class Reloader
def initialize(app, config)
@app = app
@config = config
@paths = DefinitionFilePaths.new(FactoryBot.definition_file_paths)
Allow reloading of factory definitions Closes #236 This commit uses ActiveSupport's FileUpdateChecker to allow reloading FactoryBot of definitions whenever a file in `FactoryBot.definition_file_paths` gets updated. This is similar to reloading for [I18n](https://github.com/rails/rails/blob/ced104d57997c7bceef3d1e6c8a713431363c3bb/activesupport/lib/active_support/i18n_railtie.rb#L60-L70) and [react rails](https://github.com/reactjs/react-rails/blob/83b6175460b6fd19d667854ebea4777d8c73705a/lib/react/rails/railtie.rb#L35-L41) This allows us to get rid of any Spring-specific logic in the railtie, since [Spring hooks into the application reloader](https://github.com/rails/spring/blob/0c711ff10b4ad7dcc34282b5e08573c2ce1e668a/lib/spring/application.rb#L161). This partly solves #211, since we no longer call `FactoryBot.reload` at all in `after_initialize`. Instead, we will only call it when one of the files in `definition_file_paths` gets updated. I say it partly solves #211 because once a definition file gets updated, reloading would still give warnings about redefining any constants in the definition files. I wonder how common it is to define constants in the same file as factory definitions. It's probably better to keep constants in the autoload path, allowing Rails to handle unloading and reloading them in development. I would want to see some specific examples before worrying too much about it. I would also like to offer a better way to configure the definition file paths (see #165 and #166) and possibly an option to opt out of loading definitions at all (could help with issues like #192). A couple of quirks here: * the to_prepare block could potentially get [called multiple times](https://github.com/rails/rails/issues/28108). It shouldn't matter, since `execute_if_updated` is a no-op if no updates have been made. * I noticed that the first time I call `reload!` in the console the factory definitions get reloaded even when I made no updates to the definition files. I think it is related to [this](https://github.com/rails/rails/blob/f7c5a8ce262cf16ad8d7c0b0d631a4b88afec414/activesupport/lib/active_support/evented_file_update_checker.rb#L18). After the first call `reload!` works as expected, only reloading the factory definitions if the definition files were updated. * Rails uses execute rather than execute_if_updated for the [route reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L133) and for the [watchable file reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L173). This means that changes to factory definitions will cause reloading of the whole application. I think this is fine.
2018-07-16 18:31:25 -04:00
end
def run
return unless @paths.any?
Allow reloading of factory definitions Closes #236 This commit uses ActiveSupport's FileUpdateChecker to allow reloading FactoryBot of definitions whenever a file in `FactoryBot.definition_file_paths` gets updated. This is similar to reloading for [I18n](https://github.com/rails/rails/blob/ced104d57997c7bceef3d1e6c8a713431363c3bb/activesupport/lib/active_support/i18n_railtie.rb#L60-L70) and [react rails](https://github.com/reactjs/react-rails/blob/83b6175460b6fd19d667854ebea4777d8c73705a/lib/react/rails/railtie.rb#L35-L41) This allows us to get rid of any Spring-specific logic in the railtie, since [Spring hooks into the application reloader](https://github.com/rails/spring/blob/0c711ff10b4ad7dcc34282b5e08573c2ce1e668a/lib/spring/application.rb#L161). This partly solves #211, since we no longer call `FactoryBot.reload` at all in `after_initialize`. Instead, we will only call it when one of the files in `definition_file_paths` gets updated. I say it partly solves #211 because once a definition file gets updated, reloading would still give warnings about redefining any constants in the definition files. I wonder how common it is to define constants in the same file as factory definitions. It's probably better to keep constants in the autoload path, allowing Rails to handle unloading and reloading them in development. I would want to see some specific examples before worrying too much about it. I would also like to offer a better way to configure the definition file paths (see #165 and #166) and possibly an option to opt out of loading definitions at all (could help with issues like #192). A couple of quirks here: * the to_prepare block could potentially get [called multiple times](https://github.com/rails/rails/issues/28108). It shouldn't matter, since `execute_if_updated` is a no-op if no updates have been made. * I noticed that the first time I call `reload!` in the console the factory definitions get reloaded even when I made no updates to the definition files. I think it is related to [this](https://github.com/rails/rails/blob/f7c5a8ce262cf16ad8d7c0b0d631a4b88afec414/activesupport/lib/active_support/evented_file_update_checker.rb#L18). After the first call `reload!` works as expected, only reloading the factory definitions if the definition files were updated. * Rails uses execute rather than execute_if_updated for the [route reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L133) and for the [watchable file reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L173). This means that changes to factory definitions will cause reloading of the whole application. I think this is fine.
2018-07-16 18:31:25 -04:00
register_reloader(build_reloader)
end
private
attr_reader :app, :config
def build_reloader
reloader_class.new(@paths.files, @paths.directories) do
Allow reloading of factory definitions Closes #236 This commit uses ActiveSupport's FileUpdateChecker to allow reloading FactoryBot of definitions whenever a file in `FactoryBot.definition_file_paths` gets updated. This is similar to reloading for [I18n](https://github.com/rails/rails/blob/ced104d57997c7bceef3d1e6c8a713431363c3bb/activesupport/lib/active_support/i18n_railtie.rb#L60-L70) and [react rails](https://github.com/reactjs/react-rails/blob/83b6175460b6fd19d667854ebea4777d8c73705a/lib/react/rails/railtie.rb#L35-L41) This allows us to get rid of any Spring-specific logic in the railtie, since [Spring hooks into the application reloader](https://github.com/rails/spring/blob/0c711ff10b4ad7dcc34282b5e08573c2ce1e668a/lib/spring/application.rb#L161). This partly solves #211, since we no longer call `FactoryBot.reload` at all in `after_initialize`. Instead, we will only call it when one of the files in `definition_file_paths` gets updated. I say it partly solves #211 because once a definition file gets updated, reloading would still give warnings about redefining any constants in the definition files. I wonder how common it is to define constants in the same file as factory definitions. It's probably better to keep constants in the autoload path, allowing Rails to handle unloading and reloading them in development. I would want to see some specific examples before worrying too much about it. I would also like to offer a better way to configure the definition file paths (see #165 and #166) and possibly an option to opt out of loading definitions at all (could help with issues like #192). A couple of quirks here: * the to_prepare block could potentially get [called multiple times](https://github.com/rails/rails/issues/28108). It shouldn't matter, since `execute_if_updated` is a no-op if no updates have been made. * I noticed that the first time I call `reload!` in the console the factory definitions get reloaded even when I made no updates to the definition files. I think it is related to [this](https://github.com/rails/rails/blob/f7c5a8ce262cf16ad8d7c0b0d631a4b88afec414/activesupport/lib/active_support/evented_file_update_checker.rb#L18). After the first call `reload!` works as expected, only reloading the factory definitions if the definition files were updated. * Rails uses execute rather than execute_if_updated for the [route reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L133) and for the [watchable file reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L173). This means that changes to factory definitions will cause reloading of the whole application. I think this is fine.
2018-07-16 18:31:25 -04:00
FactoryBot.reload
end
end
def reloader_class
app.config.file_watcher
end
def register_reloader(reloader)
Ensure factory_bot only loads after initialization Fixes #336 Alternate solution to #343 The initialization process looks like this: Rails runs all of the initializers 1. Run the ["factory_bot.set_factory_paths"][set_factory_paths] initializer 2. Run the ["factory_bot.register_reloader"][register_reloader] initializer, which sets up a [prepare callback][] 3. Run the [`:run_prepare_callbacks`][] initializer 4. This triggers the factory_bot [prepare callback][], which causes factory\_bot to [reload][] Rails runs `after_initialize` callbacks 1. [I18n initializes] 2. factory\_bot [reloads again][] as described in #334 The double reloading of factory_bot in this initialization is not ideal, but also shouldn't generally cause any problems on its own. The problems people are having in #336 come from the fact that I18n gets set up in an `after_initialize` callback, but factory_bot gets reloaded before the `after_initialize` callbacks are triggered. If the `FactoryBot.define` block references any code that uses I18n translations as it loads, that code will raise an error (references inside other factory_bot methods, or code that uses I18n translations inside of methods still works fine, since the whole Rails initialization process would be complete by the time any of that code runs). This commit changes step 4 above to avoid reloading factory_bot before the application has initialized. [set_factory_paths]: https://github.com/thoughtbot/factory_bot_rails/blob/3815aae2b9e4a5c5c3027a2ee8851f44b7c6a4da/lib/factory_bot_rails/railtie.rb#L17-L19 [register_reloader]: https://github.com/thoughtbot/factory_bot_rails/blob/3815aae2b9e4a5c5c3027a2ee8851f44b7c6a4da/lib/factory_bot_rails/railtie.rb#L21-L23 [prepare callback]: https://github.com/thoughtbot/factory_bot_rails/blob/master/lib/factory_bot_rails/reloader.rb#L34-L36 [`:run_prepare_callbacks`]: https://github.com/rails/rails/blob/5-2-stable/railties/lib/rails/application/finisher.rb#L62-L64 [reload]: https://github.com/thoughtbot/factory_bot_rails/blob/master/lib/factory_bot_rails/reloader.rb#L24-L26 [I18n initializes]: https://github.com/rails/rails/blob/13e2102517fafc8f8736fce5d57de901067202d0/activesupport/lib/active_support/i18n_railtie.rb#L16-L20 [reloads again]: https://github.com/thoughtbot/factory_bot_rails/blob/master/lib/factory_bot_rails/railtie.rb#L25-L27 Co-authored-by: Danny Garcia <dannygarcia.me@gmail.com>
2019-09-20 15:59:39 -04:00
closed_over_app = app
Allow reloading of factory definitions Closes #236 This commit uses ActiveSupport's FileUpdateChecker to allow reloading FactoryBot of definitions whenever a file in `FactoryBot.definition_file_paths` gets updated. This is similar to reloading for [I18n](https://github.com/rails/rails/blob/ced104d57997c7bceef3d1e6c8a713431363c3bb/activesupport/lib/active_support/i18n_railtie.rb#L60-L70) and [react rails](https://github.com/reactjs/react-rails/blob/83b6175460b6fd19d667854ebea4777d8c73705a/lib/react/rails/railtie.rb#L35-L41) This allows us to get rid of any Spring-specific logic in the railtie, since [Spring hooks into the application reloader](https://github.com/rails/spring/blob/0c711ff10b4ad7dcc34282b5e08573c2ce1e668a/lib/spring/application.rb#L161). This partly solves #211, since we no longer call `FactoryBot.reload` at all in `after_initialize`. Instead, we will only call it when one of the files in `definition_file_paths` gets updated. I say it partly solves #211 because once a definition file gets updated, reloading would still give warnings about redefining any constants in the definition files. I wonder how common it is to define constants in the same file as factory definitions. It's probably better to keep constants in the autoload path, allowing Rails to handle unloading and reloading them in development. I would want to see some specific examples before worrying too much about it. I would also like to offer a better way to configure the definition file paths (see #165 and #166) and possibly an option to opt out of loading definitions at all (could help with issues like #192). A couple of quirks here: * the to_prepare block could potentially get [called multiple times](https://github.com/rails/rails/issues/28108). It shouldn't matter, since `execute_if_updated` is a no-op if no updates have been made. * I noticed that the first time I call `reload!` in the console the factory definitions get reloaded even when I made no updates to the definition files. I think it is related to [this](https://github.com/rails/rails/blob/f7c5a8ce262cf16ad8d7c0b0d631a4b88afec414/activesupport/lib/active_support/evented_file_update_checker.rb#L18). After the first call `reload!` works as expected, only reloading the factory definitions if the definition files were updated. * Rails uses execute rather than execute_if_updated for the [route reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L133) and for the [watchable file reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L173). This means that changes to factory definitions will cause reloading of the whole application. I think this is fine.
2018-07-16 18:31:25 -04:00
config.to_prepare do
Ensure factory_bot only loads after initialization Fixes #336 Alternate solution to #343 The initialization process looks like this: Rails runs all of the initializers 1. Run the ["factory_bot.set_factory_paths"][set_factory_paths] initializer 2. Run the ["factory_bot.register_reloader"][register_reloader] initializer, which sets up a [prepare callback][] 3. Run the [`:run_prepare_callbacks`][] initializer 4. This triggers the factory_bot [prepare callback][], which causes factory\_bot to [reload][] Rails runs `after_initialize` callbacks 1. [I18n initializes] 2. factory\_bot [reloads again][] as described in #334 The double reloading of factory_bot in this initialization is not ideal, but also shouldn't generally cause any problems on its own. The problems people are having in #336 come from the fact that I18n gets set up in an `after_initialize` callback, but factory_bot gets reloaded before the `after_initialize` callbacks are triggered. If the `FactoryBot.define` block references any code that uses I18n translations as it loads, that code will raise an error (references inside other factory_bot methods, or code that uses I18n translations inside of methods still works fine, since the whole Rails initialization process would be complete by the time any of that code runs). This commit changes step 4 above to avoid reloading factory_bot before the application has initialized. [set_factory_paths]: https://github.com/thoughtbot/factory_bot_rails/blob/3815aae2b9e4a5c5c3027a2ee8851f44b7c6a4da/lib/factory_bot_rails/railtie.rb#L17-L19 [register_reloader]: https://github.com/thoughtbot/factory_bot_rails/blob/3815aae2b9e4a5c5c3027a2ee8851f44b7c6a4da/lib/factory_bot_rails/railtie.rb#L21-L23 [prepare callback]: https://github.com/thoughtbot/factory_bot_rails/blob/master/lib/factory_bot_rails/reloader.rb#L34-L36 [`:run_prepare_callbacks`]: https://github.com/rails/rails/blob/5-2-stable/railties/lib/rails/application/finisher.rb#L62-L64 [reload]: https://github.com/thoughtbot/factory_bot_rails/blob/master/lib/factory_bot_rails/reloader.rb#L24-L26 [I18n initializes]: https://github.com/rails/rails/blob/13e2102517fafc8f8736fce5d57de901067202d0/activesupport/lib/active_support/i18n_railtie.rb#L16-L20 [reloads again]: https://github.com/thoughtbot/factory_bot_rails/blob/master/lib/factory_bot_rails/railtie.rb#L25-L27 Co-authored-by: Danny Garcia <dannygarcia.me@gmail.com>
2019-09-20 15:59:39 -04:00
if closed_over_app.initialized?
reloader.execute
end
Allow reloading of factory definitions Closes #236 This commit uses ActiveSupport's FileUpdateChecker to allow reloading FactoryBot of definitions whenever a file in `FactoryBot.definition_file_paths` gets updated. This is similar to reloading for [I18n](https://github.com/rails/rails/blob/ced104d57997c7bceef3d1e6c8a713431363c3bb/activesupport/lib/active_support/i18n_railtie.rb#L60-L70) and [react rails](https://github.com/reactjs/react-rails/blob/83b6175460b6fd19d667854ebea4777d8c73705a/lib/react/rails/railtie.rb#L35-L41) This allows us to get rid of any Spring-specific logic in the railtie, since [Spring hooks into the application reloader](https://github.com/rails/spring/blob/0c711ff10b4ad7dcc34282b5e08573c2ce1e668a/lib/spring/application.rb#L161). This partly solves #211, since we no longer call `FactoryBot.reload` at all in `after_initialize`. Instead, we will only call it when one of the files in `definition_file_paths` gets updated. I say it partly solves #211 because once a definition file gets updated, reloading would still give warnings about redefining any constants in the definition files. I wonder how common it is to define constants in the same file as factory definitions. It's probably better to keep constants in the autoload path, allowing Rails to handle unloading and reloading them in development. I would want to see some specific examples before worrying too much about it. I would also like to offer a better way to configure the definition file paths (see #165 and #166) and possibly an option to opt out of loading definitions at all (could help with issues like #192). A couple of quirks here: * the to_prepare block could potentially get [called multiple times](https://github.com/rails/rails/issues/28108). It shouldn't matter, since `execute_if_updated` is a no-op if no updates have been made. * I noticed that the first time I call `reload!` in the console the factory definitions get reloaded even when I made no updates to the definition files. I think it is related to [this](https://github.com/rails/rails/blob/f7c5a8ce262cf16ad8d7c0b0d631a4b88afec414/activesupport/lib/active_support/evented_file_update_checker.rb#L18). After the first call `reload!` works as expected, only reloading the factory definitions if the definition files were updated. * Rails uses execute rather than execute_if_updated for the [route reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L133) and for the [watchable file reloader](https://github.com/rails/rails/blob/master/railties/lib/rails/application/finisher.rb#L173). This means that changes to factory definitions will cause reloading of the whole application. I think this is fine.
2018-07-16 18:31:25 -04:00
end
app.reloaders << reloader
end
end
end