aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionpack/CHANGELOG.md8
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb56
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb7
-rw-r--r--actionpack/test/dispatch/request_test.rb5
-rw-r--r--actionview/CHANGELOG.md12
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb6
-rw-r--r--actionview/test/activerecord/polymorphic_routes_test.rb33
-rw-r--r--actionview/test/template/asset_tag_helper_test.rb8
-rw-r--r--actionview/test/template/test_test.rb16
-rw-r--r--activemodel/CHANGELOG.md7
-rw-r--r--activemodel/lib/active_model/locale/en.yml12
-rw-r--r--activemodel/test/cases/validations/i18n_generate_message_validation_test.rb18
-rw-r--r--activerecord/CHANGELOG.md21
-rw-r--r--activerecord/lib/active_record/autosave_association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb9
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb6
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb15
-rw-r--r--activerecord/test/cases/adapters/mysql/connection_test.rb8
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb8
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb2
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb15
-rw-r--r--activerecord/test/cases/associations/callbacks_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb8
-rw-r--r--activerecord/test/cases/dup_test.rb9
-rw-r--r--activerecord/test/cases/persistence_test.rb11
-rw-r--r--guides/source/_license.html.erb2
-rw-r--r--guides/source/_welcome.html.erb8
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md63
-rw-r--r--guides/source/security.md4
-rw-r--r--railties/CHANGELOG.md6
-rw-r--r--railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb5
-rw-r--r--railties/lib/rails/generators/rails/plugin/plugin_generator.rb22
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec4
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE2
-rw-r--r--railties/test/generators/plugin_generator_test.rb34
39 files changed, 353 insertions, 119 deletions
diff --git a/Gemfile b/Gemfile
index 120c4bca8f..e7bc2585a7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,7 +11,7 @@ gem 'rack-cache', '~> 1.2'
gem 'jquery-rails', '~> 3.1.0'
gem 'turbolinks'
gem 'coffee-rails', '~> 4.0.0'
-gem 'arel', github: 'rails/arel'
+gem 'arel', github: 'rails/arel', branch: 'master'
gem 'sprockets-rails', github: 'rails/sprockets-rails', branch: '2-1-stable'
# require: false so bcrypt is loaded only when has_secure_password is used.
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 15833641bb..fd3f9eb72d 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Properly treat the entire IPv6 User Local Address space as private for
+ purposes of remote IP detection. Also handle uppercase private IPv6
+ addresses.
+
+ Fixes #12638.
+
+ *Caleb Spare*
+
* Fixed an issue with migrating legacy json cookies.
Previously, the `VerifyAndUpgradeLegacySignedMessage` assumes all incoming
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index c1df518b14..cbb066b092 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -31,7 +31,7 @@ module ActionDispatch
TRUSTED_PROXIES = %r{
^127\.0\.0\.1$ | # localhost IPv4
^::1$ | # localhost IPv6
- ^fc00: | # private IPv6 range fc00
+ ^[fF][cCdD] | # private IPv6 range fc00::/7
^10\. | # private IPv4 range 10.x.x.x
^172\.(1[6-9]|2[0-9]|3[0-1])\.| # private IPv4 range 172.16.0.0 .. 172.31.255.255
^192\.168\. # private IPv4 range 192.168.x.x
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 77718a14c1..400956adee 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -340,18 +340,34 @@ module ActionDispatch
match '/', { :as => :root, :via => :get }.merge!(options)
end
- # Matches a url pattern to one or more routes. Any symbols in a pattern
- # are interpreted as url query parameters and thus available as +params+
- # in an action:
+ # Matches a url pattern to one or more routes.
+ #
+ # You should not use the `match` method in your router
+ # without specifying an HTTP method.
+ #
+ # If you want to expose your action to both GET and POST, use:
#
# # sets :controller, :action and :id in params
- # match ':controller/:action/:id'
+ # match ':controller/:action/:id', via: [:get, :post]
+ #
+ # Note that +:controller+, +:action+ and +:id+ are interpreted as url
+ # query parameters and thus available through +params+ in an action.
+ #
+ # If you want to expose your action to GET, use `get` in the router:
+ #
+ # Instead of:
+ #
+ # match ":controller/:action/:id"
+ #
+ # Do:
+ #
+ # get ":controller/:action/:id"
#
# Two of these symbols are special, +:controller+ maps to the controller
# and +:action+ to the controller's action. A pattern can also map
# wildcard segments (globs) to params:
#
- # match 'songs/*category/:title', to: 'songs#show'
+ # get 'songs/*category/:title', to: 'songs#show'
#
# # 'songs/rock/classic/stairway-to-heaven' sets
# # params[:category] = 'rock/classic'
@@ -364,17 +380,17 @@ module ActionDispatch
# When a pattern points to an internal route, the route's +:action+ and
# +:controller+ should be set in options or hash shorthand. Examples:
#
- # match 'photos/:id' => 'photos#show'
- # match 'photos/:id', to: 'photos#show'
- # match 'photos/:id', controller: 'photos', action: 'show'
+ # match 'photos/:id' => 'photos#show', via: :get
+ # match 'photos/:id', to: 'photos#show', via: :get
+ # match 'photos/:id', controller: 'photos', action: 'show', via: :get
#
# A pattern can also point to a +Rack+ endpoint i.e. anything that
# responds to +call+:
#
- # match 'photos/:id', to: lambda {|hash| [200, {}, ["Coming soon"]] }
- # match 'photos/:id', to: PhotoRackApp
+ # match 'photos/:id', to: lambda {|hash| [200, {}, ["Coming soon"]] }, via: :get
+ # match 'photos/:id', to: PhotoRackApp, via: :get
# # Yes, controller actions are just rack endpoints
- # match 'photos/:id', to: PhotosController.action(:show)
+ # match 'photos/:id', to: PhotosController.action(:show), via: :get
#
# Because requesting various HTTP verbs with a single action has security
# implications, you must either specify the actions in
@@ -397,7 +413,7 @@ module ActionDispatch
# [:module]
# The namespace for :controller.
#
- # match 'path', to: 'c#a', module: 'sekret', controller: 'posts'
+ # match 'path', to: 'c#a', module: 'sekret', controller: 'posts', via: :get
# # => Sekret::PostsController
#
# See <tt>Scoping#namespace</tt> for its scope equivalent.
@@ -416,9 +432,9 @@ module ActionDispatch
# Points to a +Rack+ endpoint. Can be an object that responds to
# +call+ or a string representing a controller's action.
#
- # match 'path', to: 'controller#action'
- # match 'path', to: lambda { |env| [200, {}, ["Success!"]] }
- # match 'path', to: RackApp
+ # match 'path', to: 'controller#action', via: :get
+ # match 'path', to: lambda { |env| [200, {}, ["Success!"]] }, via: :get
+ # match 'path', to: RackApp, via: :get
#
# [:on]
# Shorthand for wrapping routes in a specific RESTful context. Valid
@@ -443,14 +459,14 @@ module ActionDispatch
# other than path can also be specified with any object
# that responds to <tt>===</tt> (eg. String, Array, Range, etc.).
#
- # match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }
+ # match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }, via: :get
#
- # match 'json_only', constraints: { format: 'json' }
+ # match 'json_only', constraints: { format: 'json' }, via: :get
#
# class Whitelist
# def matches?(request) request.remote_ip == '1.2.3.4' end
# end
- # match 'path', to: 'c#a', constraints: Whitelist.new
+ # match 'path', to: 'c#a', constraints: Whitelist.new, via: :get
#
# See <tt>Scoping#constraints</tt> for more examples with its scope
# equivalent.
@@ -459,7 +475,7 @@ module ActionDispatch
# Sets defaults for parameters
#
# # Sets params[:format] to 'jpg' by default
- # match 'path', to: 'c#a', defaults: { format: 'jpg' }
+ # match 'path', to: 'c#a', defaults: { format: 'jpg' }, via: :get
#
# See <tt>Scoping#defaults</tt> for its scope equivalent.
#
@@ -468,7 +484,7 @@ module ActionDispatch
# false, the pattern matches any request prefixed with the given path.
#
# # Matches any request starting with 'path'
- # match 'path', to: 'c#a', anchor: false
+ # match 'path', to: 'c#a', anchor: false, via: :get
#
# [:format]
# Allows you to specify the default value for optional +format+
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index cfd33d1f31..b800ee6448 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -104,7 +104,10 @@ module ActionDispatch
recipient = self
if record_or_hash_or_array.kind_of?(Array)
- record_or_hash_or_array = record_or_hash_or_array.compact
+ if record_or_hash_or_array.include? nil
+ raise ArgumentError, "Nil location provided. Can't build URI."
+ end
+ record_or_hash_or_array = record_or_hash_or_array.dup
if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
recipient = record_or_hash_or_array.shift
end
@@ -136,7 +139,7 @@ module ActionDispatch
url_options = options.except(:action, :routing_type)
unless url_options.empty?
- args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
+ args << url_options
end
args.collect! { |a| convert_to_model(a) }
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 6e21b4a258..b48e8ab974 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -152,9 +152,12 @@ class RequestIP < BaseRequestTest
request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,::1'
assert_equal nil, request.remote_ip
- request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::'
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::, fc01::, fdff'
assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'FE00::, FDFF::'
+ assert_equal 'FE00::', request.remote_ip
+
request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address'
assert_equal nil, request.remote_ip
end
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 50ca64d536..bedbf78172 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,8 +1,18 @@
+* Change `asset_path` to use File.join to create proper paths:
+
+ https://some.host.com//assets/some.js
+
+ becomes
+
+ https://some.host.com/assets/some.js
+
+ *Peter Schröder*
+
* Change `favicon_link_tag` default mimetype from `image/vnd.microsoft.icon` to
`image/x-icon`.
Before:
-
+
#=> favicon_link_tag 'myicon.ico'
<link href="/assets/myicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index c830ab23e3..41997a85b3 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -134,11 +134,11 @@ module ActionView
relative_url_root = defined?(config.relative_url_root) && config.relative_url_root
if relative_url_root
- source = "#{relative_url_root}#{source}" unless source.starts_with?("#{relative_url_root}/")
+ source = File.join(relative_url_root, source) unless source.starts_with?("#{relative_url_root}/")
end
if host = compute_asset_host(source, options)
- source = "#{host}#{source}"
+ source = File.join(host, source)
end
"#{source}#{tail}"
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index 8f10eb46ad..10dcb5c28c 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -83,13 +83,17 @@ module ActionView
# * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
# * <tt>:include_blank</tt> - If set to true, an empty option will be created.
- # * <tt>:prompt</tt> - Create a prompt option with blank value and the text asking user to select something
+ # * <tt>:prompt</tt> - Create a prompt option with blank value and the text asking user to select something.
+ # * <tt>:selected</tt> - Provide a default selected value. It should be of the exact type as the provided options.
# * Any other key creates standard HTML attributes for the tag.
#
# ==== Examples
# select_tag "people", options_from_collection_for_select(@people, "id", "name")
# # <select id="people" name="people"><option value="1">David</option></select>
#
+ # select_tag "people", options_from_collection_for_select(@people, "id", "name"), selected: ["1", "David"]
+ # # <select id="people" name="people"><option value="1" selected="selected">David</option></select>
+ #
# select_tag "people", "<option>David</option>".html_safe
# # => <select id="people" name="people"><option>David</option></select>
#
diff --git a/actionview/test/activerecord/polymorphic_routes_test.rb b/actionview/test/activerecord/polymorphic_routes_test.rb
index afb714484b..1ead18518a 100644
--- a/actionview/test/activerecord/polymorphic_routes_test.rb
+++ b/actionview/test/activerecord/polymorphic_routes_test.rb
@@ -112,6 +112,31 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
+ def test_with_empty_list
+ with_test_routes do
+ assert_raise ArgumentError, "Nil location provided. Can't build URI." do
+ polymorphic_url([])
+ end
+ end
+ end
+
+ def test_with_nil_id
+ with_test_routes do
+ assert_raise ArgumentError, "Nil location provided. Can't build URI." do
+ polymorphic_url({ :id => nil })
+ end
+ end
+ end
+
+ def test_with_nil_in_list
+ with_test_routes do
+ assert_raise ArgumentError, "Nil location provided. Can't build URI." do
+ @series.save
+ polymorphic_url([nil, @series])
+ end
+ end
+ end
+
def test_with_record
with_test_routes do
@project.save
@@ -295,17 +320,17 @@ class PolymorphicRoutesTest < ActionController::TestCase
end
end
- def test_nesting_with_array_containing_nil
+ def test_nesting_with_array
with_test_routes do
@project.save
- assert_equal "http://example.com/projects/#{@project.id}/bid", polymorphic_url([@project, nil, :bid])
+ assert_equal "http://example.com/projects/#{@project.id}/bid", polymorphic_url([@project, :bid])
end
end
def test_with_array_containing_single_object
with_test_routes do
@project.save
- assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url([nil, @project])
+ assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url([@project])
end
end
@@ -438,7 +463,7 @@ class PolymorphicRoutesTest < ActionController::TestCase
def test_with_array_containing_single_irregular_plural_object
with_test_routes do
@tax.save
- assert_equal "http://example.com/taxes/#{@tax.id}", polymorphic_url([nil, @tax])
+ assert_equal "http://example.com/taxes/#{@tax.id}", polymorphic_url([@tax])
end
end
diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb
index 651978ed80..18e4277d7a 100644
--- a/actionview/test/template/asset_tag_helper_test.rb
+++ b/actionview/test/template/asset_tag_helper_test.rb
@@ -309,6 +309,14 @@ class AssetTagHelperTest < ActionView::TestCase
AssetPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
+ def test_asset_path_tag_to_not_create_duplicate_slashes
+ @controller.config.asset_host = "host/"
+ assert_dom_equal('http://host/foo', asset_path("foo"))
+
+ @controller.config.relative_url_root = '/some/root/'
+ assert_dom_equal('http://host/some/root/foo', asset_path("foo"))
+ end
+
def test_compute_asset_public_path
assert_equal "/robots.txt", compute_asset_path("robots.txt")
assert_equal "/robots.txt", compute_asset_path("/robots.txt")
diff --git a/actionview/test/template/test_test.rb b/actionview/test/template/test_test.rb
index 108a674d95..5721ee6c6f 100644
--- a/actionview/test/template/test_test.rb
+++ b/actionview/test/template/test_test.rb
@@ -37,10 +37,20 @@ class PeopleHelperTest < ActionView::TestCase
def test_link_to_person
with_test_route_set do
- person = mock(:name => "David")
- person.class.extend ActiveModel::Naming
- expects(:mocha_mock_path).with(person).returns("/people/1")
+ person = Struct.new(:name) {
+ extend ActiveModel::Naming
+ def self.name; 'Mocha::Mock'; end
+ }.new "David"
+
+ the_model = nil
+ extend Module.new {
+ define_method(:mocha_mock_path) { |model, *args|
+ the_model = model
+ "/people/1"
+ }
+ }
assert_equal '<a href="/people/1">David</a>', link_to_person(person)
+ assert_equal person, the_model
end
end
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 0db220ab8f..68cc874ca3 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,6 +1,11 @@
+* Add plural and singular form for length validator's default messages
+
+ *Abd ar-Rahman Hamid*
+
* Introduce `validate` as an alias for `valid?`.
- This is more intuitive when you want to run validations but don't care about the return value.
+ This is more intuitive when you want to run validations but don't care about
+ the return value.
*Henrik Nyh*
diff --git a/activemodel/lib/active_model/locale/en.yml b/activemodel/lib/active_model/locale/en.yml
index 540e8132d3..bf07945fe1 100644
--- a/activemodel/lib/active_model/locale/en.yml
+++ b/activemodel/lib/active_model/locale/en.yml
@@ -14,9 +14,15 @@ en:
empty: "can't be empty"
blank: "can't be blank"
present: "must be blank"
- too_long: "is too long (maximum is %{count} characters)"
- too_short: "is too short (minimum is %{count} characters)"
- wrong_length: "is the wrong length (should be %{count} characters)"
+ too_long:
+ one: "is too long (maximum is 1 character)"
+ other: "is too long (maximum is %{count} characters)"
+ too_short:
+ one: "is too short (minimum is 1 character)"
+ other: "is too short (minimum is %{count} characters)"
+ wrong_length:
+ one: "is the wrong length (should be 1 character)"
+ other: "is the wrong length (should be %{count} characters)"
not_a_number: "is not a number"
not_an_integer: "must be an integer"
greater_than: "must be greater than %{count}"
diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
index 93600c587a..3eeb80a48b 100644
--- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
@@ -72,28 +72,40 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
# validates_length_of: generate_message(attr, :too_long, message: custom_message, count: option_value.end)
- def test_generate_message_too_long_with_default_message
+ def test_generate_message_too_long_with_default_message_plural
assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, count: 10)
end
+ def test_generate_message_too_long_with_default_message_singular
+ assert_equal "is too long (maximum is 1 character)", @person.errors.generate_message(:title, :too_long, count: 1)
+ end
+
def test_generate_message_too_long_with_custom_message
assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, message: 'custom message %{count}', count: 10)
end
# validates_length_of: generate_message(attr, :too_short, default: custom_message, count: option_value.begin)
- def test_generate_message_too_short_with_default_message
+ def test_generate_message_too_short_with_default_message_plural
assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, count: 10)
end
+ def test_generate_message_too_short_with_default_message_singular
+ assert_equal "is too short (minimum is 1 character)", @person.errors.generate_message(:title, :too_short, count: 1)
+ end
+
def test_generate_message_too_short_with_custom_message
assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, message: 'custom message %{count}', count: 10)
end
# validates_length_of: generate_message(attr, :wrong_length, message: custom_message, count: option_value)
- def test_generate_message_wrong_length_with_default_message
+ def test_generate_message_wrong_length_with_default_message_plural
assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, count: 10)
end
+ def test_generate_message_wrong_length_with_default_message_singular
+ assert_equal "is the wrong length (should be 1 character)", @person.errors.generate_message(:title, :wrong_length, count: 1)
+ end
+
def test_generate_message_wrong_length_with_custom_message
assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, message: 'custom message %{count}', count: 10)
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index e8e41192de..1f6ce38569 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,10 +1,29 @@
-* Rails will now pass a custom validation context through to autosave associations
+* Rails will now pass a custom validation context through to autosave associations
in order to validate child associations with the same context.
Fixes #13854.
*Eric Chahin*, *Aaron Nelson*, *Kevin Casey*
+* Stringify all variable keys of mysql connection configuration.
+
+ When the `sql_mode` variable for mysql adapters is set in the configuration
+ as a `String`, it was ignored and overwritten by the strict mode option.
+
+ Fixes #14895.
+
+ *Paul Nikitochkin*
+
+* Ensure SQLite3 statements are closed on errors.
+
+ Fixes #13631.
+
+ *Timur Alperovich*
+
+* Give ActiveRecord::PredicateBuilder private methods the privacy they deserve.
+
+ *Hector Satre*
+
* When using a custom `join_table` name on a `habtm`, rails was not saving it
on Reflections. This causes a problem when rails loads fixtures, because it
uses the reflections to set database with fixtures.
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index a30e5e4579..80cf7572df 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -304,7 +304,7 @@ module ActiveRecord
def association_valid?(reflection, record)
return true if record.destroyed? || record.marked_for_destruction?
- validation_context = self.validation_context unless [:create,:update].include?(self.validation_context)
+ validation_context = self.validation_context unless [:create, :update].include?(self.validation_context)
unless valid = record.valid?(validation_context)
if reflection.options[:autosave]
record.errors.each do |attribute, message|
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 75c58ac7d9..ebce0c0460 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -765,22 +765,22 @@ module ActiveRecord
end
def configure_connection
- variables = @config[:variables] || {}
+ variables = @config.fetch(:variables, {}).stringify_keys
# By default, MySQL 'where id is null' selects the last inserted id.
# Turn this off. http://dev.rubyonrails.org/ticket/6778
- variables[:sql_auto_is_null] = 0
+ variables['sql_auto_is_null'] = 0
# Increase timeout so the server doesn't disconnect us.
wait_timeout = @config[:wait_timeout]
wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
- variables[:wait_timeout] = self.class.type_cast_config_to_integer(wait_timeout)
+ variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout)
# Make MySQL reject illegal values rather than truncating or blanking them, see
# http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_all_tables
# If the user has provided another value for sql_mode, don't replace it.
- if strict_mode? && !variables.has_key?(:sql_mode)
- variables[:sql_mode] = 'STRICT_ALL_TABLES'
+ if strict_mode? && !variables.has_key?('sql_mode')
+ variables['sql_mode'] = 'STRICT_ALL_TABLES'
end
# NAMES does not have an equals sign, see
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index dd4261cec7..2c6186774f 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -296,9 +296,12 @@ module ActiveRecord
# Don't cache statements if they are not prepared
if without_prepared_statement?(binds)
stmt = @connection.prepare(sql)
- cols = stmt.columns
- records = stmt.to_a
- stmt.close
+ begin
+ cols = stmt.columns
+ records = stmt.to_a
+ ensure
+ stmt.close
+ end
stmt = records
else
cache = @statements[sql] ||= {
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 0b56430b34..42c9881b48 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -242,7 +242,7 @@ module ActiveRecord
return 0 if relation.limit_value == 0
query_builder = build_count_subquery(relation, column_name, distinct)
- bind_values = relation.bind_values
+ bind_values = query_builder.bind_values + relation.bind_values
else
column = aggregate_column(column_name)
@@ -389,9 +389,11 @@ module ActiveRecord
aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
relation.select_values = [aliased_column]
- subquery = relation.arel.as(subquery_alias)
+ arel = relation.arel
+ subquery = arel.as(subquery_alias)
sm = Arel::SelectManager.new relation.engine
+ sm.bind_values = arel.bind_values
select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
sm.project(select_value).from(subquery)
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 1252af7635..d40f276968 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -113,13 +113,14 @@ module ActiveRecord
register_handler(Relation, RelationHandler.new)
register_handler(Array, ArrayHandler.new)
- private
- def self.build(attribute, value)
- handler_for(value).call(attribute, value)
- end
+ def self.build(attribute, value)
+ handler_for(value).call(attribute, value)
+ end
+ private_class_method :build
- def self.handler_for(object)
- @handlers.detect { |klass, _| klass === object }.last
- end
+ def self.handler_for(object)
+ @handlers.detect { |klass, _| klass === object }.last
+ end
+ private_class_method :handler_for
end
end
diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb
index 412efa22ff..4c90d06732 100644
--- a/activerecord/test/cases/adapters/mysql/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql/connection_test.rb
@@ -151,6 +151,14 @@ class MysqlConnectionTest < ActiveRecord::TestCase
end
end
+ def test_mysql_sql_mode_variable_overides_strict_mode
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { 'sql_mode' => 'ansi' }))
+ result = ActiveRecord::Base.connection.exec_query 'SELECT @@SESSION.sql_mode'
+ assert_not_equal [['STRICT_ALL_TABLES']], result.rows
+ end
+ end
+
def test_mysql_set_session_variable_to_default
run_without_connection do |orig_connection|
ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:default_week_format => :default}}))
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index 182d9409c7..65f50e77bb 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -77,6 +77,14 @@ class MysqlConnectionTest < ActiveRecord::TestCase
end
end
+ def test_mysql_sql_mode_variable_overides_strict_mode
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { 'sql_mode' => 'ansi' }))
+ result = ActiveRecord::Base.connection.exec_query 'SELECT @@SESSION.sql_mode'
+ assert_not_equal [['STRICT_ALL_TABLES']], result.rows
+ end
+ end
+
def test_mysql_set_session_variable_to_default
run_without_connection do |orig_connection|
ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:default_week_format => :default}}))
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index ba89487838..e4b69fdf7b 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -100,7 +100,7 @@ module ActiveRecord
def quoted_id
"'zomg'"
end
- }
+ }.new
assert_raise(TypeError) { @conn.type_cast(quoted_id_obj, nil) }
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 2630a0f3a4..e55525177f 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -416,6 +416,21 @@ module ActiveRecord
assert @conn.respond_to?(:disable_extension)
end
+ def test_statement_closed
+ db = SQLite3::Database.new(ActiveRecord::Base.
+ configurations['arunit']['database'])
+ statement = SQLite3::Statement.new(db,
+ 'CREATE TABLE statement_test (number integer not null)')
+ statement.stubs(:step).raises(SQLite3::BusyException, 'busy')
+ statement.stubs(:columns).once.returns([])
+ statement.expects(:close).once
+ SQLite3::Statement.stubs(:new).returns(statement)
+
+ assert_raises ActiveRecord::StatementInvalid do
+ @conn.exec_query 'select * from statement_test'
+ end
+ end
+
private
def assert_logged logs
diff --git a/activerecord/test/cases/associations/callbacks_test.rb b/activerecord/test/cases/associations/callbacks_test.rb
index 968f36e92c..5b7e462f64 100644
--- a/activerecord/test/cases/associations/callbacks_test.rb
+++ b/activerecord/test/cases/associations/callbacks_test.rb
@@ -159,7 +159,7 @@ class AssociationCallbacksTest < ActiveRecord::TestCase
activerecord.reload
assert activerecord.developers_with_callbacks.size == 2
end
- log_array = activerecord.developers_with_callbacks.flat_map {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.sort
+ activerecord.developers_with_callbacks.flat_map {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.sort
assert activerecord.developers_with_callbacks.clear
assert_predicate activerecord.developers_log, :empty?
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 000ea8055a..d748e80695 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -45,12 +45,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :categories, :companies, :developers, :projects,
:developers_projects, :topics, :authors, :comments,
:people, :posts, :readers, :taggings, :cars, :essays,
- :categorizations, :jobs
+ :categorizations, :jobs, :tags, :posts
def setup
Client.destroyed_client_ids.clear
end
+ def test_sti_subselect_count
+ tag = Tag.first
+ len = Post.tagged_with(tag.id).limit(10).size
+ assert_operator len, :>, 0
+ end
+
def test_anonymous_has_many
developer = Class.new(ActiveRecord::Base) {
self.table_name = 'developers'
diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb
index 1e6ccecfab..409d9a82e2 100644
--- a/activerecord/test/cases/dup_test.rb
+++ b/activerecord/test/cases/dup_test.rb
@@ -1,4 +1,5 @@
require "cases/helper"
+require 'models/reply'
require 'models/topic'
module ActiveRecord
@@ -32,6 +33,14 @@ module ActiveRecord
assert duped.new_record?, 'topic is new'
end
+ def test_dup_not_destroyed
+ topic = Topic.first
+ topic.destroy
+
+ duped = topic.dup
+ assert_not duped.destroyed?
+ end
+
def test_dup_has_no_id
topic = Topic.first
duped = topic.dup
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 9209672ac5..823146b399 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -234,19 +234,12 @@ class PersistenceTest < ActiveRecord::TestCase
end
def test_save_with_duping_of_destroyed_object
- developer = Developer.create(name: "Kuldeep")
+ developer = Developer.first
developer.destroy
new_developer = developer.dup
new_developer.save
assert new_developer.persisted?
- end
-
- def test_dup_of_destroyed_object_is_not_destroyed
- developer = Developer.create(name: "Kuldeep")
- developer.destroy
- new_developer = developer.dup
- new_developer.save
- assert_equal new_developer.destroyed?, false
+ assert_not new_developer.destroyed?
end
def test_create_many
diff --git a/guides/source/_license.html.erb b/guides/source/_license.html.erb
index 00b4466f50..d22f016948 100644
--- a/guides/source/_license.html.erb
+++ b/guides/source/_license.html.erb
@@ -1,2 +1,2 @@
-<p>This work is licensed under a <a href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share Alike 3.0</a> License</p>
+<p>This work is licensed under a <a href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International</a> License</p>
<p>"Rails", "Ruby on Rails", and the Rails logo are trademarks of David Heinemeier Hansson. All rights reserved.</p>
diff --git a/guides/source/_welcome.html.erb b/guides/source/_welcome.html.erb
index 7e39f761f2..9101ed60d4 100644
--- a/guides/source/_welcome.html.erb
+++ b/guides/source/_welcome.html.erb
@@ -15,11 +15,5 @@
</p>
<% end %>
<p>
- The guides for Rails 4.0.x are available at <a href="http://guides.rubyonrails.org/v4.0.4/">http://guides.rubyonrails.org/v4.0.4/</a>.
-</p>
-<p>
- The guides for Rails 3.2.x are available at <a href="http://guides.rubyonrails.org/v3.2.17/">http://guides.rubyonrails.org/v3.2.17/</a>.
-</p>
-<p>
- The guides for Rails 2.3.x are available at <a href="http://guides.rubyonrails.org/v2.3.11/">http://guides.rubyonrails.org/v2.3.11/</a>.
+ The guides for earlier releases: <a href="http://guides.rubyonrails.org/v4.1.0/">Rails 4.1.0</a>, <a href="http://guides.rubyonrails.org/v4.0.4/">Rails 4.0.4</a>, <a href="http://guides.rubyonrails.org/v3.2.17/">Rails 3.2.17</a> and <a href="http://guides.rubyonrails.org/v2.3.11/">Rails 2.3.11</a>.
</p>
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index 28e1172274..edcf8fa998 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -144,7 +144,7 @@ WARNING: Docrails has a very strict policy: no code can be touched whatsoever, n
Contributing to the Rails Code
------------------------------
-### Setting Up a Development Environment ###
+### Setting Up a Development Environment
To move on from submitting bugs to helping resolve existing issues or contributing your own code to Ruby on Rails, you _must_ be able to run its test suite. In this section of the guide you'll learn how to setup the tests on your own computer.
@@ -156,7 +156,7 @@ The easiest and recommended way to get a development environment ready to hack i
In case you can't use the Rails development box, see [this other guide](development_dependencies_install.html).
-### Clone the Rails Repository ###
+### Clone the Rails Repository
To be able to contribute code, you need to clone the Rails repository:
@@ -173,7 +173,7 @@ $ git checkout -b my_new_branch
It doesn't matter much what name you use, because this branch will only exist on your local computer and your personal repository on GitHub. It won't be part of the Rails Git repository.
-### Running an Application Against Your Local Branch ###
+### Running an Application Against Your Local Branch
In case you need a dummy Rails app to test changes, the `--dev` flag of `rails new` generates an application that uses your local branch:
@@ -185,9 +185,9 @@ $ bundle exec rails new ~/my-test-app --dev
The application generated in `~/my-test-app` runs against your local branch
and in particular sees any modifications upon server reboot.
-### Write Your Code ###
+### Write Your Code
-Now get busy and add/edit code. You're on your branch now, so you can write whatever you want (you can check to make sure you're on the right branch with `git branch -a`). But if you're planning to submit your change back for inclusion in Rails, keep a few things in mind:
+Now get busy and add/edit code. You're on your branch now, so you can write whatever you want (make sure you're on the right branch with `git branch -a`). But if you're planning to submit your change back for inclusion in Rails, keep a few things in mind:
* Get the code right.
* Use Rails idioms and helpers.
@@ -215,7 +215,8 @@ Rails follows a simple set of coding style conventions:
The above are guidelines - please use your best judgment in using them.
-### Running Tests ###
+### Running Tests
+
It is not customary in Rails to run the full test suite before pushing
changes. The railties test suite in particular takes a long time, and even
more if the source code is mounted in `/vagrant` as happens in the recommended
@@ -228,20 +229,36 @@ tests are passing, that's enough to propose your contribution. We have
unexpected breakages elsewhere.
#### Entire Rails:
+
To run all the tests, do:
+
```bash
$ cd rails
$ bundle exec rake test
```
-#### Particular component of Rails
-To run tests only for particular component(ActionPack, ActiveRecord, etc.). For
-example, to run `ActionMailer` tests you can:
+
+#### For a Particular Component
+
+You can run tests only for a particular component (e.g. Action Pack). For example,
+to run Action Mailer tests:
```bash
$ cd actionmailer
$ bundle exec rake test
```
+#### Running a Single Test
+
+You can run a single test through ruby. For instance:
+
+```bash
+$ cd actionmailer
+$ ruby -w -Itest test/mail_layout_test.rb -n test_explicit_class_layout
+```
+
+The `-n` option allows you to run a single method instead of the whole
+file.
+
##### Testing Active Record
This is how you run the Active Record test suite only for SQLite3:
@@ -275,15 +292,7 @@ $ ARCONN=sqlite3 ruby -Itest test/cases/associations/has_many_associations_test.
You can invoke `test_jdbcmysql`, `test_jdbcsqlite3` or `test_jdbcpostgresql` also. See the file `activerecord/RUNNING_UNIT_TESTS.rdoc` for information on running more targeted database tests, or the file `ci/travis.rb` for the test suite run by the continuous integration server.
-#### Single Test separately
-to run just one test. For example, to run `LayoutMailerTest` you can:
-
-```bash
-$ cd actionmailer
-$ ruby -w -Ilib:test test/mail_layout_test.rb
-```
-
-### Warnings ###
+### Warnings
The test suite runs with warnings enabled. Ideally, Ruby on Rails should issue no warnings, but there may be a few, as well as some from third-party libraries. Please ignore (or fix!) them, if any, and submit patches that do not issue new warnings.
@@ -292,7 +301,8 @@ If you are sure about what you are doing and would like to have a more clear out
```bash
$ RUBYOPT=-W0 bundle exec rake test
```
-### Updating the CHANGELOG ###
+
+### Updating the CHANGELOG
The CHANGELOG is an important part of every release. It keeps the list of changes for every Rails version.
@@ -317,7 +327,7 @@ A CHANGELOG entry should summarize what was changed and should end with author's
Your name can be added directly after the last word if you don't provide any code examples or don't need multiple paragraphs. Otherwise, it's best to make as a new paragraph.
-### Sanity Check ###
+### Sanity Check
You should not be the only person who looks at the code before you submit it.
If you know someone else who uses Rails, try asking them if they'll check out
@@ -327,7 +337,7 @@ private before you push a patch out publicly is the "smoke test" for a patch:
if you can't convince one other developer of the beauty of your code, you’re
unlikely to convince the core team either.
-### Commit Your Changes ###
+### Commit Your Changes
When you're happy with the code on your computer, you need to commit the changes to Git:
@@ -367,7 +377,7 @@ You can also add bullet points:
TIP. Please squash your commits into a single commit when appropriate. This simplifies future cherry picks, and also keeps the git log clean.
-### Update Your Branch ###
+### Update Your Branch
It's pretty likely that other changes to master have happened while you were working. Go get them:
@@ -385,7 +395,7 @@ $ git rebase master
No conflicts? Tests still pass? Change still seems reasonable to you? Then move on.
-### Fork ###
+### Fork
Navigate to the Rails [GitHub repository](https://github.com/rails/rails) and press "Fork" in the upper right hand corner.
@@ -515,14 +525,13 @@ $ git push origin my_pull_request -f
You should be able to refresh the pull request on GitHub and see that it has
been updated.
-
-### Older Versions of Ruby on Rails ###
+### Older Versions of Ruby on Rails
If you want to add a fix to older versions of Ruby on Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to the 3-0-stable branch:
```bash
-$ git branch --track 3-0-stable origin/3-0-stable
-$ git checkout 3-0-stable
+$ git branch --track 4-0-stable origin/4-0-stable
+$ git checkout 4-0-stable
```
TIP: You may want to [put your Git branch name in your shell prompt](http://qugstart.com/blog/git-and-svn/add-colored-git-branch-name-to-your-shell-prompt/) to make it easier to remember which version of the code you're working with.
diff --git a/guides/source/security.md b/guides/source/security.md
index 0d347c9e4b..0f4d4e712b 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -135,8 +135,8 @@ NOTE: _Apart from stealing a user's session id, the attacker may fix a session i
This attack focuses on fixing a user's session id known to the attacker, and forcing the user's browser into using this id. It is therefore not necessary for the attacker to steal the session id afterwards. Here is how this attack works:
* The attacker creates a valid session id: They load the login page of the web application where they want to fix the session, and take the session id in the cookie from the response (see number 1 and 2 in the image).
-* They possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore they access the web application from time to time in order to keep the session alive.
-* Now the attacker will force the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on.
+* They maintain the session by accessing the web application periodically in order to keep an expiring session alive.
+* The attacker forces the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on.
* The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id.
* As the new trap session is unused, the web application will require the user to authenticate.
* From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack.
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 6a31a923a7..480ec32443 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Reading name and email from git for plugin gemspec.
+
+ Fixes #9589.
+
+ *Arun Agrawal*, *Abd ar-Rahman Hamidi*, *Roman Shmatov*
+
* Fix `console` and `generators` blocks defined at different environments.
Fixes #14748.
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
index 10f80abb15..da99e74435 100644
--- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
+++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
@@ -21,13 +21,8 @@
<%%= f.label :password_confirmation %><br>
<%%= f.password_field :password_confirmation %>
<% else -%>
- <%- if attribute.reference? -%>
<%%= f.label :<%= attribute.column_name %> %><br>
<%%= f.<%= attribute.field_type %> :<%= attribute.column_name %> %>
- <%- else -%>
- <%%= f.label :<%= attribute.name %> %><br>
- <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
- <%- end -%>
<% end -%>
</div>
<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index f6f529b80a..584f776c01 100644
--- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -288,6 +288,10 @@ task default: :test
options[:mountable]
end
+ def skip_git?
+ options[:skip_git]
+ end
+
def with_dummy_app?
options[:skip_test_unit].blank? || options[:dummy_path] != 'test/dummy'
end
@@ -304,6 +308,24 @@ task default: :test
@camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize
end
+ def author
+ default = "TODO: Write your name"
+ if skip_git?
+ @author = default
+ else
+ @author = `git config user.name`.chomp rescue default
+ end
+ end
+
+ def email
+ default = "TODO: Write your email address"
+ if skip_git?
+ @email = default
+ else
+ @email = `git config user.email`.chomp rescue default
+ end
+ end
+
def valid_const?
if original_name =~ /[^0-9a-zA-Z_]+/
raise Error, "Invalid plugin name #{original_name}. Please give a name which use only alphabetic or numeric or \"_\" characters."
diff --git a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
index 5fdf0e1554..919c349470 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
+++ b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
@@ -7,8 +7,8 @@ require "<%= name %>/version"
Gem::Specification.new do |s|
s.name = "<%= name %>"
s.version = <%= camelized %>::VERSION
- s.authors = ["TODO: Your name"]
- s.email = ["TODO: Your email"]
+ s.authors = ["<%= author %>"]
+ s.email = ["<%= email %>"]
s.homepage = "TODO"
s.summary = "TODO: Summary of <%= camelized %>."
s.description = "TODO: Description of <%= camelized %>."
diff --git a/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE
index d7a9109894..ff2fb3ba4e 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE
+++ b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright <%= Date.today.year %> YOURNAME
+Copyright <%= Date.today.year %> <%= author %>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index 853af80111..69ff23eb95 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -371,6 +371,40 @@ class PluginGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_git_name_and_email_in_gemspec_file
+ name = `git config user.name`.chomp rescue "TODO: Write your name"
+ email = `git config user.email`.chomp rescue "TODO: Write your email address"
+
+ run_generator [destination_root]
+ assert_file "bukkits.gemspec" do |contents|
+ assert_match(/#{Regexp.escape(name)}/, contents)
+ assert_match(/#{Regexp.escape(email)}/, contents)
+ end
+ end
+
+ def test_git_name_in_license_file
+ name = `git config user.name`.chomp rescue "TODO: Write your name"
+
+ run_generator [destination_root]
+ assert_file "MIT-LICENSE" do |contents|
+ assert_match(/#{Regexp.escape(name)}/, contents)
+ end
+ end
+
+ def test_no_details_from_git_when_skip_git
+ name = "TODO: Write your name"
+ email = "TODO: Write your email address"
+
+ run_generator [destination_root, '--skip-git']
+ assert_file "MIT-LICENSE" do |contents|
+ assert_match(/#{Regexp.escape(name)}/, contents)
+ end
+ assert_file "bukkits.gemspec" do |contents|
+ assert_match(/#{Regexp.escape(name)}/, contents)
+ assert_match(/#{Regexp.escape(email)}/, contents)
+ end
+ end
+
protected
def action(*args, &block)
silence(:stdout){ generator.send(*args, &block) }