提交 67b17d02 编写于 作者: J Jon Leighton

Merge branch 'master' into nested_has_many_through

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 [...]
......@@ -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
......
......@@ -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
......
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
......
......@@ -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
......
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
......
......@@ -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
......
......@@ -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"]
......
......@@ -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
......
......@@ -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
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>"
......
......@@ -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
......
......@@ -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, '') }
......
......@@ -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.
......
......@@ -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
......
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
......
......@@ -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.
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册