aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md8
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb90
-rw-r--r--actionview/CHANGELOG.md6
-rw-r--r--actionview/lib/action_view/helpers/tags/placeholderable.rb32
-rw-r--r--actionview/lib/action_view/helpers/tags/text_area.rb4
-rw-r--r--actionview/lib/action_view/helpers/tags/text_field.rb4
-rw-r--r--actionview/test/template/form_helper_test.rb168
-rw-r--r--activejob/lib/active_job/logging.rb8
-rw-r--r--activerecord/RUNNING_UNIT_TESTS.rdoc4
-rw-r--r--activerecord/lib/active_record/associations.rb12
-rw-r--r--activesupport/CHANGELOG.md7
-rw-r--r--activesupport/lib/active_support/duration.rb6
-rw-r--r--activesupport/test/core_ext/duration_test.rb5
-rw-r--r--guides/source/debugging_rails_applications.md2
-rw-r--r--guides/source/generators.md8
-rw-r--r--guides/source/nested_model_forms.md5
-rw-r--r--railties/lib/rails/commands/console.rb2
-rw-r--r--railties/lib/rails/commands/server.rb2
-rw-r--r--railties/test/application/middleware/remote_ip_test.rb16
19 files changed, 108 insertions, 281 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index bdb14b69e5..050ec5e649 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Allow `config.action_dispatch.trusted_proxies` to accept an IPAddr object.
+
+ Example:
+ # config/environments/production.rb
+ config.action_dispatch.trusted_proxies = IPAddr.new('4.8.15.0/16')
+
+ *Sam Aarons*
+
* Avoid duplicating routes for HEAD requests.
Instead of duplicating the routes, we will first match the HEAD request to
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index 6a79b4e859..b022fea001 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -1,3 +1,5 @@
+require 'ipaddr'
+
module ActionDispatch
# This middleware calculates the IP address of the remote client that is
# making the request. It does this by checking various headers that could
@@ -28,14 +30,14 @@ module ActionDispatch
# guaranteed by the IP specification to be private addresses. Those will
# not be the ultimate client IP in production, and so are discarded. See
# http://en.wikipedia.org/wiki/Private_network for details.
- TRUSTED_PROXIES = %r{
- ^127\.0\.0\.1$ | # localhost IPv4
- ^::1$ | # localhost IPv6
- ^[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
- }x
+ TRUSTED_PROXIES = [
+ "127.0.0.1", # localhost IPv4
+ "::1", # localhost IPv6
+ "fc00::/7", # private IPv6 range fc00::/7
+ "10.0.0.0/8", # private IPv4 range 10.x.x.x
+ "172.16.0.0/12", # private IPv4 range 172.16.0.0 .. 172.31.255.255
+ "192.168.0.0/16", # private IPv4 range 192.168.x.x
+ ].map { |proxy| IPAddr.new(proxy) }
attr_reader :check_ip, :proxies
@@ -47,24 +49,24 @@ module ActionDispatch
# clients (like WAP devices), or behind proxies that set headers in an
# incorrect or confusing way (like AWS ELB).
#
- # The +custom_proxies+ argument can take a regex, which will be used
- # instead of +TRUSTED_PROXIES+, or a string, which will be used in addition
- # to +TRUSTED_PROXIES+. Any proxy setup will put the value you want in the
- # middle (or at the beginning) of the X-Forwarded-For list, with your proxy
- # servers after it. If your proxies aren't removed, pass them in via the
- # +custom_proxies+ parameter. That way, the middleware will ignore those
- # IP addresses, and return the one that you want.
+ # The +custom_proxies+ argument can take an Array of string, IPAddr, or
+ # Regexp objects which will be used instead of +TRUSTED_PROXIES+. If a
+ # single string, IPAddr, or Regexp object is provided, it will be used in
+ # addition to +TRUSTED_PROXIES+. Any proxy setup will put the value you
+ # want in the middle (or at the beginning) of the X-Forwarded-For list,
+ # with your proxy servers after it. If your proxies aren't removed, pass
+ # them in via the +custom_proxies+ parameter. That way, the middleware will
+ # ignore those IP addresses, and return the one that you want.
def initialize(app, check_ip_spoofing = true, custom_proxies = nil)
@app = app
@check_ip = check_ip_spoofing
- @proxies = case custom_proxies
- when Regexp
- custom_proxies
- when nil
- TRUSTED_PROXIES
- else
- Regexp.union(TRUSTED_PROXIES, custom_proxies)
- end
+ @proxies = if custom_proxies.blank?
+ TRUSTED_PROXIES
+ elsif custom_proxies.respond_to?(:any?)
+ custom_proxies
+ else
+ Array(custom_proxies) + TRUSTED_PROXIES
+ end
end
# Since the IP address may not be needed, we store the object here
@@ -80,32 +82,6 @@ module ActionDispatch
# into an actual IP address. If the ActionDispatch::Request#remote_ip method
# is called, this class will calculate the value and then memoize it.
class GetIp
-
- # This constant contains a regular expression that validates every known
- # form of IP v4 and v6 address, with or without abbreviations, adapted
- # from {this gist}[https://gist.github.com/gazay/1289635].
- VALID_IP = %r{
- (^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})){3}$) | # ip v4
- (^(
- (([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}) | # ip v6 not abbreviated
- (([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4}) | # ip v6 with double colon in the end
- (([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4}) | # - ip addresses v6
- (([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4}) | # - with
- (([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4}) | # - double colon
- (([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4}) | # - in the middle
- (([0-9A-Fa-f]{1,4}:){6} ((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3} (\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
- (([0-9A-Fa-f]{1,4}:){1,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
- (([0-9A-Fa-f]{1,4}:){1}:([0-9A-Fa-f]{1,4}:){0,4}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
- (([0-9A-Fa-f]{1,4}:){0,2}:([0-9A-Fa-f]{1,4}:){0,3}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
- (([0-9A-Fa-f]{1,4}:){0,3}:([0-9A-Fa-f]{1,4}:){0,2}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
- (([0-9A-Fa-f]{1,4}:){0,4}:([0-9A-Fa-f]{1,4}:){1}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
- (::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d) |(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
- ([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4}) | # ip v6 with compatible to v4
- (::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4}) | # ip v6 with double colon at the beginning
- (([0-9A-Fa-f]{1,4}:){1,7}:) # ip v6 without ending
- )$)
- }x
-
def initialize(env, middleware)
@env = env
@check_ip = middleware.check_ip
@@ -173,12 +149,22 @@ module ActionDispatch
def ips_from(header)
# Split the comma-separated list into an array of strings
ips = @env[header] ? @env[header].strip.split(/[,\s]+/) : []
- # Only return IPs that are valid according to the regex
- ips.select{ |ip| ip =~ VALID_IP }
+ ips.select do |ip|
+ begin
+ # Only return IPs that are valid according to the IPAddr#new method
+ range = IPAddr.new(ip).to_range
+ # we want to make sure nobody is sneaking a netmask in
+ range.begin == range.end
+ rescue ArgumentError, IPAddr::InvalidAddressError
+ nil
+ end
+ end
end
def filter_proxies(ips)
- ips.reject { |ip| ip =~ @proxies }
+ ips.reject do |ip|
+ @proxies.any? { |proxy| proxy === ip }
+ end
end
end
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 552a902349..3fc2ab178c 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,9 +1,3 @@
-* Add I18n support for input/textarea placeholder text.
-
- Placeholder I18n follows the same convention as `label` I18n.
-
- *Alex Robbin*
-
* Fix that render layout: 'messages/layout' should also be added to the dependency tracker tree.
*DHH*
diff --git a/actionview/lib/action_view/helpers/tags/placeholderable.rb b/actionview/lib/action_view/helpers/tags/placeholderable.rb
deleted file mode 100644
index 313aa725c9..0000000000
--- a/actionview/lib/action_view/helpers/tags/placeholderable.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-module ActionView
- module Helpers
- module Tags # :nodoc:
- module Placeholderable # :nodoc:
- def initialize(*)
- super
-
- if tag_value = @options[:placeholder]
- object_name = @object_name.gsub(/\[(.*)_attributes\]\[\d+\]/, '.\1')
- method_and_value = tag_value.is_a?(TrueClass) ? @method_name : "#{@method_name}.#{tag_value}"
-
- if object.respond_to?(:to_model)
- key = object.class.model_name.i18n_key
- i18n_default = ["#{key}.#{method_and_value}".to_sym, ""]
- end
-
- i18n_default ||= ""
- placeholder = I18n.t("#{object_name}.#{method_and_value}", :default => i18n_default, :scope => "helpers.placeholder").presence
-
- placeholder ||= if object && object.class.respond_to?(:human_attribute_name)
- object.class.human_attribute_name(method_and_value)
- end
-
- placeholder ||= @method_name.humanize
-
- @options[:placeholder] = placeholder
- end
- end
- end
- end
- end
-end
diff --git a/actionview/lib/action_view/helpers/tags/text_area.rb b/actionview/lib/action_view/helpers/tags/text_area.rb
index 69038c1498..9ee83ee7c2 100644
--- a/actionview/lib/action_view/helpers/tags/text_area.rb
+++ b/actionview/lib/action_view/helpers/tags/text_area.rb
@@ -1,11 +1,7 @@
-require 'action_view/helpers/tags/placeholderable'
-
module ActionView
module Helpers
module Tags # :nodoc:
class TextArea < Base # :nodoc:
- include Placeholderable
-
def render
options = @options.stringify_keys
add_default_name_and_id(options)
diff --git a/actionview/lib/action_view/helpers/tags/text_field.rb b/actionview/lib/action_view/helpers/tags/text_field.rb
index 5c576a20ca..e0b80d81c2 100644
--- a/actionview/lib/action_view/helpers/tags/text_field.rb
+++ b/actionview/lib/action_view/helpers/tags/text_field.rb
@@ -1,11 +1,7 @@
-require 'action_view/helpers/tags/placeholderable'
-
module ActionView
module Helpers
module Tags # :nodoc:
class TextField < Base # :nodoc:
- include Placeholderable
-
def render
options = @options.stringify_keys
options["size"] = options["maxlength"] unless options.key?("size")
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index d944214961..a9f137aec6 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -59,35 +59,6 @@ class FormHelperTest < ActionView::TestCase
}
}
- I18n.backend.store_translations 'placeholder', {
- activemodel: {
- attributes: {
- post: {
- cost: "Total cost"
- },
- :"post/cost" => {
- uk: "Pounds"
- }
- }
- },
- helpers: {
- placeholder: {
- post: {
- title: "What is this about?",
- written_on: {
- spanish: "Escrito en"
- },
- comments: {
- body: "Write body here"
- }
- },
- tag: {
- value: "Tag"
- }
- }
- }
- }
-
@post = Post.new
@comment = Comment.new
def @post.errors()
@@ -326,68 +297,6 @@ class FormHelperTest < ActionView::TestCase
)
end
- def test_text_field_placeholder_without_locales
- with_locale :placeholder do
- assert_dom_equal('<input id="post_body" name="post[body]" placeholder="Body" type="text" value="Back to the hill and over it again!" />', text_field(:post, :body, placeholder: true))
- end
- end
-
- def test_text_field_placeholder_with_locales
- with_locale :placeholder do
- assert_dom_equal('<input id="post_title" name="post[title]" placeholder="What is this about?" type="text" value="Hello World" />', text_field(:post, :title, placeholder: true))
- end
- end
-
- def test_text_field_placeholder_with_human_attribute_name
- with_locale :placeholder do
- assert_dom_equal('<input id="post_cost" name="post[cost]" placeholder="Total cost" type="text" />', text_field(:post, :cost, placeholder: true))
- end
- end
-
- def test_text_field_placeholder_with_human_attribute_name_and_value
- with_locale :placeholder do
- assert_dom_equal('<input id="post_cost" name="post[cost]" placeholder="Pounds" type="text" />', text_field(:post, :cost, placeholder: "uk"))
- end
- end
-
- def test_text_field_placeholder_with_locales_and_value
- with_locale :placeholder do
- assert_dom_equal('<input id="post_written_on" name="post[written_on]" placeholder="Escrito en" type="text" value="2004-06-15" />', text_field(:post, :written_on, placeholder: "spanish"))
- end
- end
-
- def test_text_field_placeholder_with_locales_and_nested_attributes
- with_locale :placeholder do
- form_for(@post, html: { id: 'create-post' }) do |f|
- f.fields_for(:comments) do |cf|
- concat cf.text_field(:body, placeholder: true)
- end
- end
-
- expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
- '<input id="post_comments_attributes_0_body" name="post[comments_attributes][0][body]" placeholder="Write body here" type="text" />'
- end
-
- assert_dom_equal expected, output_buffer
- end
- end
-
- def test_text_field_placeholder_with_locales_fallback_and_nested_attributes
- with_locale :placeholder do
- form_for(@post, html: { id: 'create-post' }) do |f|
- f.fields_for(:tags) do |cf|
- concat cf.text_field(:value, placeholder: true)
- end
- end
-
- expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
- '<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" placeholder="Tag" type="text" value="new tag" />'
- end
-
- assert_dom_equal expected, output_buffer
- end
- end
-
def test_text_field
assert_dom_equal(
'<input id="post_title" name="post[title]" type="text" value="Hello World" />',
@@ -756,83 +665,6 @@ class FormHelperTest < ActionView::TestCase
)
end
- def test_text_area_placeholder_without_locales
- with_locale :placeholder do
- assert_dom_equal(
- %{<textarea id="post_body" name="post[body]" placeholder="Body">\nBack to the hill and over it again!</textarea>},
- text_area(:post, :body, placeholder: true)
- )
- end
- end
-
- def test_text_area_placeholder_with_locales
- with_locale :placeholder do
- assert_dom_equal(
- %{<textarea id="post_title" name="post[title]" placeholder="What is this about?">\nHello World</textarea>},
- text_area(:post, :title, placeholder: true)
- )
- end
- end
-
- def test_text_area_placeholder_with_human_attribute_name
- with_locale :placeholder do
- assert_dom_equal(
- %{<textarea id="post_cost" name="post[cost]" placeholder="Total cost">\n</textarea>},
- text_area(:post, :cost, placeholder: true)
- )
- end
- end
-
- def test_text_area_placeholder_with_human_attribute_name_and_value
- with_locale :placeholder do
- assert_dom_equal(
- %{<textarea id="post_cost" name="post[cost]" placeholder="Pounds">\n</textarea>},
- text_area(:post, :cost, placeholder: "uk")
- )
- end
- end
-
- def test_text_area_placeholder_with_locales_and_value
- with_locale :placeholder do
- assert_dom_equal(
- %{<textarea id="post_written_on" name="post[written_on]" placeholder="Escrito en">\n2004-06-15</textarea>},
- text_area(:post, :written_on, placeholder: "spanish")
- )
- end
- end
-
- def test_text_area_placeholder_with_locales_and_nested_attributes
- with_locale :placeholder do
- form_for(@post, html: { id: 'create-post' }) do |f|
- f.fields_for(:comments) do |cf|
- concat cf.text_area(:body, placeholder: true)
- end
- end
-
- expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
- %{<textarea id="post_comments_attributes_0_body" name="post[comments_attributes][0][body]" placeholder="Write body here">\n</textarea>}
- end
-
- assert_dom_equal expected, output_buffer
- end
- end
-
- def test_text_area_placeholder_with_locales_fallback_and_nested_attributes
- with_locale :placeholder do
- form_for(@post, html: { id: 'create-post' }) do |f|
- f.fields_for(:tags) do |cf|
- concat cf.text_area(:value, placeholder: true)
- end
- end
-
- expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
- %{<textarea id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" placeholder="Tag">\nnew tag</textarea>}
- end
-
- assert_dom_equal expected, output_buffer
- end
- end
-
def test_text_area
assert_dom_equal(
%{<textarea id="post_body" name="post[body]">\nBack to the hill and over it again!</textarea>},
diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb
index d9e544acf5..ae098a80f3 100644
--- a/activejob/lib/active_job/logging.rb
+++ b/activejob/lib/active_job/logging.rb
@@ -52,19 +52,19 @@ module ActiveJob
class LogSubscriber < ActiveSupport::LogSubscriber
def enqueue(event)
- info "Enqueued #{event.payload[:job].name} (Job ID: #{event.payload[:job_id]}) to #{queue_name(event)}" + args_info(event)
+ info { "Enqueued #{event.payload[:job].name} (Job ID: #{event.payload[:job_id]}) to #{queue_name(event)}" + args_info(event) }
end
def enqueue_at(event)
- info "Enqueued #{event.payload[:job].name} (Job ID: #{event.payload[:job_id]}) to #{queue_name(event)} at #{enqueued_at(event)}" + args_info(event)
+ info { "Enqueued #{event.payload[:job].name} (Job ID: #{event.payload[:job_id]}) to #{queue_name(event)} at #{enqueued_at(event)}" + args_info(event) }
end
def perform_start(event)
- info "Performing #{event.payload[:job].name} from #{queue_name(event)}" + args_info(event)
+ info { "Performing #{event.payload[:job].name} from #{queue_name(event)}" + args_info(event) }
end
def perform(event)
- info "Performed #{event.payload[:job].name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms"
+ info { "Performed #{event.payload[:job].name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms" }
end
private
diff --git a/activerecord/RUNNING_UNIT_TESTS.rdoc b/activerecord/RUNNING_UNIT_TESTS.rdoc
index ca1f2fd665..569685bd45 100644
--- a/activerecord/RUNNING_UNIT_TESTS.rdoc
+++ b/activerecord/RUNNING_UNIT_TESTS.rdoc
@@ -32,8 +32,8 @@ defined in +Rakefile+)
== Config File
-If +test/config.yml+ is present, it's parameters are obeyed. Otherwise, the
-parameters in +test/config.example.yml+ are obeyed.
+If +test/config.yml+ is present, then its parameters are obeyed; otherwise, the
+parameters in +test/config.example.yml+ are.
You can override the +connections:+ parameter in either file using the +ARCONN+
(Active Record CONNection) environment variable:
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index fb8cf1cecc..4ec1c8d545 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1578,6 +1578,18 @@ module ActiveRecord
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
# The declaration may include an +options+ hash to specialize the behavior of the association.
#
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific set of records or customize the generated
+ # query when you access the associated collection.
+ #
+ # Scope examples:
+ # has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
+ # has_and_belongs_to_many :categories, ->(category) {
+ # where("default_category = ?", category.name)
+ # }
+ #
# === Options
#
# [:class_name]
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 96bce53999..88d6e09d4b 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,6 +1,11 @@
+* Add the `Duration#instance_of?` method that was previously delegated to the
+ internal `value` attribute.
+
+ *Robin Dupret*
+
* Fix rounding errors with #travel_to by resetting the usec on any passed time to zero, so we only travel
with per-second precision, not anything deeper than that.
-
+
*DHH*
* Fix ActiveSupport::TestCase not to order users' test cases by default.
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 0ae641d05b..084d13a9e3 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -35,10 +35,14 @@ module ActiveSupport
end
def is_a?(klass) #:nodoc:
- Duration == klass || value.is_a?(klass)
+ instance_of?(klass) || value.is_a?(klass)
end
alias :kind_of? :is_a?
+ def instance_of?(klass) # :nodoc:
+ Duration == klass
+ end
+
# Returns +true+ if +other+ is also a Duration instance with the
# same +value+, or if <tt>other == value</tt>.
def ==(other)
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 31af3c4521..330d995b7c 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -41,6 +41,11 @@ class DurationTest < ActiveSupport::TestCase
assert !1.eql?(1.second)
end
+ def test_instance_of
+ assert !1.minute.instance_of?(Fixnum)
+ assert !2.days.instance_of?(Fixnum)
+ end
+
def test_inspect
assert_equal '0 seconds', 0.seconds.inspect
assert_equal '1 month', 1.month.inspect
diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md
index 53b8566d83..88c6210296 100644
--- a/guides/source/debugging_rails_applications.md
+++ b/guides/source/debugging_rails_applications.md
@@ -211,7 +211,7 @@ logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs "
### Impact of Logs on Performance
Logging will always have a small impact on performance of your rails app,
- particularly when logging to disk.However, there are a few subtleties:
+ particularly when logging to disk. However, there are a few subtleties:
Using the `:debug` level will have a greater performance penalty than `:fatal`,
as a far greater number of strings are being evaluated and written to the
diff --git a/guides/source/generators.md b/guides/source/generators.md
index 2b39ea66d8..f5d2c67cb4 100644
--- a/guides/source/generators.md
+++ b/guides/source/generators.md
@@ -341,13 +341,17 @@ end
If you generate another resource, you can see that we get exactly the same result! This is useful if you want to customize your scaffold templates and/or layout by just creating `edit.html.erb`, `index.html.erb` and so on inside `lib/templates/erb/scaffold`.
-Many scaffold templates in Rails are written in ERB tags which need to be escaped, so that the output is valid ERB code. For example,
+Scaffold templates in Rails frequently use ERB tags; these tags need to be
+escaped so that the generated output is valid ERB code.
+
+For example, the following escaped ERB tag would be needed in the template
+(note the extra `%`)...
```ruby
<%%= stylesheet_include_tag :application %>
```
-when passed through the generator, would generate the following output.
+...to generate the following output:
```ruby
<%= stylesheet_include_tag :application %>
diff --git a/guides/source/nested_model_forms.md b/guides/source/nested_model_forms.md
index 4f0634d955..f0ee34cfb1 100644
--- a/guides/source/nested_model_forms.md
+++ b/guides/source/nested_model_forms.md
@@ -1,4 +1,4 @@
-Rails nested model forms
+Rails Nested Model Forms
========================
Creating a form for a model _and_ its associations can become quite tedious. Therefore Rails provides helpers to assist in dealing with the complexities of generating these forms _and_ the required CRUD operations to create, update, and destroy associations.
@@ -54,6 +54,9 @@ class Person < ActiveRecord::Base
end
```
+NOTE: For greater detail on associations see [Active Record Associations](association_basics.html).
+For a complete reference on associations please visit the API documentation for [ActiveRecord::Associations::ClassMethods](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html).
+
### Custom model
As you might have inflected from this explanation, you _don't_ necessarily need an ActiveRecord::Base model to use this functionality. The following examples are sufficient to enable the nested model form behavior:
diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb
index c926620b33..96ced3c2f9 100644
--- a/railties/lib/rails/commands/console.rb
+++ b/railties/lib/rails/commands/console.rb
@@ -14,7 +14,7 @@ module Rails
OptionParser.new do |opt|
opt.banner = "Usage: rails console [environment] [options]"
- opt.on('-s', '--sandbox', 'Rollbacks database modifications on exit.') { |v| options[:sandbox] = v }
+ opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
opt.on("-e", "--environment=name", String,
"Specifies the environment to run this console under (test/development/production).",
"Default: development") { |v| options[:environment] = v.strip }
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index ba7e7396ba..c479e92ae0 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -20,7 +20,7 @@ module Rails
def option_parser(options)
OptionParser.new do |opts|
- opts.banner = "Usage: rails server [Mongrel, Thin etc] [options]"
+ opts.banner = "Usage: rails server [mongrel, thin etc] [options]"
opts.on("-p", "--port=port", Integer,
"Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v }
opts.on("-b", "--binding=IP", String,
diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb
index 946b82eeb3..97d5b5c698 100644
--- a/railties/test/application/middleware/remote_ip_test.rb
+++ b/railties/test/application/middleware/remote_ip_test.rb
@@ -1,3 +1,4 @@
+require 'ipaddr'
require 'isolation/abstract_unit'
require 'active_support/key_generator'
@@ -53,12 +54,25 @@ module ApplicationTests
end
end
+ test "remote_ip works with HTTP_X_FORWARDED_FOR" do
+ make_basic_app
+ assert_equal "4.2.42.42", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "4.2.42.42")
+ end
+
test "the user can set trusted proxies" do
make_basic_app do |app|
app.config.action_dispatch.trusted_proxies = /^4\.2\.42\.42$/
end
- assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "4.2.42.42,1.1.1.1")
+ assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "4.2.42.42")
+ end
+
+ test "the user can set trusted proxies with an IPAddr argument" do
+ make_basic_app do |app|
+ app.config.action_dispatch.trusted_proxies = IPAddr.new('4.2.42.0/24')
+ end
+
+ assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "10.0.0.0,4.2.42.42")
end
end
end