1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge branch 'master' into nested_has_many_through

This commit is contained in:
Jon Leighton 2011-03-07 20:58:54 +00:00
commit 67b17d029a
25 changed files with 193 additions and 44 deletions

View file

@ -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 file

@ -153,8 +153,8 @@ class BaseTest < ActiveSupport::TestCase
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 file

@ -172,6 +172,10 @@ module ActionController
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 @@ module ActionController
# 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 @@ module ActionController
@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 file

@ -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 @@ module ActionDispatch
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 file

@ -22,7 +22,7 @@ module ActionDispatch
end
def cookies
HashWithIndifferentAccess.new(@request.cookies.merge(@response.cookies))
@request.cookies.merge(@response.cookies).with_indifferent_access
end
def redirect_to_url

View file

@ -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 @@ module ActionDispatch
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 file

@ -6,6 +6,7 @@ require 'active_support/core_ext/class/attribute'
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 @@ module ActionView
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 file

@ -124,6 +124,20 @@ class CookiesTest < ActionController::TestCase
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 @@ class CookiesTest < ActionController::TestCase
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 file

@ -2313,6 +2313,38 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
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 file

@ -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 file

@ -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 @@ class FormOptionsHelperTest < ActionView::TestCase
)
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 file

@ -72,7 +72,7 @@ module ActiveModel
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 file

@ -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 file

@ -484,19 +484,20 @@ module ActiveSupport
# 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 @@ module ActiveSupport
# 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 file

@ -64,21 +64,21 @@ module ActiveSupport
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 file

@ -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 @@ module ActiveSupport
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 file

@ -14,7 +14,7 @@ module I18n
@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 file

@ -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 file

@ -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 file

@ -2,7 +2,7 @@ require 'active_support/base64'
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 file

@ -37,7 +37,7 @@ class NilClass
# 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 file

@ -679,12 +679,12 @@ class CacheEntryTest < ActiveSupport::TestCase
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 file

@ -33,9 +33,11 @@ class WhinyNilTest < Test::Unit::TestCase
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 file

@ -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 file

@ -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.