aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/lib/action_controller/base/http_authentication.rb2
-rw-r--r--actionpack/lib/action_controller/base/mime_responds.rb262
-rw-r--r--actionpack/lib/action_controller/base/renderer.rb3
-rw-r--r--actionpack/lib/action_controller/base/request_forgery_protection.rb3
-rw-r--r--actionpack/lib/action_controller/routing.rb2
-rw-r--r--actionpack/lib/action_controller/routing/generation/url_rewriter.rb2
-rw-r--r--actionpack/lib/action_controller/routing/route_set.rb2
-rw-r--r--actionpack/lib/action_controller/testing/test_case.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_types.rb6
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb42
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb30
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb42
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb97
-rw-r--r--actionpack/test/controller/mime_responds_test.rb204
-rw-r--r--actionpack/test/dispatch/request_test.rb51
-rw-r--r--actionpack/test/fixtures/public/.gitignore2
-rw-r--r--actionpack/test/fixtures/respond_with/using_defaults.html.erb1
-rw-r--r--actionpack/test/fixtures/respond_with/using_defaults.js.rjs1
-rw-r--r--actionpack/test/fixtures/respond_with/using_defaults_with_type_list.js.rjs1
-rw-r--r--actionpack/test/fixtures/respond_with/using_defaults_with_type_list.xml.builder1
-rw-r--r--actionpack/test/fixtures/respond_with/using_resource.html.erb1
-rw-r--r--actionpack/test/template/active_record_helper_i18n_test.rb7
-rw-r--r--actionpack/test/template/active_record_helper_test.rb10
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb8
29 files changed, 626 insertions, 181 deletions
diff --git a/actionpack/lib/action_controller/base/http_authentication.rb b/actionpack/lib/action_controller/base/http_authentication.rb
index 2519f55269..525787bf92 100644
--- a/actionpack/lib/action_controller/base/http_authentication.rb
+++ b/actionpack/lib/action_controller/base/http_authentication.rb
@@ -276,7 +276,7 @@ module ActionController
#
# The nonce is opaque to the client. Composed of Time, and hash of Time with secret
# key from the Rails session secret generated upon creation of project. Ensures
- # the time cannot be modifed by client.
+ # the time cannot be modified by client.
def nonce(time = Time.now)
t = time.to_i
hashed = [t, secret_key]
diff --git a/actionpack/lib/action_controller/base/mime_responds.rb b/actionpack/lib/action_controller/base/mime_responds.rb
index ed0d58dba1..f4a4007a43 100644
--- a/actionpack/lib/action_controller/base/mime_responds.rb
+++ b/actionpack/lib/action_controller/base/mime_responds.rb
@@ -1,5 +1,55 @@
module ActionController #:nodoc:
module MimeResponds #:nodoc:
+ extend ActiveSupport::Concern
+
+ included do
+ class_inheritable_reader :mimes_for_respond_to
+ clear_respond_to
+ end
+
+ module ClassMethods
+ # Defines mimes that are rendered by default when invoking respond_with.
+ #
+ # Examples:
+ #
+ # respond_to :html, :xml, :json
+ #
+ # All actions on your controller will respond to :html, :xml and :json.
+ #
+ # But if you want to specify it based on your actions, you can use only and
+ # except:
+ #
+ # respond_to :html
+ # respond_to :xml, :json, :except => [ :edit ]
+ #
+ # The definition above explicits that all actions respond to :html. And all
+ # actions except :edit respond to :xml and :json.
+ #
+ # You can specify also only parameters:
+ #
+ # respond_to :rjs, :only => :create
+ #
+ def respond_to(*mimes)
+ options = mimes.extract_options!
+
+ only_actions = Array(options.delete(:only))
+ except_actions = Array(options.delete(:except))
+
+ mimes.each do |mime|
+ mime = mime.to_sym
+ mimes_for_respond_to[mime] = {}
+ mimes_for_respond_to[mime][:only] = only_actions unless only_actions.empty?
+ mimes_for_respond_to[mime][:except] = except_actions unless except_actions.empty?
+ end
+ end
+
+ # Clear all mimes in respond_to.
+ #
+ def clear_respond_to
+ write_inheritable_attribute(:mimes_for_respond_to, ActiveSupport::OrderedHash.new)
+ end
+ end
+
# Without web-service support, an action which collects the data for displaying a list of people
# might look something like this:
#
@@ -92,50 +142,187 @@ module ActionController #:nodoc:
# environment.rb as follows.
#
# Mime::Type.register "image/jpg", :jpg
- def respond_to(*types, &block)
- raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block
- block ||= lambda { |responder| types.each { |type| responder.send(type) } }
- responder = Responder.new(self)
- block.call(responder)
- responder.respond
- end
+ #
+ # Respond to also allows you to specify a common block for different formats by using any:
+ #
+ # def index
+ # @people = Person.find(:all)
+ #
+ # respond_to do |format|
+ # format.html
+ # format.any(:xml, :json) { render request.format.to_sym => @people }
+ # end
+ # end
+ #
+ # In the example above, if the format is xml, it will render:
+ #
+ # render :xml => @people
+ #
+ # Or if the format is json:
+ #
+ # render :json => @people
+ #
+ # Since this is a common pattern, you can use the class method respond_to
+ # with the respond_with method to have the same results:
+ #
+ # class PeopleController < ApplicationController
+ # respond_to :html, :xml, :json
+ #
+ # def index
+ # @people = Person.find(:all)
+ # respond_with(@person)
+ # end
+ # end
+ #
+ # Be sure to check respond_with and respond_to documentation for more examples.
+ #
+ def respond_to(*mimes, &block)
+ options = mimes.extract_options!
+ raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
- class Responder #:nodoc:
-
- def initialize(controller)
- @controller = controller
- @request = controller.request
- @response = controller.response
+ resource = options.delete(:with)
+ responder = Responder.new
- @mime_type_priority = @request.formats
+ mimes = collect_mimes_from_class_level if mimes.empty?
+ mimes.each { |mime| responder.send(mime) }
+ block.call(responder) if block_given?
- @order = []
- @responses = {}
+ if format = request.negotiate_mime(responder.order)
+ respond_to_block_or_template_or_resource(format, resource,
+ options, &responder.response_for(format))
+ else
+ head :not_acceptable
end
+ end
- def custom(mime_type, &block)
- mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
+ # respond_with allows you to respond an action with a given resource. It
+ # requires that you set your class with a :respond_to method with the
+ # formats allowed:
+ #
+ # class PeopleController < ApplicationController
+ # respond_to :html, :xml, :json
+ #
+ # def index
+ # @people = Person.find(:all)
+ # respond_with(@person)
+ # end
+ # end
+ #
+ # When a request comes with format :xml, the respond_with will first search
+ # for a template as person/index.xml, if the template is not available, it
+ # will see if the given resource responds to :to_xml.
+ #
+ # If neither are available, it will raise an error.
+ #
+ # Extra parameters given to respond_with are used when :to_format is invoked.
+ # This allows you to set status and location for several formats at the same
+ # time. Consider this restful controller response on create for both xml
+ # and json formats:
+ #
+ # class PeopleController < ApplicationController
+ # respond_to :xml, :json
+ #
+ # def create
+ # @person = Person.new(params[:person])
+ #
+ # if @person.save
+ # respond_with(@person, :status => :ok, :location => person_url(@person))
+ # else
+ # respond_with(@person.errors, :status => :unprocessable_entity)
+ # end
+ # end
+ # end
+ #
+ # Finally, respond_with also accepts blocks, as in respond_to. Let's take
+ # the same controller and create action above and add common html behavior:
+ #
+ # class PeopleController < ApplicationController
+ # respond_to :html, :xml, :json
+ #
+ # def create
+ # @person = Person.new(params[:person])
+ #
+ # if @person.save
+ # options = { :status => :ok, :location => person_url(@person) }
+ #
+ # respond_with(@person, options) do |format|
+ # format.html { redirect_to options[:location] }
+ # end
+ # else
+ # respond_with(@person.errors, :status => :unprocessable_entity) do
+ # format.html { render :action => :new }
+ # end
+ # end
+ # end
+ # end
+ #
+ def respond_with(resource, options={}, &block)
+ respond_to(options.merge!(:with => resource), &block)
+ end
- @order << mime_type
+ protected
- @responses[mime_type] ||= Proc.new do
- # TODO: Remove this when new base is merged in
- @controller.formats = [mime_type.to_sym]
- @controller.content_type = mime_type
- @controller.template.formats = [mime_type.to_sym]
+ def respond_to_block_or_template_or_resource(format, resource, options)
+ self.formats = [format.to_sym]
+ return yield if block_given?
- block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
+ begin
+ default_render
+ rescue ActionView::MissingTemplate => e
+ if resource && resource.respond_to?(:"to_#{format.to_sym}")
+ render options.merge(format.to_sym => resource)
+ else
+ raise e
end
end
+ end
+
+ # Collect mimes declared in the class method respond_to valid for the
+ # current action.
+ #
+ def collect_mimes_from_class_level #:nodoc:
+ action = action_name.to_sym
+
+ mimes_for_respond_to.keys.select do |mime|
+ config = mimes_for_respond_to[mime]
+
+ if config[:except]
+ !config[:except].include?(action)
+ elsif config[:only]
+ config[:only].include?(action)
+ else
+ true
+ end
+ end
+ end
+
+ class Responder #:nodoc:
+ attr_accessor :order
+
+ def initialize
+ @order, @responses = [], {}
+ end
def any(*args, &block)
if args.any?
args.each { |type| send(type, &block) }
else
- custom(@mime_type_priority.first, &block)
+ custom(Mime::ALL, &block)
end
end
-
+ alias :all :any
+
+ def custom(mime_type, &block)
+ mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
+
+ @order << mime_type
+ @responses[mime_type] ||= block
+ end
+
+ def response_for(mime)
+ @responses[mime] || @responses[Mime::ALL]
+ end
+
def self.generate_method_for_mime(mime)
sym = mime.is_a?(Symbol) ? mime : mime.to_sym
const = sym.to_s.upcase
@@ -152,7 +339,7 @@ module ActionController #:nodoc:
def method_missing(symbol, &block)
mime_constant = Mime.const_get(symbol.to_s.upcase)
-
+
if Mime::SET.include?(mime_constant)
self.class.generate_method_for_mime(mime_constant)
send(symbol, &block)
@@ -161,25 +348,6 @@ module ActionController #:nodoc:
end
end
- def respond
- for priority in @mime_type_priority
- if priority == Mime::ALL
- @responses[@order.first].call
- return
- else
- if @responses[priority]
- @responses[priority].call
- return # mime type match found, be happy and return
- end
- end
- end
-
- if @order.include?(Mime::ALL)
- @responses[Mime::ALL].call
- else
- @controller.send :head, :not_acceptable
- end
- end
end
end
end
diff --git a/actionpack/lib/action_controller/base/renderer.rb b/actionpack/lib/action_controller/base/renderer.rb
index 2fab501302..572da451ff 100644
--- a/actionpack/lib/action_controller/base/renderer.rb
+++ b/actionpack/lib/action_controller/base/renderer.rb
@@ -11,11 +11,10 @@ module ActionController
def render(options)
super
- options[:_template] ||= _action_view._partial
self.content_type ||= begin
mime = options[:_template].mime_type
formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first)
- end
+ end.to_s
response_body
end
diff --git a/actionpack/lib/action_controller/base/request_forgery_protection.rb b/actionpack/lib/action_controller/base/request_forgery_protection.rb
index 6ba86cd0be..ad06657f86 100644
--- a/actionpack/lib/action_controller/base/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/base/request_forgery_protection.rb
@@ -106,8 +106,7 @@ module ActionController #:nodoc:
!request.content_type.nil? && request.content_type.verify_request?
end
- # Sets the token value for the current session. Pass a <tt>:secret</tt> option
- # in +protect_from_forgery+ to add a custom salt to the hash.
+ # Sets the token value for the current session.
def form_authenticity_token
session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32)
end
diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb
index ce59866531..5b9ded83dd 100644
--- a/actionpack/lib/action_controller/routing.rb
+++ b/actionpack/lib/action_controller/routing.rb
@@ -139,7 +139,7 @@ module ActionController
# # In routes.rb
# map.with_options :controller => 'blog' do |blog|
# blog.show '', :action => 'list'
- # blog.delete 'delete/:id', :action => 'delete',
+ # blog.delete 'delete/:id', :action => 'delete'
# blog.edit 'edit/:id', :action => 'edit'
# end
#
diff --git a/actionpack/lib/action_controller/routing/generation/url_rewriter.rb b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb
index 16720b915b..9717582b5e 100644
--- a/actionpack/lib/action_controller/routing/generation/url_rewriter.rb
+++ b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb
@@ -93,7 +93,7 @@ module ActionController
#
# * <tt>:only_path</tt> - If true, the relative url is returned. Defaults to +false+.
# * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'.
- # * <tt>:host</tt> - Specifies the host the link should be targetted at.
+ # * <tt>:host</tt> - Specifies the host the link should be targeted at.
# If <tt>:only_path</tt> is false, this option must be
# provided either explicitly, or via +default_url_options+.
# * <tt>:port</tt> - Optionally specify the port to connect to.
diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb
index f5a4b1e1db..040a7e2cb6 100644
--- a/actionpack/lib/action_controller/routing/route_set.rb
+++ b/actionpack/lib/action_controller/routing/route_set.rb
@@ -155,7 +155,7 @@ module ActionController
def define_url_helper(route, name, kind, options)
selector = url_helper_name(name, kind)
- # The segment keys used for positional paramters
+ # The segment keys used for positional parameters
hash_access_method = hash_access_name(name, kind)
diff --git a/actionpack/lib/action_controller/testing/test_case.rb b/actionpack/lib/action_controller/testing/test_case.rb
index 7b4eda58e5..a11755b517 100644
--- a/actionpack/lib/action_controller/testing/test_case.rb
+++ b/actionpack/lib/action_controller/testing/test_case.rb
@@ -56,7 +56,7 @@ module ActionController
#
# ActionController::TestCase will automatically infer the controller under test
# from the test class name. If the controller cannot be inferred from the test
- # class name, you can explicity set it with +tests+.
+ # class name, you can explicitly set it with +tests+.
#
# class SpecialEdgeCaseWidgetsControllerTest < ActionController::TestCase
# tests WidgetController
@@ -182,7 +182,7 @@ module ActionController
@controller.send(:initialize_current_url)
end
end
-
+
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
def rescue_action_in_public!
@request.remote_addr = '208.77.188.166' # example.com
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 27f27e27fe..cc989d6625 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -84,7 +84,7 @@ module Mime
end
def lookup_by_extension(extension)
- EXTENSION_LOOKUP[extension]
+ EXTENSION_LOOKUP[extension.to_s]
end
# Registers an alias that's not used on mime type lookup, but can be referenced directly. Especially useful for
diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb
index 7c28cac419..68f37d2f65 100644
--- a/actionpack/lib/action_dispatch/http/mime_types.rb
+++ b/actionpack/lib/action_dispatch/http/mime_types.rb
@@ -2,7 +2,6 @@
# http://www.iana.org/assignments/media-types/
Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
-Mime::Type.register "*/*", :all
Mime::Type.register "text/plain", :text, [], %w(txt)
Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
Mime::Type.register "text/css", :css
@@ -18,4 +17,7 @@ Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
# http://www.ietf.org/rfc/rfc4627.txt
# http://www.json.org/JSONRequest.html
-Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest ) \ No newline at end of file
+Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
+
+# Create Mime::ALL but do not add it to the SET.
+Mime::ALL = Mime::Type.new("*/*", :all, [])
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 3f23a5af7a..5f9463eb91 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -161,7 +161,7 @@ module ActionDispatch
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
-
+ #
def format(view_path = [])
@env["action_dispatch.request.format"] ||=
if parameters[:format]
@@ -173,13 +173,11 @@ module ActionDispatch
end
end
+ # Expand raw_formats by converting Mime::ALL to the Mime::SET.
+ #
def formats
if ActionController::Base.use_accept_header
- if param = parameters[:format]
- Array.wrap(Mime[param])
- else
- accepts.dup
- end.tap do |ret|
+ raw_formats.tap do |ret|
if ret == ONLY_ALL
ret.replace Mime::SET
elsif all = ret.index(Mime::ALL)
@@ -187,7 +185,7 @@ module ActionDispatch
end
end
else
- [format] + Mime::SET
+ raw_formats + Mime::SET
end
end
@@ -232,7 +230,7 @@ module ActionDispatch
def xml_http_request?
!(@env['HTTP_X_REQUESTED_WITH'] !~ /XMLHttpRequest/i)
end
- alias xhr? :xml_http_request?
+ alias :xhr? :xml_http_request?
# Which IP addresses are "trusted proxies" that can be stripped from
# the right-hand-side of X-Forwarded-For
@@ -485,7 +483,35 @@ EOM
session['flash'] || {}
end
+ # Receives an array of mimes and return the first user sent mime that
+ # matches the order array.
+ #
+ def negotiate_mime(order)
+ raw_formats.each do |priority|
+ if priority == Mime::ALL
+ return order.first
+ elsif order.include?(priority)
+ return priority
+ end
+ end
+
+ order.include?(Mime::ALL) ? formats.first : nil
+ end
+
private
+
+ def raw_formats
+ if ActionController::Base.use_accept_header
+ if param = parameters[:format]
+ Array.wrap(Mime[param])
+ else
+ accepts.dup
+ end
+ else
+ [format]
+ end
+ end
+
def named_host?(host)
!(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
end
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 0f122d9232..4fd7f7d83c 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -160,11 +160,24 @@ module ActionView
#
# error_messages_for 'user'
#
+ # You can also supply an object:
+ #
+ # error_messages_for @user
+ #
+ # This will use the last part of the model name in the presentation. For instance, if
+ # this is a MyKlass::User object, this will use "user" as the name in the String. This
+ # is taken from MyKlass::User.model_name.human, which can be overridden.
+ #
# To specify more than one object, you simply list them; optionally, you can add an extra <tt>:object_name</tt> parameter, which
# will be the name used in the header message:
#
# error_messages_for 'user_common', 'user', :object_name => 'user'
#
+ # You can also use a number of objects, which will have the same naming semantics
+ # as a single object.
+ #
+ # error_messages_for @user, @post
+ #
# If the objects cannot be located as instance variables, you can add an extra <tt>:object</tt> parameter which gives the actual
# object (or array of objects to use):
#
@@ -176,15 +189,20 @@ module ActionView
def error_messages_for(*params)
options = params.extract_options!.symbolize_keys
- if object = options.delete(:object)
- objects = [object].flatten
- else
- objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
+ objects = Array.wrap(options.delete(:object) || params).map do |object|
+ unless object.respond_to?(:to_model)
+ object = instance_variable_get("@#{object}")
+ object = convert_to_model(object)
+ else
+ object = object.to_model
+ options[:object_name] ||= object.class.model_name.human
+ end
+ object
end
- objects.map! {|o| convert_to_model(o) }
+ objects.compact!
- count = objects.inject(0) {|sum, object| sum + object.errors.count }
+ count = objects.inject(0) {|sum, object| sum + object.errors.count }
unless count.zero?
html = {}
[:id, :class].each do |key|
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 3fde79dfa4..081003bcf3 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -557,7 +557,7 @@ module ActionView
# video_tag("trailer.ogg") # =>
# <video src="/videos/trailer.ogg" />
# video_tag("trailer.ogg", :controls => true, :autobuffer => true) # =>
- # <video autobuffer="true" controls="true" src="/videos/trailer.ogg" />
+ # <video autobuffer="autobuffer" controls="controls" src="/videos/trailer.ogg" />
# video_tag("trailer.m4v", :size => "16x10", :poster => "screenshot.png") # =>
# <video src="/videos/trailer.m4v" width="16" height="10" poster="/images/screenshot.png" />
# video_tag("/trailers/hd.avi", :size => "16x16") # =>
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 72fe9a3232..332743d55b 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -112,12 +112,12 @@ module ActionView
# ==== Options
# * <tt>:use_month_numbers</tt> - Set to true if you want to use month numbers rather than month names (e.g.
# "2" instead of "February").
- # * <tt>:use_short_month</tt> - Set to true if you want to use the abbreviated month name instead of the full
- # name (e.g. "Feb" instead of "February").
- # * <tt>:add_month_number</tt> - Set to true if you want to show both, the month's number and name (e.g.
+ # * <tt>:use_short_month</tt> - Set to true if you want to use abbreviated month names instead of full
+ # month names (e.g. "Feb" instead of "February").
+ # * <tt>:add_month_numbers</tt> - Set to true if you want to use both month numbers and month names (e.g.
# "2 - February" instead of "February").
# * <tt>:use_month_names</tt> - Set to an array with 12 month names if you want to customize month names.
- # Note: You can also use Rails' new i18n functionality for this.
+ # Note: You can also use Rails' i18n functionality for this.
# * <tt>:date_separator</tt> - Specifies a string to separate the date fields. Default is "" (i.e. nothing).
# * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Time.now.year - 5</tt>.
# * <tt>:end_year</tt> - Set the end year for the year select. Default is <tt>Time.now.year + 5</tt>.
@@ -128,7 +128,7 @@ module ActionView
# as a hidden field instead of showing a select field. Also note that this implicitly sets :discard_day to true.
# * <tt>:discard_year</tt> - Set to true if you don't want to show a year select. This includes the year
# as a hidden field instead of showing a select field.
- # * <tt>:order</tt> - Set to an array containing <tt>:day</tt>, <tt>:month</tt> and <tt>:year</tt> do
+ # * <tt>:order</tt> - Set to an array containing <tt>:day</tt>, <tt>:month</tt> and <tt>:year</tt> to
# customize the order in which the select fields are shown. If you leave out any of the symbols, the respective
# select will not be shown (like when you set <tt>:discard_xxx => true</tt>. Defaults to the order defined in
# the respective locale (e.g. [:year, :month, :day] in the en locale that ships with Rails).
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 6adbab175f..8cb5882aab 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -167,31 +167,31 @@ module ActionView
#
# In addition to the <tt>:include_blank</tt> option documented above,
# this method also supports a <tt>:model</tt> option, which defaults
- # to TimeZone. This may be used by users to specify a different time
- # zone model object. (See +time_zone_options_for_select+ for more
- # information.)
+ # to ActiveSupport::TimeZone. This may be used by users to specify a
+ # different time zone model object. (See +time_zone_options_for_select+
+ # for more information.)
#
- # You can also supply an array of TimeZone objects
+ # You can also supply an array of ActiveSupport::TimeZone objects
# as +priority_zones+, so that they will be listed above the rest of the
- # (long) list. (You can use TimeZone.us_zones as a convenience for
- # obtaining a list of the US time zones, or a Regexp to select the zones
+ # (long) list. (You can use ActiveSupport::TimeZone.us_zones as a convenience
+ # for obtaining a list of the US time zones, or a Regexp to select the zones
# of your choice)
#
# Finally, this method supports a <tt>:default</tt> option, which selects
- # a default TimeZone if the object's time zone is +nil+.
+ # a default ActiveSupport::TimeZone if the object's time zone is +nil+.
#
# Examples:
# time_zone_select( "user", "time_zone", nil, :include_blank => true)
#
# time_zone_select( "user", "time_zone", nil, :default => "Pacific Time (US & Canada)" )
#
- # time_zone_select( "user", 'time_zone', TimeZone.us_zones, :default => "Pacific Time (US & Canada)")
+ # time_zone_select( "user", 'time_zone', ActiveSupport::TimeZone.us_zones, :default => "Pacific Time (US & Canada)")
#
- # time_zone_select( "user", 'time_zone', [ TimeZone['Alaska'], TimeZone['Hawaii'] ])
+ # time_zone_select( "user", 'time_zone', [ ActiveSupport::TimeZone['Alaska'], ActiveSupport::TimeZone['Hawaii'] ])
#
# time_zone_select( "user", 'time_zone', /Australia/)
#
- # time_zone_select( "user", "time_zone", TZInfo::Timezone.all.sort, :model => TZInfo::Timezone)
+ # time_zone_select( "user", "time_zone", ActiveSupport::Timezone.all.sort, :model => ActiveSupport::Timezone)
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
InstanceTag.new(object, method, self, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
end
@@ -393,20 +393,20 @@ module ActionView
end
# Returns a string of option tags for pretty much any time zone in the
- # world. Supply a TimeZone name as +selected+ to have it marked as the
- # selected option tag. You can also supply an array of TimeZone objects
- # as +priority_zones+, so that they will be listed above the rest of the
- # (long) list. (You can use TimeZone.us_zones as a convenience for
- # obtaining a list of the US time zones, or a Regexp to select the zones
- # of your choice)
+ # world. Supply a ActiveSupport::TimeZone name as +selected+ to have it
+ # marked as the selected option tag. You can also supply an array of
+ # ActiveSupport::TimeZone objects as +priority_zones+, so that they will
+ # be listed above the rest of the (long) list. (You can use
+ # ActiveSupport::TimeZone.us_zones as a convenience for obtaining a list
+ # of the US time zones, or a Regexp to select the zones of your choice)
#
# The +selected+ parameter must be either +nil+, or a string that names
- # a TimeZone.
+ # a ActiveSupport::TimeZone.
#
- # By default, +model+ is the TimeZone constant (which can be obtained
- # in Active Record as a value object). The only requirement is that the
- # +model+ parameter be an object that responds to +all+, and returns
- # an array of objects that represent time zones.
+ # By default, +model+ is the ActiveSupport::TimeZone constant (which can
+ # be obtained in Active Record as a value object). The only requirement
+ # is that the +model+ parameter be an object that responds to +all+, and
+ # returns an array of objects that represent time zones.
#
# NOTE: Only the option tags are returned, you have to wrap this call in
# a regular HTML select tag.
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index 66d7592874..eea797abb5 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -8,7 +8,10 @@ module ActionView
module TagHelper
include ERB::Util
- BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked).to_set
+ BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer
+ autoplay controls loop selected hidden scoped async
+ defer reversed ismap seemless muted required
+ autofocus novalidate formnovalidate open).to_set
BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map {|attr| attr.to_sym })
# Returns an empty HTML tag of type +name+ which by default is XHTML
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index ad0733a7e1..c3ce4c671e 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -436,7 +436,7 @@ module ActionView
end
# Returns the current cycle string after a cycle has been started. Useful
- # for complex table highlighing or any other design need which requires
+ # for complex table highlighting or any other design need which requires
# the current cycle string in more than one place.
#
# ==== Example
@@ -544,7 +544,7 @@ module ActionView
left, right = $`, $'
# detect already linked URLs and URLs in the middle of a tag
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
- # do not change string; URL is alreay linked
+ # do not change string; URL is already linked
href
else
# don't include trailing punctuation character as part of the URL
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index de864f453c..c5a6d1f084 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -12,11 +12,11 @@ module ActionView
# Returns the URL for the set of +options+ provided. This takes the
# same options as +url_for+ in Action Controller (see the
- # documentation for ActionController::Base#url_for). Note that by default
- # <tt>:only_path</tt> is <tt>true</tt> so you'll get the relative /controller/action
- # instead of the fully qualified URL like http://example.com/controller/action.
+ # documentation for <tt>ActionController::Base#url_for</tt>). Note that by default
+ # <tt>:only_path</tt> is <tt>true</tt> so you'll get the relative "/controller/action"
+ # instead of the fully qualified URL like "http://example.com/controller/action".
#
- # When called from a view, url_for returns an HTML escaped url. If you
+ # When called from a view, +url_for+ returns an HTML escaped url. If you
# need an unescaped url, pass <tt>:escape => false</tt> in the +options+.
#
# ==== Options
@@ -34,8 +34,8 @@ module ActionView
#
# If you instead of a hash pass a record (like an Active Record or Active Resource) as the options parameter,
# you'll trigger the named route for that record. The lookup will happen on the name of the class. So passing
- # a Workshop object will attempt to use the workshop_path route. If you have a nested route, such as
- # admin_workshop_path you'll have to call that explicitly (it's impossible for url_for to guess that route).
+ # a Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as
+ # +admin_workshop_path+ you'll have to call that explicitly (it's impossible for +url_for+ to guess that route).
#
# ==== Examples
# <%= url_for(:action => 'index') %>
@@ -97,10 +97,10 @@ module ActionView
# Creates a link tag of the given +name+ using a URL created by the set
# of +options+. See the valid options in the documentation for
- # url_for. It's also possible to pass a string instead
+ # +url_for+. It's also possible to pass a string instead
# of an options hash to get a link tag that uses the value of the string as the
# href for the link, or use <tt>:back</tt> to link to the referrer - a JavaScript back
- # link will be used in place of a referrer if none exists. If nil is passed as
+ # link will be used in place of a referrer if none exists. If +nil+ is passed as
# a name, the link itself will become the name.
#
# ==== Signatures
@@ -117,27 +117,22 @@ module ActionView
# * <tt>:popup => true || array of window options</tt> - This will force the
# link to open in a popup window. By passing true, a default browser window
# will be opened with the URL. You can also specify an array of options
- # that are passed-thru to JavaScripts window.open method.
+ # that are passed to the <tt>window.open</tt> JavaScript call.
# * <tt>:method => symbol of HTTP verb</tt> - This modifier will dynamically
# create an HTML form and immediately submit the form for processing using
# the HTTP verb specified. Useful for having links perform a POST operation
# in dangerous actions like deleting a record (which search bots can follow
# while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt> and <tt>:put</tt>.
# Note that if the user has JavaScript disabled, the request will fall back
- # to using GET. If you are relying on the POST behavior, you should check
- # for it in your controller's action by using the request object's methods
- # for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
+ # to using GET. If <tt>:href => '#'</tt> is used and the user has JavaScript
+ # disabled clicking the link will have no effect. If you are relying on the
+ # POST behavior, you should check for it in your controller's action by using
+ # the request object's methods for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
# * The +html_options+ will accept a hash of html attributes for the link tag.
#
- # Note that if the user has JavaScript disabled, the request will fall back
- # to using GET. If <tt>:href => '#'</tt> is used and the user has JavaScript disabled
- # clicking the link will have no effect. If you are relying on the POST
- # behavior, your should check for it in your controller's action by using the
- # request object's methods for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
- #
# You can mix and match the +html_options+ with the exception of
- # <tt>:popup</tt> and <tt>:method</tt> which will raise an ActionView::ActionViewError
- # exception.
+ # <tt>:popup</tt> and <tt>:method</tt> which will raise an
+ # <tt>ActionView::ActionViewError</tt> exception.
#
# ==== Examples
# Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
@@ -170,9 +165,11 @@ module ActionView
# You can use a block as well if your link target is hard to fit into the name parameter. ERb example:
#
# <% link_to(@profile) do %>
- # <strong><%= @profile.name %></strong> -- <span>Check it out!!</span>
+ # <strong><%= @profile.name %></strong> -- <span>Check it out!</span>
# <% end %>
- # # => <a href="/profiles/1"><strong>David</strong> -- <span>Check it out!!</span></a>
+ # # => <a href="/profiles/1">
+ # <strong>David</strong> -- <span>Check it out!</span>
+ # </a>
#
# Classes and ids for CSS are easy to produce:
#
@@ -215,7 +212,9 @@ module ActionView
# # => <a href="/images/9" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form');
# f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;
# var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method');
- # m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a>
+ # m.setAttribute('value', 'delete');var s = document.createElement('input'); s.setAttribute('type', 'hidden');
+ # s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'Q/ttlxPYZ6R77B+vZ1sBkhj21G2isO9dpE6UtOHBApg=');
+ # f.appendChild(s)f.appendChild(m);f.submit(); };return false;">Delete Image</a>
def link_to(*args, &block)
if block_given?
options = args.first || {}
@@ -246,21 +245,21 @@ module ActionView
# by the set of +options+. This is the safest method to ensure links that
# cause changes to your data are not triggered by search bots or accelerators.
# If the HTML button does not work with your layout, you can also consider
- # using the link_to method with the <tt>:method</tt> modifier as described in
- # the link_to documentation.
+ # using the +link_to+ method with the <tt>:method</tt> modifier as described in
+ # the +link_to+ documentation.
#
- # The generated FORM element has a class name of <tt>button-to</tt>
+ # The generated form element has a class name of <tt>button-to</tt>
# to allow styling of the form itself and its children. You can control
# the form submission and input element behavior using +html_options+.
# This method accepts the <tt>:method</tt> and <tt>:confirm</tt> modifiers
- # described in the link_to documentation. If no <tt>:method</tt> modifier
+ # described in the +link_to+ documentation. If no <tt>:method</tt> modifier
# is given, it will default to performing a POST operation. You can also
# disable the button by passing <tt>:disabled => true</tt> in +html_options+.
# If you are using RESTful routes, you can pass the <tt>:method</tt>
# to change the HTTP verb used to submit the form.
#
# ==== Options
- # The +options+ hash accepts the same options at url_for.
+ # The +options+ hash accepts the same options as url_for.
#
# There are a few special +html_options+:
# * <tt>:method</tt> - Specifies the anchor name to be appended to the path.
@@ -317,7 +316,7 @@ module ActionView
# Creates a link tag of the given +name+ using a URL created by the set of
# +options+ unless the current request URI is the same as the links, in
# which case only the name is returned (or the given block is yielded, if
- # one exists). You can give link_to_unless_current a block which will
+ # one exists). You can give +link_to_unless_current+ a block which will
# specialize the default behavior (e.g., show a "Start Here" link rather
# than the link's text).
#
@@ -343,7 +342,7 @@ module ActionView
# <li><a href="/controller/about">About Us</a></li>
# </ul>
#
- # The implicit block given to link_to_unless_current is evaluated if the current
+ # The implicit block given to +link_to_unless_current+ is evaluated if the current
# action is the action given. So, if we had a comments page and wanted to render a
# "Go Back" link instead of a link to the comments page, we could do something like this...
#
@@ -360,7 +359,7 @@ module ActionView
# +options+ unless +condition+ is true, in which case only the name is
# returned. To specialize the default behavior (i.e., show a login link rather
# than just the plaintext link text), you can pass a block that
- # accepts the name or the full argument list for link_to_unless.
+ # accepts the name or the full argument list for +link_to_unless+.
#
# ==== Examples
# <%= link_to_unless(@current_user.nil?, "Reply", { :action => "reply" }) %>
@@ -391,8 +390,8 @@ module ActionView
# Creates a link tag of the given +name+ using a URL created by the set of
# +options+ if +condition+ is true, in which case only the name is
# returned. To specialize the default behavior, you can pass a block that
- # accepts the name or the full argument list for link_to_unless (see the examples
- # in link_to_unless).
+ # accepts the name or the full argument list for +link_to_unless+ (see the examples
+ # in +link_to_unless+).
#
# ==== Examples
# <%= link_to_if(@current_user.nil?, "Login", { :controller => "sessions", :action => "new" }) %>
@@ -416,27 +415,27 @@ module ActionView
# also used as the name of the link unless +name+ is specified. Additional
# HTML attributes for the link can be passed in +html_options+.
#
- # mail_to has several methods for hindering email harvesters and customizing
+ # +mail_to+ has several methods for hindering email harvesters and customizing
# the email itself by passing special keys to +html_options+.
#
# ==== Options
- # * <tt>:encode</tt> - This key will accept the strings "javascript" or "hex".
- # Passing "javascript" will dynamically create and encode the mailto: link then
+ # * <tt>:encode</tt> - This key will accept the strings "javascript" or "hex".
+ # Passing "javascript" will dynamically create and encode the mailto link then
# eval it into the DOM of the page. This method will not show the link on
# the page if the user has JavaScript disabled. Passing "hex" will hex
- # encode the +email_address+ before outputting the mailto: link.
- # * <tt>:replace_at</tt> - When the link +name+ isn't provided, the
+ # encode the +email_address+ before outputting the mailto link.
+ # * <tt>:replace_at</tt> - When the link +name+ isn't provided, the
# +email_address+ is used for the link label. You can use this option to
# obfuscate the +email_address+ by substituting the @ sign with the string
# given as the value.
- # * <tt>:replace_dot</tt> - When the link +name+ isn't provided, the
+ # * <tt>:replace_dot</tt> - When the link +name+ isn't provided, the
# +email_address+ is used for the link label. You can use this option to
# obfuscate the +email_address+ by substituting the . in the email with the
# string given as the value.
- # * <tt>:subject</tt> - Preset the subject line of the email.
+ # * <tt>:subject</tt> - Preset the subject line of the email.
# * <tt>:body</tt> - Preset the body of the email.
- # * <tt>:cc</tt> - Carbon Copy addition recipients on the email.
- # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
+ # * <tt>:cc</tt> - Carbon Copy addition recipients on the email.
+ # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
#
# ==== Examples
# mail_to "me@domain.com"
@@ -607,23 +606,23 @@ module ActionView
submit_function << "f.submit();"
end
- # Processes the _html_options_ hash, converting the boolean
+ # Processes the +html_options+ hash, converting the boolean
# attributes from true/false form into the form required by
# HTML/XHTML. (An attribute is considered to be boolean if
- # its name is listed in the given _bool_attrs_ array.)
+ # its name is listed in the given +bool_attrs+ array.)
#
- # More specifically, for each boolean attribute in _html_options_
+ # More specifically, for each boolean attribute in +html_options+
# given as:
#
- # "attr" => bool_value
+ # "attr" => bool_value
#
- # if the associated _bool_value_ evaluates to true, it is
+ # if the associated +bool_value+ evaluates to true, it is
# replaced with the attribute's name; otherwise the attribute is
- # removed from the _html_options_ hash. (See the XHTML 1.0 spec,
+ # removed from the +html_options+ hash. (See the XHTML 1.0 spec,
# section 4.5 "Attribute Minimization" for more:
# http://www.w3.org/TR/xhtml1/#h-4.5)
#
- # Returns the updated _html_options_ hash, which is also modified
+ # Returns the updated +html_options+ hash, which is also modified
# in place.
#
# Example:
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index 93ca34c41c..117f4ea4f0 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -86,6 +86,7 @@ class RespondToController < ActionController::Base
type.mobile { render :text => "Mobile" }
end
ensure
+ Mime::SET.delete(:mobile)
Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) }
end
@@ -98,6 +99,7 @@ class RespondToController < ActionController::Base
end
ensure
+ Mime::SET.delete(:mobile)
Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) }
end
@@ -132,6 +134,7 @@ class RespondToController < ActionController::Base
end
ensure
+ Mime::SET.delete(:iphone)
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
end
@@ -145,6 +148,7 @@ class RespondToController < ActionController::Base
end
ensure
+ Mime::SET.delete(:iphone)
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
end
@@ -162,7 +166,7 @@ class RespondToController < ActionController::Base
end
end
-class MimeControllerTest < ActionController::TestCase
+class RespondToControllerTest < ActionController::TestCase
tests RespondToController
def setup
@@ -436,10 +440,10 @@ class MimeControllerTest < ActionController::TestCase
def test_render_action_for_html
@controller.instance_eval do
def render(*args)
- unless args.empty?
- @action = args.first[:action] || action_name
- end
- response.body = "#{@action} - #{@template.formats}"
+ @action = args.first[:action] unless args.empty?
+ @action ||= action_name
+
+ response.body = "#{@action} - #{formats}"
end
end
@@ -467,7 +471,185 @@ class MimeControllerTest < ActionController::TestCase
end
end
+class RespondResource
+ undef_method :to_json
+
+ def to_xml
+ "XML"
+ end
+
+ def to_js
+ "JS"
+ end
+end
+
+class RespondWithController < ActionController::Base
+ respond_to :html, :json
+ respond_to :xml, :except => :using_defaults
+ respond_to :js, :only => :using_defaults
+
+ def using_defaults
+ respond_to do |format|
+ format.csv { render :text => "CSV" }
+ end
+ end
+
+ def using_defaults_with_type_list
+ respond_to(:js, :xml)
+ end
+
+ def using_resource
+ respond_with(RespondResource.new)
+ end
+
+ def using_resource_with_options
+ respond_with(RespondResource.new, :status => :unprocessable_entity) do |format|
+ format.js
+ end
+ end
+
+ def default_overwritten
+ respond_to do |format|
+ format.html { render :text => "HTML" }
+ end
+ end
+
+protected
+
+ def _render_js(js, options)
+ self.content_type ||= Mime::JS
+ self.response_body = js.respond_to?(:to_js) ? js.to_js : js
+ end
+end
+
+class InheritedRespondWithController < RespondWithController
+ clear_respond_to
+ respond_to :xml, :json
+
+ def index
+ respond_with(RespondResource.new) do |format|
+ format.json { render :text => "JSON" }
+ end
+ end
+end
+
+class RespondWithControllerTest < ActionController::TestCase
+ tests RespondWithController
+
+ def setup
+ super
+ ActionController::Base.use_accept_header = true
+ @request.host = "www.example.com"
+ end
+
+ def teardown
+ super
+ ActionController::Base.use_accept_header = false
+ end
+
+ def test_using_defaults
+ @request.accept = "*/*"
+ get :using_defaults
+ assert_equal "text/html", @response.content_type
+ assert_equal 'Hello world!', @response.body
+
+ @request.accept = "text/csv"
+ get :using_defaults
+ assert_equal "text/csv", @response.content_type
+ assert_equal "CSV", @response.body
+
+ @request.accept = "text/javascript"
+ get :using_defaults
+ assert_equal "text/javascript", @response.content_type
+ assert_equal '$("body").visualEffect("highlight");', @response.body
+ end
+
+ def test_using_defaults_with_type_list
+ @request.accept = "*/*"
+ get :using_defaults_with_type_list
+ assert_equal "text/javascript", @response.content_type
+ assert_equal '$("body").visualEffect("highlight");', @response.body
+
+ @request.accept = "application/xml"
+ get :using_defaults_with_type_list
+ assert_equal "application/xml", @response.content_type
+ assert_equal "<p>Hello world!</p>\n", @response.body
+ end
+
+ def test_using_resource
+ @request.accept = "text/html"
+ get :using_resource
+ assert_equal "text/html", @response.content_type
+ assert_equal "Hello world!", @response.body
+
+ @request.accept = "application/xml"
+ get :using_resource
+ assert_equal "application/xml", @response.content_type
+ assert_equal "XML", @response.body
+
+ @request.accept = "application/json"
+ assert_raise ActionView::MissingTemplate do
+ get :using_resource
+ end
+ end
+
+ def test_using_resource_with_options
+ @request.accept = "application/xml"
+ get :using_resource_with_options
+ assert_equal "application/xml", @response.content_type
+ assert_equal 422, @response.status
+ assert_equal "XML", @response.body
+
+ @request.accept = "text/javascript"
+ get :using_resource_with_options
+ assert_equal "text/javascript", @response.content_type
+ assert_equal 422, @response.status
+ assert_equal "JS", @response.body
+ end
+
+ def test_default_overwritten
+ get :default_overwritten
+ assert_equal "text/html", @response.content_type
+ assert_equal "HTML", @response.body
+ end
+
+ def test_clear_respond_to
+ @controller = InheritedRespondWithController.new
+ @request.accept = "text/html"
+ get :index
+ assert_equal 406, @response.status
+ end
+
+ def test_first_in_respond_to_has_higher_priority
+ @controller = InheritedRespondWithController.new
+ @request.accept = "*/*"
+ get :index
+ assert_equal "application/xml", @response.content_type
+ assert_equal "XML", @response.body
+ end
+
+ def test_not_acceptable
+ @request.accept = "application/xml"
+ get :using_defaults
+ assert_equal 406, @response.status
+
+ @request.accept = "text/html"
+ get :using_defaults_with_type_list
+ assert_equal 406, @response.status
+
+ @request.accept = "application/json"
+ get :using_defaults_with_type_list
+ assert_equal 406, @response.status
+
+ @request.accept = "text/javascript"
+ get :using_resource
+ assert_equal 406, @response.status
+ end
+end
+
class AbstractPostController < ActionController::Base
+ respond_to :html, :iphone
+
self.view_paths = File.dirname(__FILE__) + "/../fixtures/post_test/"
end
@@ -476,10 +658,7 @@ class PostController < AbstractPostController
around_filter :with_iphone
def index
- respond_to do |type|
- type.html
- type.iphone
- end
+ respond_to # It will use formats declared above
end
protected
@@ -489,17 +668,12 @@ protected
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
yield
ensure
+ Mime::SET.delete(:iphone)
Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) }
end
end
class SuperPostController < PostController
- def index
- respond_to do |type|
- type.html
- type.iphone
- end
- end
end
class MimeControllerLayoutsTest < ActionController::TestCase
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 3a85db8aa5..8ebf9aa186 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -338,16 +338,11 @@ class RequestTest < ActiveSupport::TestCase
end
test "XMLHttpRequest" do
- begin
- ActionController::Base.use_accept_header, old =
- false, ActionController::Base.use_accept_header
-
+ with_accept_header false do
request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
request.expects(:parameters).at_least_once.returns({})
assert request.xhr?
assert_equal Mime::JS, request.format
- ensure
- ActionController::Base.use_accept_header = old
end
end
@@ -396,10 +391,54 @@ class RequestTest < ActiveSupport::TestCase
assert_equal({"bar" => 2}, request.query_parameters)
end
+ test "formats with accept header" do
+ with_accept_header true do
+ request = stub_request 'HTTP_ACCEPT' => 'text/html'
+ request.expects(:parameters).at_least_once.returns({})
+ assert_equal [ Mime::HTML ], request.formats
+
+ request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
+ request.expects(:parameters).at_least_once.returns({})
+ assert_equal with_set(Mime::XML, Mime::HTML), request.formats
+ end
+
+ with_accept_header false do
+ request = stub_request
+ request.expects(:parameters).at_least_once.returns({ :format => :txt })
+ assert_equal with_set(Mime::TEXT), request.formats
+ end
+ end
+
+ test "negotiate_mime" do
+ with_accept_header true do
+ request = stub_request 'HTTP_ACCEPT' => 'text/html'
+ request.expects(:parameters).at_least_once.returns({})
+
+ assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON])
+ assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML])
+ assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL])
+
+ request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
+ request.expects(:parameters).at_least_once.returns({})
+ assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV])
+ assert_equal Mime::CSV, request.negotiate_mime([Mime::CSV, Mime::YAML])
+ end
+ end
+
protected
def stub_request(env={})
ActionDispatch::Request.new(env)
end
+ def with_set(*args)
+ args + Mime::SET
+ end
+
+ def with_accept_header(value)
+ ActionController::Base.use_accept_header, old = value, ActionController::Base.use_accept_header
+ yield
+ ensure
+ ActionController::Base.use_accept_header = old
+ end
end
diff --git a/actionpack/test/fixtures/public/.gitignore b/actionpack/test/fixtures/public/.gitignore
index 0c6759baec..312e635ee6 100644
--- a/actionpack/test/fixtures/public/.gitignore
+++ b/actionpack/test/fixtures/public/.gitignore
@@ -1 +1 @@
-absolute \ No newline at end of file
+absolute/*
diff --git a/actionpack/test/fixtures/respond_with/using_defaults.html.erb b/actionpack/test/fixtures/respond_with/using_defaults.html.erb
new file mode 100644
index 0000000000..6769dd60bd
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/using_defaults.html.erb
@@ -0,0 +1 @@
+Hello world! \ No newline at end of file
diff --git a/actionpack/test/fixtures/respond_with/using_defaults.js.rjs b/actionpack/test/fixtures/respond_with/using_defaults.js.rjs
new file mode 100644
index 0000000000..469fcd8e15
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/using_defaults.js.rjs
@@ -0,0 +1 @@
+page[:body].visual_effect :highlight \ No newline at end of file
diff --git a/actionpack/test/fixtures/respond_with/using_defaults_with_type_list.js.rjs b/actionpack/test/fixtures/respond_with/using_defaults_with_type_list.js.rjs
new file mode 100644
index 0000000000..469fcd8e15
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/using_defaults_with_type_list.js.rjs
@@ -0,0 +1 @@
+page[:body].visual_effect :highlight \ No newline at end of file
diff --git a/actionpack/test/fixtures/respond_with/using_defaults_with_type_list.xml.builder b/actionpack/test/fixtures/respond_with/using_defaults_with_type_list.xml.builder
new file mode 100644
index 0000000000..598d62e2fc
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/using_defaults_with_type_list.xml.builder
@@ -0,0 +1 @@
+xml.p "Hello world!" \ No newline at end of file
diff --git a/actionpack/test/fixtures/respond_with/using_resource.html.erb b/actionpack/test/fixtures/respond_with/using_resource.html.erb
new file mode 100644
index 0000000000..6769dd60bd
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/using_resource.html.erb
@@ -0,0 +1 @@
+Hello world! \ No newline at end of file
diff --git a/actionpack/test/template/active_record_helper_i18n_test.rb b/actionpack/test/template/active_record_helper_i18n_test.rb
index 63032e4e5c..047f81be29 100644
--- a/actionpack/test/template/active_record_helper_i18n_test.rb
+++ b/actionpack/test/template/active_record_helper_i18n_test.rb
@@ -3,11 +3,14 @@ require 'abstract_unit'
class ActiveRecordHelperI18nTest < Test::Unit::TestCase
include ActionView::Context
include ActionView::Helpers::ActiveModelHelper
-
+
attr_reader :request
def setup
@object = stub :errors => stub(:count => 1, :full_messages => ['full_messages'])
+ @object.stubs :to_model => @object
+ @object.stubs :class => stub(:model_name => stub(:human => ""))
+
@object_name = 'book_seller'
@object_name_without_underscore = 'book seller'
@@ -39,7 +42,7 @@ class ActiveRecordHelperI18nTest < Test::Unit::TestCase
I18n.expects(:t).with('', :default => '', :count => 1, :scope => [:activerecord, :models]).once.returns ''
error_messages_for(:object => @object, :locale => 'en')
end
-
+
def test_error_messages_for_given_object_name_it_translates_object_name
I18n.expects(:t).with(:header, :locale => 'en', :scope => [:activerecord, :errors, :template], :count => 1, :model => @object_name_without_underscore).returns "1 error prohibited this #{@object_name_without_underscore} from being saved"
I18n.expects(:t).with(@object_name, :default => @object_name_without_underscore, :count => 1, :scope => [:activerecord, :models]).once.returns @object_name_without_underscore
diff --git a/actionpack/test/template/active_record_helper_test.rb b/actionpack/test/template/active_record_helper_test.rb
index b07ce6cf5d..ec3384f15d 100644
--- a/actionpack/test/template/active_record_helper_test.rb
+++ b/actionpack/test/template/active_record_helper_test.rb
@@ -295,6 +295,16 @@ class ActiveRecordHelperTest < ActionView::TestCase
assert_equal '', error_messages_for('user', :object => nil)
end
+ def test_error_messages_for_model_objects
+ error = error_messages_for(@post)
+ assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>),
+ error
+
+ error = error_messages_for(@user, @post)
+ assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this user from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>),
+ error
+ end
+
def test_form_with_string_multipart
assert_dom_equal(
%(<form action="create" enctype="multipart/form-data" method="post"><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Create" /></form>),
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 921bfeb93a..08963946ab 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -158,8 +158,8 @@ class AssetTagHelperTest < ActionView::TestCase
VideoLinkToTag = {
%(video_tag("xml.ogg")) => %(<video src="/videos/xml.ogg" />),
- %(video_tag("rss.m4v", :autoplay => true, :controls => true)) => %(<video autoplay="true" controls="true" src="/videos/rss.m4v" />),
- %(video_tag("rss.m4v", :autobuffer => true)) => %(<video autobuffer="true" src="/videos/rss.m4v" />),
+ %(video_tag("rss.m4v", :autoplay => true, :controls => true)) => %(<video autoplay="autoplay" controls="controls" src="/videos/rss.m4v" />),
+ %(video_tag("rss.m4v", :autobuffer => true)) => %(<video autobuffer="autobuffer" src="/videos/rss.m4v" />),
%(video_tag("gold.m4v", :size => "160x120")) => %(<video height="120" src="/videos/gold.m4v" width="160" />),
%(video_tag("gold.m4v", "size" => "320x240")) => %(<video height="240" src="/videos/gold.m4v" width="320" />),
%(video_tag("trailer.ogg", :poster => "screenshot.png")) => %(<video poster="/images/screenshot.png" src="/videos/trailer.ogg" />),
@@ -168,7 +168,7 @@ class AssetTagHelperTest < ActionView::TestCase
%(video_tag("error.avi", "size" => "x")) => %(<video src="/videos/error.avi" />),
%(video_tag("http://media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="http://media.rubyonrails.org/video/rails_blog_2.mov" />),
%(video_tag(["multiple.ogg", "multiple.avi"])) => %(<video><source src="multiple.ogg" /><source src="multiple.avi" /></video>),
- %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="true" height="120" width="160"><source src="multiple.ogg" /><source src="multiple.avi" /></video>)
+ %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="controls" height="120" width="160"><source src="multiple.ogg" /><source src="multiple.avi" /></video>)
}
AudioPathToTag = {
@@ -187,7 +187,7 @@ class AssetTagHelperTest < ActionView::TestCase
AudioLinkToTag = {
%(audio_tag("xml.wav")) => %(<audio src="/audios/xml.wav" />),
- %(audio_tag("rss.wav", :autoplay => true, :controls => true)) => %(<audio autoplay="true" controls="true" src="/audios/rss.wav" />),
+ %(audio_tag("rss.wav", :autoplay => true, :controls => true)) => %(<audio autoplay="autoplay" controls="controls" src="/audios/rss.wav" />),
%(audio_tag("http://media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="http://media.rubyonrails.org/audio/rails_blog_2.mov" />),
}