Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into nested_has_many_through

  • Loading branch information...
commit 67b17d029a8eeddd908cce2d4e0e27e4708e8463 2 parents bb063b2 + 5968d7a
@jonleighton jonleighton authored
Showing with 193 additions and 44 deletions.
  1. +4 −1 actionmailer/lib/rails/generators/mailer/USAGE
  2. +2 −2 actionmailer/test/base_test.rb
  3. +10 −1 actionpack/lib/action_controller/test_case.rb
  4. +2 −0  actionpack/lib/action_dispatch/routing/route_set.rb
  5. +1 −1  actionpack/lib/action_dispatch/testing/test_process.rb
  6. +6 −1 actionpack/lib/action_dispatch/testing/test_request.rb
  7. +4 −3 actionpack/lib/action_view/helpers/form_helper.rb
  8. +65 −0 actionpack/test/dispatch/cookies_test.rb
  9. +32 −0 actionpack/test/dispatch/routing_test.rb
  10. +2 −2 actionpack/test/dispatch/test_request_test.rb
  11. +19 −0 actionpack/test/template/form_options_helper_test.rb
  12. +1 −1  activemodel/lib/active_model/observing.rb
  13. +1 −1  activesupport/lib/active_support/backtrace_cleaner.rb
  14. +11 −14 activesupport/lib/active_support/cache.rb
  15. +6 −6 activesupport/lib/active_support/configurable.rb
  16. +2 −2 activesupport/lib/active_support/hash_with_indifferent_access.rb
  17. +1 −1  activesupport/lib/active_support/i18n_railtie.rb
  18. +1 −1  activesupport/lib/active_support/log_subscriber.rb
  19. +1 −1  activesupport/lib/active_support/message_encryptor.rb
  20. +1 −1  activesupport/lib/active_support/message_verifier.rb
  21. +1 −1  activesupport/lib/active_support/whiny_nil.rb
  22. +3 −3 activesupport/test/caching_test.rb
  23. +2 −0  activesupport/test/whiny_nil_test.rb
  24. +1 −1  railties/guides/source/active_record_querying.textile
  25. +14 −0 railties/guides/source/contributing_to_ruby_on_rails.textile
View
5 actionmailer/lib/rails/generators/mailer/USAGE
@@ -1,4 +1,5 @@
Description:
+============
Stubs out a new mailer and its views. Pass the mailer name, either
CamelCased or under_scored, and an optional list of emails as arguments.
@@ -6,10 +7,12 @@ Description:
engine and test framework generators.
Example:
- `rails generate mailer Notifications signup forgot_password invoice`
+========
+ rails generate mailer Notifications signup forgot_password invoice
creates a Notifications mailer class, views, test, and fixtures:
Mailer: app/mailers/notifications.rb
Views: app/views/notifications/signup.erb [...]
Test: test/functional/notifications_test.rb
Fixtures: test/fixtures/notifications/signup [...]
+
View
4 actionmailer/test/base_test.rb
@@ -153,8 +153,8 @@ def teardown
assert_equal(2, email.parts.length)
assert_equal("multipart/related", email.mime_type)
assert_equal("multipart/alternative", email.parts[0].mime_type)
- assert_equal("text/plain", email.parts[0].parts[0].mime_type)
- assert_equal("text/html", email.parts[0].parts[1].mime_type)
+ assert_equal("text/plain", email.parts[0].parts[0].mime_type)
+ assert_equal("text/html", email.parts[0].parts[1].mime_type)
assert_equal("logo.png", email.parts[1].filename)
end
View
11 actionpack/lib/action_controller/test_case.rb
@@ -172,6 +172,10 @@ def assign_parameters(routes, controller_path, action, parameters = {})
end
def recycle!
+ write_cookies!
+ @env.delete('HTTP_COOKIE') if @cookies.blank?
+ @env.delete('action_dispatch.cookies')
+ @cookies = nil
@formats = nil
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
@@ -301,7 +305,11 @@ def exists?
# and cookies, though. For sessions, you just do:
#
# @request.session[:key] = "value"
- # @request.cookies["key"] = "value"
+ # @request.cookies[:key] = "value"
+ #
+ # To clear the cookies for a test just clear the request's cookies hash:
+ #
+ # @request.cookies.clear
#
# == \Testing named routes
#
@@ -416,6 +424,7 @@ def process(action, parameters = nil, session = nil, flash = nil, http_method =
@controller.process_with_new_base_test(@request, @response)
@assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
@request.session.delete('flash') if @request.session['flash'].blank?
+ @request.cookies.merge!(@response.cookies)
@response
end
View
2  actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,5 +1,6 @@
require 'rack/mount'
require 'forwardable'
+require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
@@ -330,6 +331,7 @@ def empty?
end
def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true)
+ raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i)
route = Route.new(self, app, conditions, requirements, defaults, name, anchor)
@set.add_route(*route)
named_routes[name] = route if name
View
2  actionpack/lib/action_dispatch/testing/test_process.rb
@@ -22,7 +22,7 @@ def flash
end
def cookies
- HashWithIndifferentAccess.new(@request.cookies.merge(@response.cookies))
+ @request.cookies.merge(@response.cookies).with_indifferent_access
end
def redirect_to_url
View
7 actionpack/lib/action_dispatch/testing/test_request.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/hash/reverse_merge'
+require 'rack/utils'
module ActionDispatch
class TestRequest < Request
@@ -77,10 +78,14 @@ def cookies
private
def write_cookies!
unless @cookies.blank?
- @env['HTTP_COOKIE'] = @cookies.map { |name, value| "#{name}=#{value};" }.join(' ')
+ @env['HTTP_COOKIE'] = @cookies.map { |name, value| escape_cookie(name, value) }.join('; ')
end
end
+ def escape_cookie(name, value)
+ "#{Rack::Utils.escape(name)}=#{Rack::Utils.escape(value)}"
+ end
+
def delete_nil_values!
@env.delete_if { |k, v| v.nil? }
end
View
7 actionpack/lib/action_view/helpers/form_helper.rb
@@ -6,6 +6,7 @@
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/output_safety'
+require 'active_support/core_ext/array/extract_options'
module ActionView
# = Action View Form Helpers
@@ -880,9 +881,9 @@ def range_field(object_name, method, options = {})
private
- def instantiate_builder(record, record_object = nil, options = nil, &block)
- options, record_object = record_object, nil if record_object.is_a?(Hash)
- options ||= {}
+ def instantiate_builder(record, *args, &block)
+ options = args.extract_options!
+ record_object = args.shift
case record
when String, Symbol
View
65 actionpack/test/dispatch/cookies_test.rb
@@ -124,6 +124,20 @@ def string_key
cookies['user_name'] = "david"
head :ok
end
+
+ def symbol_key_mock
+ cookies[:user_name] = "david" if cookies[:user_name] == "andrew"
+ head :ok
+ end
+
+ def string_key_mock
+ cookies['user_name'] = "david" if cookies['user_name'] == "andrew"
+ head :ok
+ end
+
+ def noop
+ head :ok
+ end
end
tests TestController
@@ -411,6 +425,57 @@ def test_cookies_hash_is_indifferent_access
end
end
+ def test_setting_request_cookies_is_indifferent_access
+ @request.cookies.clear
+ @request.cookies[:user_name] = "andrew"
+ get :string_key_mock
+ assert_equal "david", cookies[:user_name]
+
+ @request.cookies.clear
+ @request.cookies['user_name'] = "andrew"
+ get :symbol_key_mock
+ assert_equal "david", cookies['user_name']
+ end
+
+ def test_cookies_retained_across_requests
+ get :symbol_key
+ assert_equal "user_name=david; path=/", @response.headers["Set-Cookie"]
+ assert_equal "david", cookies[:user_name]
+
+ get :noop
+ assert_nil @response.headers["Set-Cookie"]
+ assert_equal "user_name=david", @request.env['HTTP_COOKIE']
+ assert_equal "david", cookies[:user_name]
+
+ get :noop
+ assert_nil @response.headers["Set-Cookie"]
+ assert_equal "user_name=david", @request.env['HTTP_COOKIE']
+ assert_equal "david", cookies[:user_name]
+ end
+
+ def test_cookies_can_be_cleared
+ get :symbol_key
+ assert_equal "user_name=david; path=/", @response.headers["Set-Cookie"]
+ assert_equal "david", cookies[:user_name]
+
+ @request.cookies.clear
+ get :noop
+ assert_nil @response.headers["Set-Cookie"]
+ assert_nil @request.env['HTTP_COOKIE']
+ assert_nil cookies[:user_name]
+
+ get :symbol_key
+ assert_equal "user_name=david; path=/", @response.headers["Set-Cookie"]
+ assert_equal "david", cookies[:user_name]
+ end
+
+ def test_cookies_are_escaped
+ @request.cookies[:user_ids] = '1;2'
+ get :noop
+ assert_equal "user_ids=1%3B2", @request.env['HTTP_COOKIE']
+ assert_equal "1;2", cookies[:user_ids]
+ end
+
private
def assert_cookie_header(expected)
header = @response.headers["Set-Cookie"]
View
32 actionpack/test/dispatch/routing_test.rb
@@ -2313,6 +2313,38 @@ def test_controller_name_with_leading_slash_raise_error
end
end
+ def test_invalid_route_name_raises_error
+ assert_raise(ArgumentError) do
+ self.class.stub_controllers do |routes|
+ routes.draw { get '/products', :to => 'products#index', :as => 'products ' }
+ end
+ end
+
+ assert_raise(ArgumentError) do
+ self.class.stub_controllers do |routes|
+ routes.draw { get '/products', :to => 'products#index', :as => ' products' }
+ end
+ end
+
+ assert_raise(ArgumentError) do
+ self.class.stub_controllers do |routes|
+ routes.draw { get '/products', :to => 'products#index', :as => 'products!' }
+ end
+ end
+
+ assert_raise(ArgumentError) do
+ self.class.stub_controllers do |routes|
+ routes.draw { get '/products', :to => 'products#index', :as => 'products index' }
+ end
+ end
+
+ assert_raise(ArgumentError) do
+ self.class.stub_controllers do |routes|
+ routes.draw { get '/products', :to => 'products#index', :as => '1products' }
+ end
+ end
+ end
+
def test_nested_route_in_nested_resource
get "/posts/1/comments/2/views"
assert_equal "comments#views", @response.body
View
4 actionpack/test/dispatch/test_request_test.rb
@@ -36,10 +36,10 @@ class TestRequestTest < ActiveSupport::TestCase
req.cookies["user_name"] = "david"
assert_equal({"user_name" => "david"}, req.cookies)
- assert_equal "user_name=david;", req.env["HTTP_COOKIE"]
+ assert_equal "user_name=david", req.env["HTTP_COOKIE"]
req.cookies["login"] = "XJ-122"
assert_equal({"user_name" => "david", "login" => "XJ-122"}, req.cookies)
- assert_equal %w(login=XJ-122 user_name=david), req.env["HTTP_COOKIE"].split(/; ?/).sort
+ assert_equal %w(login=XJ-122 user_name=david), req.env["HTTP_COOKIE"].split(/; /).sort
end
end
View
19 actionpack/test/template/form_options_helper_test.rb
@@ -1,6 +1,12 @@
require 'abstract_unit'
require 'tzinfo'
+class Map < Hash
+ def category
+ "<mus>"
+ end
+end
+
TZInfo::Timezone.cattr_reader :loaded_zones
class FormOptionsHelperTest < ActionView::TestCase
@@ -394,6 +400,19 @@ def test_select_under_fields_for
)
end
+ def test_fields_for_with_record_inherited_from_hash
+ map = Map.new
+
+ output_buffer = fields_for :map, map do |f|
+ concat f.select(:category, %w( abe <mus> hest))
+ end
+
+ assert_dom_equal(
+ "<select id=\"map_category\" name=\"map[category]\"><option value=\"abe\">abe</option>\n<option value=\"&lt;mus&gt;\" selected=\"selected\">&lt;mus&gt;</option>\n<option value=\"hest\">hest</option></select>",
+ output_buffer
+ )
+ end
+
def test_select_under_fields_for_with_index
@post = Post.new
@post.category = "<mus>"
View
2  activemodel/lib/active_model/observing.rb
@@ -72,7 +72,7 @@ def count_observers
def instantiate_observer(observer) #:nodoc:
# string/symbol
if observer.respond_to?(:to_sym)
- observer = observer.to_s.camelize.constantize.instance
+ observer.to_s.camelize.constantize.instance
elsif observer.respond_to?(:instance)
observer.instance
else
View
2  activesupport/lib/active_support/backtrace_cleaner.rb
@@ -8,7 +8,7 @@ module ActiveSupport
# filter or modify the paths of any lines of the backtrace, you can call BacktraceCleaner#remove_filters! These two methods
# will give you a completely untouched backtrace.
#
- # Example:
+ # ==== Example:
#
# bc = BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root, '') }
View
25 activesupport/lib/active_support/cache.rb
@@ -484,19 +484,20 @@ def merged_options(call_options) # :nodoc:
# object responds to +cache_key+. Otherwise, to_param method will be
# called. If the key is a Hash, then keys will be sorted alphabetically.
def expanded_key(key) # :nodoc:
- if key.respond_to?(:cache_key)
- key = key.cache_key.to_s
- elsif key.is_a?(Array)
+ return key.cache_key.to_s if key.respond_to?(:cache_key)
+
+ case key
+ when Array
if key.size > 1
- key.collect{|element| expanded_key(element)}.to_param
+ key = key.collect{|element| expanded_key(element)}
else
- key.first.to_param
+ key = key.first
end
- elsif key.is_a?(Hash)
- key = key.to_a.sort{|a,b| a.first.to_s <=> b.first.to_s}.collect{|k,v| "#{k}=#{v}"}.to_param
- else
- key = key.to_param
+ when Hash
+ key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"}
end
+
+ key.to_param
end
# Prefix a key with the namespace. Namespace and key will be delimited with a colon.
@@ -589,11 +590,7 @@ def compressed?
# Check if the entry is expired. The +expires_in+ parameter can override the
# value set when the entry was created.
def expired?
- if @expires_in && @created_at + @expires_in <= Time.now.to_f
- true
- else
- false
- end
+ @expires_in && @created_at + @expires_in <= Time.now.to_f
end
# Set a new time when the entry will expire.
View
12 activesupport/lib/active_support/configurable.rb
@@ -64,21 +64,21 @@ def #{name}=(value); config.#{name} = value; end
end
# Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
- #
- # require 'active_support/configurable'
- #
+ #
+ # require 'active_support/configurable'
+ #
# class User
# include ActiveSupport::Configurable
- # end
+ # end
#
# user = User.new
- #
+ #
# user.config.allowed_access = true
# user.config.level = 1
#
# user.config.allowed_access # => true
# user.config.level # => 1
- #
+ #
def config
@_config ||= self.class.config.inheritable_copy
end
View
4 activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -1,7 +1,7 @@
require 'active_support/core_ext/hash/keys'
# This class has dubious semantics and we only have it so that
-# people can write params[:key] instead of params['key']
+# people can write <tt>params[:key]</tt> instead of <tt>params['key']</tt>
# and they get the same value for both keys.
module ActiveSupport
@@ -109,7 +109,7 @@ def merge(hash)
end
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
- # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
+ # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a <tt>HashWithDifferentAccess</tt>.
def reverse_merge(other_hash)
super self.class.new_from_hash_copying_default(other_hash)
end
View
2  activesupport/lib/active_support/i18n_railtie.rb
@@ -14,7 +14,7 @@ def self.reloader
@reloader ||= ActiveSupport::FileUpdateChecker.new([]){ I18n.reload! }
end
- # Add I18n::Railtie.reloader to ActionDispatch callbacks. Since, at this
+ # Add <tt>I18n::Railtie.reloader</tt> to ActionDispatch callbacks. Since, at this
# point, no path was added to the reloader, I18n.reload! is not triggered
# on to_prepare callbacks. This will only happen on the config.after_initialize
# callback below.
View
2  activesupport/lib/active_support/log_subscriber.rb
@@ -21,7 +21,7 @@ module ActiveSupport
# ActiveRecord::LogSubscriber.attach_to :active_record
#
# Since we need to know all instance methods before attaching the log subscriber,
- # the line above should be called after your ActiveRecord::LogSubscriber definition.
+ # the line above should be called after your <tt>ActiveRecord::LogSubscriber</tt> definition.
#
# After configured, whenever a "sql.active_record" notification is published,
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
View
2  activesupport/lib/active_support/message_encryptor.rb
@@ -7,7 +7,7 @@ module ActiveSupport
#
# The cipher text and initialization vector are base64 encoded and returned to you.
#
- # This can be used in situations similar to the MessageVerifier, but where you don't
+ # This can be used in situations similar to the <tt>MessageVerifier</tt>, but where you don't
# want users to be able to determine the value of the payload.
class MessageEncryptor
class InvalidMessage < StandardError; end
View
2  activesupport/lib/active_support/message_verifier.rb
@@ -2,7 +2,7 @@
require 'active_support/core_ext/object/blank'
module ActiveSupport
- # MessageVerifier makes it easy to generate and verify messages which are signed
+ # +MessageVerifier+ makes it easy to generate and verify messages which are signed
# to prevent tampering.
#
# This is useful for cases like remember-me tokens and auto-unsubscribe links where the
View
2  activesupport/lib/active_support/whiny_nil.rb
@@ -37,7 +37,7 @@ def self.add_whiner(klass)
# Raises a RuntimeError when you attempt to call +id+ on +nil+.
def id
- raise RuntimeError, "Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id", caller
+ raise RuntimeError, "Called id for nil, which would mistakenly be #{object_id} -- if you really wanted the id of nil, use object_id", caller
end
private
View
6 activesupport/test/caching_test.rb
@@ -679,12 +679,12 @@ def test_create_raw_entry
def test_expired
entry = ActiveSupport::Cache::Entry.new("value")
- assert_equal false, entry.expired?
+ assert !entry.expired?, 'entry not expired'
entry = ActiveSupport::Cache::Entry.new("value", :expires_in => 60)
- assert_equal false, entry.expired?
+ assert !entry.expired?, 'entry not expired'
time = Time.now + 61
Time.stubs(:now).returns(time)
- assert_equal true, entry.expired?
+ assert entry.expired?, 'entry is expired'
end
def test_compress_values
View
2  activesupport/test/whiny_nil_test.rb
@@ -33,9 +33,11 @@ def test_array
end
def test_id
+ nil.stubs(:object_id).returns(999)
nil.id
rescue RuntimeError => nme
assert_no_match(/nil:NilClass/, nme.message)
+ assert_match(/999/, nme.message)
end
def test_no_to_ary_coercion
View
2  railties/guides/source/active_record_querying.textile
@@ -420,7 +420,7 @@ Client.limit(5).offset(30)
will return instead a maximum of 5 clients beginning with the 31st. The SQL looks like:
<sql>
-SELECT * FROM clients LIMIT 5, 30
+SELECT * FROM clients LIMIT 5 OFFSET 30
</sql>
h3. Group
View
14 railties/guides/source/contributing_to_ruby_on_rails.textile
@@ -364,6 +364,20 @@ Please make sure the patch does not introduce whitespace errors:
$ git apply --whitespace=error-all mynew_patch.diff
</shell>
+You can check your patches by applying your patch to an different dedicated branch:
+
+<shell>
+$ git checkout -b testing_branch
+$ git apply --check my_new_patch.diff
+</shell>
+
+You can make sure your patches don't add any whitespace by applying it yourself using the --whitespace=error-all option. Make sure you are on your dedicated test branche and:
+
+<shell>
+$ git apply --whitespace=error-all mynew_patch.diff
+</shell>
+
+
h4. Create a Lighthouse Ticket
Now create a ticket with your patch. Go to the "new ticket":http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/new page at Lighthouse. Fill in a reasonable title and description, remember to attach your patch file, and tag the ticket with the ‘patch’ tag and whatever other subject area tags make sense.
Please sign in to comment.
Something went wrong with that request. Please try again.