diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md index 12db528b91..a39dd9ace0 100644 --- a/guides/source/4_2_release_notes.md +++ b/guides/source/4_2_release_notes.md @@ -85,6 +85,9 @@ Please refer to the [Changelog][railties] for detailed changes. * Introduced `Rails.gem_version` as a convenience method to return `Gem::Version.new(Rails.version)`. ([Pull Request](https://github.com/rails/rails/pull/14101)) +* Introduced an `after_bundle` callback in the Rails templates. + ([Pull Request](https://github.com/rails/rails/pull/16359)) + Action Pack ----------- diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md index 0bd608c007..6512b14e60 100644 --- a/guides/source/rails_application_templates.md +++ b/guides/source/rails_application_templates.md @@ -38,9 +38,11 @@ generate(:scaffold, "person name:string") route "root to: 'people#index'" rake("db:migrate") -git :init -git add: "." -git commit: %Q{ -m 'Initial commit' } +after_bundle do + git :init + git add: "." + git commit: %Q{ -m 'Initial commit' } +end ``` The following sections outline the primary methods provided by the API: @@ -228,6 +230,22 @@ git add: "." git commit: "-a -m 'Initial commit'" ``` +### after_bundle(&block) + +Registers a callback to be executed after the gems are bundled and binstubs +are generated. Useful for all generated files to version control: + +```ruby +after_bundle do + git :init + git add: '.' + git commit: "-a -m 'Initial commit'" +end +``` + +The callbacks gets executed even if `--skip-bundle` and/or `--skip-spring` has +been passed. + Advanced Usage -------------- diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index b3e4505fc0..62e4071935 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -58,6 +58,38 @@ When assigning `nil` to a serialized attribute, it will be saved to the database as `NULL` instead of passing the `nil` value through the coder (e.g. `"null"` when using the `JSON` coder). +### `after_bundle` in Rails templates + +If you have a Rails template that adds all the files in version control, it +fails to add the generated binstubs because it gets executed before Bundler: + +```ruby +# template.rb +generate(:scaffold, "person name:string") +route "root to: 'people#index'" +rake("db:migrate") + +git :init +git add: "." +git commit: %Q{ -m 'Initial commit' } +``` + +You can now wrap the `git` calls in an `after_bundle` block. It will be run +after the binstubs have been generated. + +```ruby +# template.rb +generate(:scaffold, "person name:string") +route "root to: 'people#index'" +rake("db:migrate") + +after_bundle do + git :init + git add: "." + git commit: %Q{ -m 'Initial commit' } +end +``` + Upgrading from Rails 4.0 to Rails 4.1 ------------------------------------- diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index dac554e015..1ccdfb6589 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,10 @@ +* Add `after_bundle` callbacks in Rails templates. Useful for allowing the + generated binstubs to be added to version control. + + Fixes #16292. + + *Stefan Kanev* + * Pull in the custom configuration concept from dhh/custom_configuration, which allows you to configure your own code through the Rails configuration object with custom configuration: diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index a239874df0..4709914947 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -7,6 +7,7 @@ module Rails def initialize(*) # :nodoc: super @in_group = nil + @after_bundle_callbacks = [] end # Adds an entry into +Gemfile+ for the supplied gem. @@ -232,6 +233,16 @@ module Rails log File.read(find_in_source_paths(path)) end + # Registers a callback to be executed after bundle and spring binstubs + # have run. + # + # after_bundle do + # git add: '.' + # end + def after_bundle(&block) + @after_bundle_callbacks << block + end + protected # Define log for backwards compatibility. If just one argument is sent, diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 188e62b6c8..9110c129d1 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -259,6 +259,12 @@ module Rails public_task :apply_rails_template, :run_bundle public_task :generate_spring_binstubs + def run_after_bundle_callbacks + @after_bundle_callbacks.each do |callback| + callback.call + end + end + protected def self.banner diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 184cfc2220..3f31f89473 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -501,6 +501,21 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_after_bundle_callback + path = 'http://example.org/rails_template' + template = %{ after_bundle { run 'echo ran after_bundle' } } + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + + bundler_first = sequence('bundle, binstubs, after_bundle') + generator.expects(:bundle_command).with('install').once.in_sequence(bundler_first) + generator.expects(:bundle_command).with('exec spring binstub --all').in_sequence(bundler_first) + generator.expects(:run).with('echo ran after_bundle').in_sequence(bundler_first) + + quietly { generator.invoke_all } + end + protected def action(*args, &block)