Permalink
Browse files

Merge branch 'master' of git@github.com:lifo/docrails

* 'master' of git@github.com:lifo/docrails: (319 commits)
  deletes screencast promo in prologue, its proper place is the References section
  Typo fix
  list -> index
  in caching guide, RESTifies some examples, revised conventions here and there
  Tech edit of caching guide from Gregg Pollack
  Fix typo in comment: hide_actions -> hide_action
  Fix two typos in a comment in config/initializers/backtrace_silencers.rb
  With -> with in a title
  Clear up a little confusing wording in Routing Guide.
  copyedited minor details in the rack on rails guide
  remove piece of UrlWriter documentation claiming that you can access named routes as its class methods
  Add note about change to session options
  TRUNCATE is also a MySQL DDL statement, so document this is a possible caveat when using transactions and savepoints.
  Improve documentation for ActiveResource::Validations, fix typos
  Fix typos in ActiveResource::Base documentation, use present tense, reword confusing sentences
  Update ActiveResource::Connection documentation to use present tense
  Fix typos in Active Resource README
  Fix a small typo
  ensure authors get warnings about broken links, and ensure end users don't
  in guides generator, warn about duplicate header IDs only if WARN_DUPLICATE_HEADERS
  ...
  • Loading branch information...
2 parents ab55ddc + 9e9469e commit e878c3e44a8dba19c1188b636e25ec1bc2165116 @radar radar committed Apr 4, 2009
Showing 311 changed files with 6,219 additions and 3,217 deletions.
@@ -1,10 +1,7 @@
-*Edge*
+*2.3.2 [Final] (March 15, 2009)*
* Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones]
-
-*2.3.0 [RC1] (February 1st, 2009)*
-
* Fixed RFC-2045 quoted-printable bug #1421 [squadette]
* Fixed that no body charset would be set when there are attachments present #740 [Paweł Kondzior]
@@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
- s.add_dependency('actionpack', '= 2.3.0' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.3.2' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
@@ -58,4 +58,5 @@ module Net
end
autoload :MailHelper, 'action_mailer/mail_helper'
-autoload :TMail, 'action_mailer/vendor/tmail'
+
+require 'action_mailer/vendor/tmail'
@@ -479,7 +479,7 @@ def create!(method_name, *parameters) #:nodoc:
)
end
unless @parts.empty?
- @content_type = "multipart/alternative"
+ @content_type = "multipart/alternative" if @content_type !~ /^multipart/
@parts = sort_parts(@parts, @implicit_parts_order)
end
end
@@ -88,7 +88,10 @@ def to_mail(defaults)
part.parts << prt
end
- part.set_content_type(real_content_type, nil, ctype_attrs) if real_content_type =~ /multipart/
+ if real_content_type =~ /multipart/
+ ctype_attrs.delete 'charset'
+ part.set_content_type(real_content_type, nil, ctype_attrs)
+ end
end
headers.each { |k,v| part[k] = v }
@@ -1150,7 +1150,7 @@ def test_format_style
assert_equal(Text::Format::JUSTIFY, @format_o.format_style)
assert_match(/^of freedom, and that government of the people, by the people, for the$/,
@format_o.format(GETTYSBURG).split("\n")[-3])
- assert_raises(ArgumentError) { @format_o.format_style = 33 }
+ assert_raise(ArgumentError) { @format_o.format_style = 33 }
end
def test_tag_paragraph
@@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 0
+ TINY = 2
STRING = [MAJOR, MINOR, TINY].join('.')
end
@@ -21,10 +21,12 @@ def nolayout(recipient)
body render(:inline => "Hello, <%= @world %>", :layout => false, :body => { :world => "Earth" })
end
- def multipart(recipient)
+ def multipart(recipient, type = nil)
recipients recipient
subject "You have a mail"
from "tester@example.com"
+
+ content_type(type) if type
end
end
@@ -64,6 +66,19 @@ def test_should_pickup_default_layout
def test_should_pickup_multipart_layout
mail = AutoLayoutMailer.create_multipart(@recipient)
+ assert_equal "multipart/alternative", mail.content_type
+ assert_equal 2, mail.parts.size
+
+ assert_equal 'text/plain', mail.parts.first.content_type
+ assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
+
+ assert_equal 'text/html', mail.parts.last.content_type
+ assert_equal "Hello from layout text/html multipart", mail.parts.last.body
+ end
+
+ def test_should_pickup_multipartmixed_layout
+ mail = AutoLayoutMailer.create_multipart(@recipient, "multipart/mixed")
+ assert_equal "multipart/mixed", mail.content_type
assert_equal 2, mail.parts.size
assert_equal 'text/plain', mail.parts.first.content_type
@@ -73,6 +88,19 @@ def test_should_pickup_multipart_layout
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
end
+ def test_should_fix_multipart_layout
+ mail = AutoLayoutMailer.create_multipart(@recipient, "text/plain")
+ assert_equal "multipart/alternative", mail.content_type
+ assert_equal 2, mail.parts.size
+
+ assert_equal 'text/plain', mail.parts.first.content_type
+ assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
+
+ assert_equal 'text/html', mail.parts.last.content_type
+ assert_equal "Hello from layout text/html multipart", mail.parts.last.body
+ end
+
+
def test_should_pickup_layout_given_to_render
mail = AutoLayoutMailer.create_spam(@recipient)
assert_equal "Spammer layout Hello, Earth", mail.body.strip
@@ -330,6 +330,7 @@ def test_nested_parts
assert_equal "multipart/mixed", created.content_type
assert_equal "multipart/alternative", created.parts.first.content_type
assert_equal "bar", created.parts.first.header['foo'].to_s
+ assert_nil created.parts.first.charset
assert_equal "text/plain", created.parts.first.parts.first.content_type
assert_equal "text/html", created.parts.first.parts[1].content_type
assert_equal "application/octet-stream", created.parts[1].content_type
@@ -1068,7 +1069,7 @@ def test_should_not_respond_to_method_where_deliver_is_not_a_suffix
end
def test_should_still_raise_exception_with_expected_message_when_calling_an_undefined_method
- error = assert_raises NoMethodError do
+ error = assert_raise NoMethodError do
RespondToMailer.not_a_method
end
@@ -26,7 +26,7 @@ def test_mailer_class_is_correctly_inferred
end
def test_determine_default_mailer_raises_correct_error
- assert_raises(ActionMailer::NonInferrableMailerError) do
+ assert_raise(ActionMailer::NonInferrableMailerError) do
self.class.determine_default_mailer("NotAMailerTest")
end
end
@@ -84,7 +84,7 @@ def test_assert_no_emails
end
def test_assert_emails_too_few_sent
- error = assert_raises ActiveSupport::TestCase::Assertion do
+ error = assert_raise ActiveSupport::TestCase::Assertion do
assert_emails 2 do
TestHelperMailer.deliver_test
end
@@ -94,7 +94,7 @@ def test_assert_emails_too_few_sent
end
def test_assert_emails_too_many_sent
- error = assert_raises ActiveSupport::TestCase::Assertion do
+ error = assert_raise ActiveSupport::TestCase::Assertion do
assert_emails 1 do
TestHelperMailer.deliver_test
TestHelperMailer.deliver_test
@@ -105,7 +105,7 @@ def test_assert_emails_too_many_sent
end
def test_assert_no_emails_failure
- error = assert_raises ActiveSupport::TestCase::Assertion do
+ error = assert_raise ActiveSupport::TestCase::Assertion do
assert_no_emails do
TestHelperMailer.deliver_test
end
View
@@ -1,14 +1,19 @@
-*Edge*
+*2.3.2 [Final] (March 15, 2009)*
+
+* Fixed that redirection would just log the options, not the final url (which lead to "Redirected to #<Post:0x23150b8>") [DHH]
+
+* Added ability to pass in :public => true to fresh_when, stale?, and expires_in to make the request proxy cachable #2095 [Gregg Pollack]
+
+* Fixed that passing a custom form builder would be forwarded to nested fields_for calls #2023 [Eloy Duran/Nate Wiger]
+
+* Form option helpers now support disabled option tags and the use of lambdas for selecting/disabling option tags from collections #837 [Tekin]
* Added partial scoping to TranslationHelper#translate, so if you call translate(".foo") from the people/index.html.erb template, you'll actually be calling I18n.translate("people.index.foo") [DHH]
* Fix a syntax error in current_page?() that was prevent matches against URL's with multiple query parameters #1385, #1868 [chris finne/Andrew White]
* Added localized rescue template when I18n.locale is set (ex: public/404.da.html) #1835 [José Valim]
-
-*2.3.0 [RC1] (February 1st, 2009)*
-
* Make the form_for and fields_for helpers support the new Active Record nested update options. #1202 [Eloy Duran]
<% form_for @person do |person_form| %>
View
@@ -80,8 +80,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true
s.requirements << 'none'
- s.add_dependency('activesupport', '= 2.3.0' + PKG_BUILD)
- s.add_dependency('rack', '>= 0.9.0')
+ s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'action_controller'
@@ -31,7 +31,12 @@
end
end
-require 'action_controller/vendor/rack-1.0/rack'
+begin
+ gem 'rack', '~> 1.0.0'
+ require 'rack'
+rescue Gem::LoadError
+ require 'action_controller/vendor/rack-1.0/rack'
+end
module ActionController
# TODO: Review explicit to see if they will automatically be handled by
@@ -22,7 +22,7 @@ class MethodNotAllowed < ActionControllerError #:nodoc:
attr_reader :allowed_methods
def initialize(*allowed_methods)
- super("Only #{allowed_methods.to_sentence} requests are allowed.")
+ super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.")
@allowed_methods = allowed_methods
end
@@ -408,7 +408,7 @@ def controller_path
# Return an array containing the names of public methods that have been marked hidden from the action processor.
# By default, all methods defined in ActionController::Base and included modules are hidden.
- # More methods can be hidden using <tt>hide_actions</tt>.
+ # More methods can be hidden using <tt>hide_action</tt>.
def hidden_actions
read_inheritable_attribute(:hidden_actions) || write_inheritable_attribute(:hidden_actions, [])
end
@@ -908,12 +908,14 @@ def render(options = nil, extra_options = {}, &block) #:doc:
end
options = extra_options
+ elsif !options.is_a?(Hash)
+ extra_options[:partial] = options
+ options = extra_options
end
layout = pick_layout(options)
response.layout = layout.path_without_format_and_extension if layout
logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
- layout = layout.path_without_format_and_extension if layout
if content_type = options[:content_type]
response.content_type = content_type.to_s
@@ -982,6 +984,7 @@ def render(options = nil, extra_options = {}, &block) #:doc:
# of sending it as the response body to the browser.
def render_to_string(options = nil, &block) #:doc:
render(options, &block)
+ response.body
ensure
response.content_type = nil
erase_render_results
@@ -1018,7 +1021,7 @@ def head(*args)
# Clears the rendered results, allowing for another render to be performed.
def erase_render_results #:nodoc:
- response.body = nil
+ response.body = []
@performed_render = false
end
@@ -1101,7 +1104,6 @@ def redirect_to(options = {}, response_status = {}) #:doc:
end
response.redirected_to = options
- logger.info("Redirected to #{options}") if logger && logger.info?
case options
# The scheme name consist of a letter followed by any combination of
@@ -1124,6 +1126,7 @@ def redirect_to(options = {}, response_status = {}) #:doc:
def redirect_to_full_url(url, status)
raise DoubleRenderError if performed?
+ logger.info("Redirected to #{url}") if logger && logger.info?
response.redirect(url, interpret_status(status))
@performed_redirect = true
end
@@ -1133,6 +1136,11 @@ def redirect_to_full_url(url, status)
# request is considered stale and should be generated from scratch. Otherwise,
# it's fresh and we don't need to generate anything and a reply of "304 Not Modified" is sent.
#
+ # Parameters:
+ # * <tt>:etag</tt>
+ # * <tt>:last_modified</tt>
+ # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches).
+ #
# Example:
#
# def show
@@ -1153,20 +1161,34 @@ def stale?(options)
# Sets the etag, last_modified, or both on the response and renders a
# "304 Not Modified" response if the request is already fresh.
#
+ # Parameters:
+ # * <tt>:etag</tt>
+ # * <tt>:last_modified</tt>
+ # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches).
+ #
# Example:
#
# def show
# @article = Article.find(params[:id])
- # fresh_when(:etag => @article, :last_modified => @article.created_at.utc)
+ # fresh_when(:etag => @article, :last_modified => @article.created_at.utc, :public => true)
# end
#
# This will render the show template if the request isn't sending a matching etag or
# If-Modified-Since header and just a "304 Not Modified" response if there's a match.
+ #
def fresh_when(options)
- options.assert_valid_keys(:etag, :last_modified)
+ options.assert_valid_keys(:etag, :last_modified, :public)
response.etag = options[:etag] if options[:etag]
response.last_modified = options[:last_modified] if options[:last_modified]
+
+ if options[:public]
+ cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
+ cache_control.delete("private")
+ cache_control.delete("no-cache")
+ cache_control << "public"
+ response.headers["Cache-Control"] = cache_control.join(', ')
+ end
if request.fresh?(response)
head :not_modified
@@ -1178,15 +1200,26 @@ def fresh_when(options)
#
# Examples:
# expires_in 20.minutes
- # expires_in 3.hours, :private => false
- # expires in 3.hours, 'max-stale' => 5.hours, :private => nil, :public => true
+ # expires_in 3.hours, :public => true
+ # expires in 3.hours, 'max-stale' => 5.hours, :public => true
#
# This method will overwrite an existing Cache-Control header.
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
def expires_in(seconds, options = {}) #:doc:
- cache_options = { 'max-age' => seconds, 'private' => true }.symbolize_keys.merge!(options.symbolize_keys)
- cache_options.delete_if { |k,v| v.nil? or v == false }
- cache_control = cache_options.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
+ cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
+
+ cache_control << "max-age=#{seconds}"
+ cache_control.delete("no-cache")
+ if options[:public]
+ cache_control.delete("private")
+ cache_control << "public"
+ else
+ cache_control << "private"
+ end
+
+ # This allows for additional headers to be passed through like 'max-stale' => 5.hours
+ cache_control += options.symbolize_keys.reject{|k,v| k == :public || k == :private }.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
+
response.headers["Cache-Control"] = cache_control.join(', ')
end
@@ -1215,13 +1248,12 @@ def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
if append_response
- response.body ||= ''
- response.body << text.to_s
+ response.body_parts << text.to_s
else
response.body = case text
- when Proc then text
- when nil then " " # Safari doesn't pass the headers of the return if the response is zero length
- else text.to_s
+ when Proc then text
+ when nil then [" "] # Safari doesn't pass the headers of the return if the response is zero length
+ else [text.to_s]
end
end
end
@@ -1298,7 +1330,7 @@ def perform_action
rescue ActionView::MissingTemplate => e
# Was the implicit template missing, or was it another template?
if e.path == default_template_name
- raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller
+ raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence(:locale => :en)}", caller
else
raise e
end
Oops, something went wrong.

0 comments on commit e878c3e

Please sign in to comment.