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

This commit is contained in:
aditya-kapoor 2013-09-01 18:05:04 +05:30
commit 6b9b0767bf
301 changed files with 3959 additions and 2709 deletions

12
Gemfile
View File

@ -61,13 +61,13 @@ platforms :ruby do
end
platforms :jruby do
git 'git://github.com/jruby/activerecord-jdbc-adapter.git' do
gem 'activerecord-jdbcsqlite3-adapter'
group :db do
gem 'activerecord-jdbcmysql-adapter'
gem 'activerecord-jdbcpostgresql-adapter'
end
git 'git://github.com/jruby/activerecord-jdbc-adapter.git' do
gem 'activerecord-jdbcsqlite3-adapter'
group :db do
gem 'activerecord-jdbcmysql-adapter'
gem 'activerecord-jdbcpostgresql-adapter'
end
end
end
# gems that are necessary for ActiveRecord tests with Oracle database

View File

@ -8,11 +8,6 @@ pattern.
Understanding the MVC pattern is key to understanding Rails. MVC divides your
application into three layers, each with a specific responsibility.
The _View layer_ is composed of "templates" that are responsible for providing
appropriate representations of your application's resources. Templates can
come in a variety of formats, but most view templates are HTML with embedded
Ruby code (ERB files).
The _Model layer_ represents your domain model (such as Account, Product,
Person, Post, etc.) and encapsulates the business logic that is specific to
your application. In Rails, database-backed model classes are derived from
@ -24,16 +19,26 @@ as provided by the Active Model module. You can read more about Active Record
in its [README](activerecord/README.rdoc).
The _Controller layer_ is responsible for handling incoming HTTP requests and
providing a suitable response. Usually this means returning HTML, but Rails
controllers can also generate XML, JSON, PDFs, mobile-specific views, and
more. Controllers manipulate models and render view templates in order to
generate the appropriate HTTP response.
providing a suitable response. Usually this means returning HTML, but Rails controllers
can also generate XML, JSON, PDFs, mobile-specific views, and more. Controllers load and
manipulate models, and render view templates in order to generate the appropriate HTTP response.
In Rails, incoming requests are routed by Action Dispatch to an appropriate controller, and
controller classes are derived from `ActionController::Base`. Action Dispatch and Action Controller
are bundled together in Action Pack. You can read more about Action Pack in its
[README](actionpack/README.rdoc).
In Rails, the Controller and View layers are handled together by Action Pack.
These two layers are bundled in a single package due to their heavy interdependence.
This is unlike the relationship between Active Record and Action Pack, which are
independent. Each of these packages can be used independently outside of Rails. You
can read more about Action Pack in its [README](actionpack/README.rdoc).
The _View layer_ is composed of "templates" that are responsible for providing
appropriate representations of your application's resources. Templates can
come in a variety of formats, but most view templates are HTML with embedded
Ruby code (ERB files). Views are typically rendered to generate a controller response,
or to generate the body of an email. In Rails, View generation is handled by Action View.
You can read more about Action View in its [README](actionview/README.rdoc).
Active Record, Action Pack, and Action View can each be used independently outside Rails.
In addition to them, Rails also comes with Action Mailer ([README](actionmailer/README.rdoc)), a library
to generate and send emails; and Active Support ([README](activesupport/README.rdoc)), a collection of
utility classes and standard library extensions that are useful for Rails, and may also be used
independently outside Rails.
## Getting Started

View File

@ -20,6 +20,7 @@ Gem::Specification.new do |s|
s.requirements << 'none'
s.add_dependency 'actionpack', version
s.add_dependency 'actionview', version
s.add_dependency 'mail', '~> 2.5.4'
end

View File

@ -22,7 +22,6 @@
#++
require 'abstract_controller'
require 'action_view'
require 'action_mailer/version'
# Common Active Support usage in Action Mailer

View File

@ -3,6 +3,7 @@ require 'action_mailer/collector'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/module/anonymous'
require 'action_mailer/log_subscriber'
module ActionMailer
@ -361,18 +362,17 @@ module ActionMailer
# <tt>delivery_method :test</tt>. Most useful for unit and functional testing.
class Base < AbstractController::Base
include DeliveryMethods
abstract!
include AbstractController::Logger
include AbstractController::Rendering
include AbstractController::Layouts
include AbstractController::Logger
include AbstractController::Helpers
include AbstractController::Translation
include AbstractController::AssetPaths
include AbstractController::Callbacks
self.protected_instance_variables = [:@_action_has_layout]
helper ActionMailer::MailHelper
private_class_method :new #:nodoc:
@ -385,6 +385,10 @@ module ActionMailer
parts_order: [ "text/plain", "text/enriched", "text/html" ]
}.freeze
def self.default_protected_instance_vars
super.concat [:@_action_has_layout]
end
class << self
# Register one or more Observers which will be notified when mail is delivered.
def register_observers(*observers)

View File

@ -1,3 +1,5 @@
require 'active_support/log_subscriber'
module ActionMailer
# Implements the ActiveSupport::LogSubscriber for logging notifications when
# email is delivered and received.

View File

@ -11,11 +11,11 @@ end
require 'active_support/testing/autorun'
require 'action_mailer'
require 'action_mailer/test_case'
require 'mail'
silence_warnings do
# These external dependencies have warnings :/
require 'mail'
end
# Emulate AV railtie
require 'action_view'
ActionMailer::Base.send(:include, ActionView::Layouts)
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true

View File

@ -1,4 +1,5 @@
require 'abstract_unit'
require 'action_view'
require 'action_controller'
class I18nTestMailer < ActionMailer::Base
@ -14,6 +15,9 @@ class I18nTestMailer < ActionMailer::Base
end
end
# Emulate AV railtie
ActionController::Base.superclass.send(:include, ActionView::Layouts)
class TestController < ActionController::Base
def send_mail
I18nTestMailer.mail_with_i18n_subject("test@localhost").deliver

View File

@ -1,3 +1,16 @@
* Introduce `BasicRendering` which is the most basic rendering implementation. It
allows to `render :text` and `render :nothing` without depending on Action View.
*Łukasz Strzałkowski*
* Separate Action View completely from Action Pack.
*Łukasz Strzałkowski*
* Development mode exceptions are rendered in text format in case of XHR request.
*Kir Shatrov*
* Fix an issue where :if and :unless controller action procs were being run
before checking for the correct action in the :only and :unless options.

View File

@ -20,11 +20,11 @@ Gem::Specification.new do |s|
s.requirements << 'none'
s.add_dependency 'activesupport', version
s.add_dependency 'actionview', version
s.add_dependency 'rack', '~> 1.5.2'
s.add_dependency 'rack-test', '~> 0.6.2'
s.add_development_dependency 'activemodel', version
s.add_development_dependency 'tzinfo', '~> 0.3.37'
s.add_development_dependency 'actionview', version
s.add_development_dependency 'activemodel', version
s.add_development_dependency 'tzinfo', '~> 0.3.37'
end

View File

@ -10,12 +10,11 @@ module AbstractController
autoload :Base
autoload :Callbacks
autoload :Collector
autoload :DoubleRenderError, "abstract_controller/rendering"
autoload :Helpers
autoload :Layouts
autoload :Logger
autoload :Rendering
autoload :Translation
autoload :AssetPaths
autoload :ViewPaths
autoload :UrlFor
end

View File

@ -114,6 +114,11 @@ module AbstractController
end
end
# Define some internal variables that should not be propagated to the view.
def self.default_protected_instance_vars
[]
end
abstract!
# Calls the action going through the entire action dispatch stack.

View File

@ -1,5 +1,5 @@
require "abstract_controller/base"
require "action_view"
require 'active_support/concern'
require 'active_support/core_ext/class/attribute'
module AbstractController
class DoubleRenderError < Error
@ -10,91 +10,11 @@ module AbstractController
end
end
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
# it will trigger the lookup_context and consequently expire the cache.
class I18nProxy < ::I18n::Config #:nodoc:
attr_reader :original_config, :lookup_context
def initialize(original_config, lookup_context)
original_config = original_config.original_config if original_config.respond_to?(:original_config)
@original_config, @lookup_context = original_config, lookup_context
end
def locale
@original_config.locale
end
def locale=(value)
@lookup_context.locale = value
end
end
module Rendering
extend ActiveSupport::Concern
include AbstractController::ViewPaths
included do
class_attribute :protected_instance_variables
self.protected_instance_variables = []
end
# Overwrite process to setup I18n proxy.
def process(*) #:nodoc:
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
super
ensure
I18n.config = old_config
end
module ClassMethods
def view_context_class
@view_context_class ||= begin
routes = respond_to?(:_routes) && _routes
helpers = respond_to?(:_helpers) && _helpers
Class.new(ActionView::Base) do
if routes
include routes.url_helpers
include routes.mounted_helpers
end
if helpers
include helpers
end
end
end
end
end
attr_internal_writer :view_context_class
def view_context_class
@_view_context_class ||= self.class.view_context_class
end
# An instance of a view class. The default view class is ActionView::Base
#
# The view class must have the following methods:
# View.new[lookup_context, assigns, controller]
# Create a new ActionView instance for a controller
# View#render[options]
# Returns String with the rendered template
#
# Override this method in a module to change the default behavior.
def view_context
view_context_class.new(view_renderer, view_assigns, self)
end
# Returns an object that is able to render templates.
def view_renderer
@_view_renderer ||= ActionView::Renderer.new(lookup_context)
end
# Normalize arguments, options and then delegates render_to_body and
# sticks the result in self.response_body.
def render(*args, &block)
options = _normalize_render(*args, &block)
self.response_body = render_to_body(options)
def self.default_protected_instance_vars
super.concat [:@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config]
end
# Raw rendering of a template to a string.
@ -109,88 +29,52 @@ module AbstractController
# overridden in order to still return a string.
# :api: plugin
def render_to_string(*args, &block)
options = _normalize_render(*args, &block)
render_to_body(options)
end
# Raw rendering of a template.
# :api: plugin
def render_to_body(options = {})
_process_options(options)
_render_template(options)
end
# Find and renders a template based on the options given.
# :api: private
def _render_template(options) #:nodoc:
lookup_context.rendered_format = nil if options[:formats]
view_renderer.render(view_context, options)
# Normalize arguments, options and then delegates render_to_body and
# sticks the result in self.response_body.
# :api: public
def render(*args, &block)
end
DEFAULT_PROTECTED_INSTANCE_VARIABLES = [
:@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config,
:@_view_context_class, :@_view_renderer, :@_lookup_context
]
# Return Content-Type of rendered content
# :api: public
def rendered_format
end
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
# :api: public
def view_assigns
hash = {}
variables = instance_variables
variables -= protected_instance_variables
variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES
variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) }
(instance_variables - self.class.default_protected_instance_vars).each do |name|
hash[name[1..-1]] = instance_variable_get(name)
end
hash
end
private
# Normalize args and options.
# :api: private
def _normalize_render(*args, &block)
options = _normalize_args(*args, &block)
_normalize_options(options)
options
end
# Normalize args by converting render "foo" to render :action => "foo" and
# render "foo/bar" to render :file => "foo/bar".
# :api: plugin
def _normalize_args(action=nil, options={})
case action
when NilClass
when Hash
options = action
when String, Symbol
action = action.to_s
key = action.include?(?/) ? :file : :action
options[key] = action
else
options[:partial] = action
end
options
end
# Normalize options.
# :api: plugin
def _normalize_options(options)
if options[:partial] == true
options[:partial] = action_name
end
if (options.keys & [:partial, :file, :template]).empty?
options[:prefixes] ||= _prefixes
end
options[:template] ||= (options[:action] || action_name).to_s
options
end
# Process extra options.
# :api: plugin
def _process_options(options)
options
end
end
end

View File

@ -13,6 +13,7 @@ module ActionController
autoload :Middleware
autoload_under "metal" do
autoload :BasicRendering, 'action_controller/metal/rendering'
autoload :Compatibility
autoload :ConditionalGet
autoload :Cookies
@ -46,18 +47,9 @@ module ActionController
def self.eager_load!
super
ActionController::Caching.eager_load!
HTML.eager_load!
end
end
# All of these simply register additional autoloads
require 'action_view'
require 'action_view/vendor/html-scanner'
ActiveSupport.on_load(:action_view) do
ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
end
# Common Active Support usage in Action Controller
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/load_error'

View File

@ -2,6 +2,21 @@ require "action_controller/log_subscriber"
require "action_controller/metal/params_wrapper"
module ActionController
# The <tt>metal</tt> anonymous class was introduced to solve issue with including modules in <tt>ActionController::Base</tt>.
# Modules needes to be included in particluar order. First wee need to have <tt>AbstractController::Rendering</tt> included,
# next we should include actuall implementation which would be for example <tt>ActionView::Rendering</tt> and after that
# <tt>ActionController::Rendering</tt>. This order must be preserved and as we want to have middle module included dynamicaly
# <tt>metal</tt> class was introduced. It has <tt>AbstractController::Rendering</tt> included and is parent class of
# <tt>ActionController::Base</tt> which includes <tt>ActionController::Rendering</tt>. If we include <tt>ActionView::Rendering</tt>
# beetween them to perserve the required order, we can simply do this by:
#
# ActionController::Base.superclass.send(:include, ActionView::Rendering)
#
metal = Class.new(Metal) do
include AbstractController::Rendering
include ActionController::BasicRendering
end
# Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed
# on request and then either it renders a template or redirects to another action. An action is defined as a public method
# on the controller, which will automatically be made accessible to the web-server through \Rails Routes.
@ -160,7 +175,7 @@ module ActionController
# render action: "overthere" # won't be called if monkeys is nil
# end
#
class Base < Metal
class Base < metal
abstract!
# We document the request and response methods here because albeit they are
@ -200,7 +215,6 @@ module ActionController
end
MODULES = [
AbstractController::Layouts,
AbstractController::Translation,
AbstractController::AssetPaths,
@ -247,11 +261,12 @@ module ActionController
include mod
end
# Define some internal variables that should not be propagated to the view.
self.protected_instance_variables = [
:@_status, :@_headers, :@_params, :@_env, :@_response, :@_request,
:@_view_runtime, :@_stream, :@_url_options, :@_action_has_layout
]
def self.default_protected_instance_vars
super.concat [
:@_status, :@_headers, :@_params, :@_env, :@_response, :@_request,
:@_view_runtime, :@_stream, :@_url_options, :@_action_has_layout
]
end
ActiveSupport.run_load_hooks(:action_controller, self)
end

View File

@ -1,5 +1,6 @@
require 'action_dispatch/http/response'
require 'delegate'
require 'active_support/json'
module ActionController
# Mix this module in to your controller, and all actions in that controller
@ -32,6 +33,79 @@ module ActionController
# the main thread. Make sure your actions are thread safe, and this shouldn't
# be a problem (don't share state across threads, etc).
module Live
# This class provides the ability to write an SSE (Server Sent Event)
# to an IO stream. The class is initialized with a stream and can be used
# to either write a JSON string or an object which can be converted to JSON.
#
# Writing an object will convert it into standard SSE format with whatever
# options you have configured. You may choose to set the following options:
#
# 1) Event. If specified, an event with this name will be dispatched on
# the browser.
# 2) Retry. The reconnection time in milliseconds used when attempting
# to send the event.
# 3) Id. If the connection dies while sending an SSE to the browser, then
# the server will receive a +Last-Event-ID+ header with value equal to +id+.
#
# After setting an option in the constructor of the SSE object, all future
# SSEs sent accross the stream will use those options unless overridden.
#
# Example Usage:
#
# class MyController < ActionController::Base
# include ActionController::Live
#
# def index
# response.headers['Content-Type'] = 'text/event-stream'
# sse = SSE.new(response.stream, retry: 300, event: "event-name")
# sse.write({ name: 'John'})
# sse.write({ name: 'John'}, id: 10)
# sse.write({ name: 'John'}, id: 10, event: "other-event")
# sse.write({ name: 'John'}, id: 10, event: "other-event", retry: 500)
# ensure
# sse.close
# end
# end
#
# Note: SSEs are not currently supported by IE. However, they are supported
# by Chrome, Firefox, Opera, and Safari.
class SSE
WHITELISTED_OPTIONS = %w( retry event id )
def initialize(stream, options = {})
@stream = stream
@options = options
end
def close
@stream.close
end
def write(object, options = {})
case object
when String
perform_write(object, options)
else
perform_write(ActiveSupport::JSON.encode(object), options)
end
end
private
def perform_write(json, options)
current_options = @options.merge(options).stringify_keys
WHITELISTED_OPTIONS.each do |option_name|
if (option_value = current_options[option_name])
@stream.write "#{option_name}: #{option_value}\n"
end
end
@stream.write "data: #{json}\n\n"
end
end
class Buffer < ActionDispatch::Response::Buffer #:nodoc:
def initialize(response)
@error_callback = nil

View File

@ -6,6 +6,13 @@ module ActionController
Renderers.add(key, &block)
end
class MissingRenderer < LoadError
def initialize(format)
@format = format
super("No renderer defined for format: #{@format}")
end
end
module Renderers
extend ActiveSupport::Concern

View File

@ -1,8 +1,38 @@
module ActionController
module Rendering
# Basic rendering implements the most minimal rendering layer.
# It only supports rendering :text and :nothing. Passing any other option will
# result in `UnsupportedOperationError` exception. For more functionality like
# different formats, layouts etc. you should use `ActionView` gem.
module BasicRendering
extend ActiveSupport::Concern
include AbstractController::Rendering
# Render text or nothing (empty string) to response_body
# :api: public
def render(*args, &block)
super(*args, &block)
opts = args.first
if opts.has_key?(:text) && opts[:text].present?
self.response_body = opts[:text]
elsif opts.has_key?(:nothing) && opts[:nothing]
self.response_body = " "
else
raise UnsupportedOperationError
end
end
def rendered_format
Mime::TEXT
end
class UnsupportedOperationError < StandardError
def initialize
super "Unsupported render operation. BasicRendering supports only :text and :nothing options. For more, you need to include ActionView."
end
end
end
module Rendering
extend ActiveSupport::Concern
# Before processing, set the request formats in current controller formats.
def process_action(*) #:nodoc:
@ -12,17 +42,17 @@ module ActionController
# Check for double render errors and set the content_type after rendering.
def render(*args) #:nodoc:
raise ::AbstractController::DoubleRenderError if response_body
raise ::AbstractController::DoubleRenderError if self.response_body
super
self.content_type ||= Mime[lookup_context.rendered_format].to_s
response_body
self.content_type ||= rendered_format.to_s
self.response_body
end
# Overwrite render_to_string because body can now be set to a rack body.
def render_to_string(*)
if self.response_body = super
string = ""
response_body.each { |r| string << r }
self.response_body.each { |r| string << r }
string
end
ensure

View File

@ -202,6 +202,7 @@ module ActionController #:nodoc:
# This is the common behavior for formats associated with APIs, such as :xml and :json.
def api_behavior(error)
raise error unless resourceful?
raise MissingRenderer.new(format) unless has_renderer?
if get?
display resource
@ -269,6 +270,11 @@ module ActionController #:nodoc:
resource.respond_to?(:errors) && !resource.errors.empty?
end
# Check whether the neceessary Renderer is available
def has_renderer?
Renderers::RENDERERS.include?(format)
end
# By default, render the <code>:edit</code> action for HTML requests with errors, unless
# the verb was POST.
#

View File

@ -193,31 +193,29 @@ module ActionController #:nodoc:
module Streaming
extend ActiveSupport::Concern
include AbstractController::Rendering
protected
# Set proper cache control and transfer encoding when streaming
def _process_options(options) #:nodoc:
super
if options[:stream]
if env["HTTP_VERSION"] == "HTTP/1.0"
options.delete(:stream)
else
headers["Cache-Control"] ||= "no-cache"
headers["Transfer-Encoding"] = "chunked"
headers.delete("Content-Length")
# Set proper cache control and transfer encoding when streaming
def _process_options(options) #:nodoc:
super
if options[:stream]
if env["HTTP_VERSION"] == "HTTP/1.0"
options.delete(:stream)
else
headers["Cache-Control"] ||= "no-cache"
headers["Transfer-Encoding"] = "chunked"
headers.delete("Content-Length")
end
end
end
end
# Call render_body if we are streaming instead of usual +render+.
def _render_template(options) #:nodoc:
if options.delete(:stream)
Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
else
super
# Call render_body if we are streaming instead of usual +render+.
def _render_template(options) #:nodoc:
if options.delete(:stream)
Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
else
super
end
end
end
end
end

View File

@ -298,7 +298,7 @@ module ActionController
# params.slice(:d) # => {}
def slice(*keys)
self.class.new(super).tap do |new_instance|
new_instance.instance_variable_set :@permitted, @permitted
new_instance.permitted = @permitted
end
end
@ -312,10 +312,15 @@ module ActionController
# copy_params.permitted? # => true
def dup
super.tap do |duplicate|
duplicate.instance_variable_set :@permitted, @permitted
duplicate.permitted = @permitted
end
end
protected
def permitted=(new_permitted)
@permitted = new_permitted
end
private
def convert_hashes_to_parameters(key, value)
if value.is_a?(Parameters) || !value.is_a?(Hash)

View File

@ -1,7 +1,6 @@
require "rails"
require "action_controller"
require "action_dispatch/railtie"
require "action_view/railtie"
require "abstract_controller/railties/routes_helpers"
require "action_controller/railties/helpers"

View File

@ -57,22 +57,25 @@ module ActionDispatch
# you'll get a weird error down the road, but our form handling
# should really prevent that from happening
def normalize_encode_params(params)
if params.is_a?(String)
return params.force_encoding(Encoding::UTF_8).encode!
elsif !params.is_a?(Hash)
return params
end
new_hash = {}
params.each do |key, val|
new_key = key.is_a?(String) ? key.dup.force_encoding(Encoding::UTF_8).encode! : key
new_hash[new_key] = if val.is_a?(Array)
val.map! { |el| normalize_encode_params(el) }
case params
when String
params.force_encoding(Encoding::UTF_8).encode!
when Hash
if params.has_key?(:tempfile)
UploadedFile.new(params)
else
normalize_encode_params(val)
params.each_with_object({}) do |(key, val), new_hash|
new_key = key.is_a?(String) ? key.dup.force_encoding(Encoding::UTF_8).encode! : key
new_hash[new_key] = if val.is_a?(Array)
val.map! { |el| normalize_encode_params(el) }
else
normalize_encode_params(val)
end
end.with_indifferent_access
end
else
params
end
new_hash.with_indifferent_access
end
end
end

View File

@ -18,7 +18,6 @@ module ActionDispatch
include ActionDispatch::Http::MimeNegotiation
include ActionDispatch::Http::Parameters
include ActionDispatch::Http::FilterParameters
include ActionDispatch::Http::Upload
include ActionDispatch::Http::URL
autoload :Session, 'action_dispatch/request/session'

View File

@ -73,18 +73,5 @@ module ActionDispatch
filename.force_encoding(Encoding::UTF_8).encode! if filename
end
end
module Upload # :nodoc:
# Replace file upload hash with UploadedFile objects
# when normalize and encode parameters.
def normalize_encode_params(value)
if Hash === value && value.has_key?(:tempfile)
UploadedFile.new(value)
else
super
end
end
private :normalize_encode_params
end
end
end

View File

@ -34,27 +34,35 @@ module ActionDispatch
log_error(env, wrapper)
if env['action_dispatch.show_detailed_exceptions']
request = Request.new(env)
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
:request => Request.new(env),
:exception => wrapper.exception,
:application_trace => wrapper.application_trace,
:framework_trace => wrapper.framework_trace,
:full_trace => wrapper.full_trace,
:routes_inspector => routes_inspector(exception),
:source_extract => wrapper.source_extract,
:line_number => wrapper.line_number,
:file => wrapper.file
request: request,
exception: wrapper.exception,
application_trace: wrapper.application_trace,
framework_trace: wrapper.framework_trace,
full_trace: wrapper.full_trace,
routes_inspector: routes_inspector(exception),
source_extract: wrapper.source_extract,
line_number: wrapper.line_number,
file: wrapper.file
)
file = "rescues/#{wrapper.rescue_template}"
body = template.render(:template => file, :layout => 'rescues/layout')
render(wrapper.status_code, body)
if request.xhr?
body = template.render(template: file, layout: false, formats: [:text])
format = "text/plain"
else
body = template.render(template: file, layout: 'rescues/layout')
format = "text/html"
end
render(wrapper.status_code, body, format)
else
raise exception
end
end
def render(status, body)
[status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
def render(status, body, format)
[status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
end
def log_error(env, wrapper)

View File

@ -0,0 +1,23 @@
<%
clean_params = @request.filtered_parameters.clone
clean_params.delete("action")
clean_params.delete("controller")
request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
def debug_hash(object)
object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
end unless self.class.method_defined?(:debug_hash)
%>
Request parameters
<%= request_dump %>
Session dump
<%= debug_hash @request.session %>
Env dump
<%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %>
Response headers
<%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %>

View File

@ -0,0 +1,15 @@
<%
traces = { "Application Trace" => @application_trace,
"Framework Trace" => @framework_trace,
"Full Trace" => @full_trace }
%>
Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %>
<% traces.each do |name, trace| %>
<% if trace.any? %>
<%= name %>
<%= trace.join("\n") %>
<% end %>
<% end %>

View File

@ -8,7 +8,7 @@
</header>
<div id="container">
<h2><%= @exception.message %></h2>
<h2><%= h @exception.message %></h2>
<%= render template: "rescues/_source" %>
<%= render template: "rescues/_trace" %>

View File

@ -3,5 +3,5 @@
</header>
<div id="container">
<h2><%= @exception.message %></h2>
<h2><%= h @exception.message %></h2>
</div>

View File

@ -0,0 +1,3 @@
Template is missing
<%= @exception.message %>

View File

@ -2,7 +2,7 @@
<h1>Routing Error</h1>
</header>
<div id="container">
<h2><%= @exception.message %></h2>
<h2><%= h @exception.message %></h2>
<% unless @exception.failures.empty? %>
<p>
<h2>Failure reasons:</h2>

View File

@ -0,0 +1,11 @@
Routing Error
<%= @exception.message %>
<% unless @exception.failures.empty? %>
Failure reasons:
<% @exception.failures.each do |route, reason| %>
- <%= route.inspect.delete('\\') %></code> failed because <%= reason.downcase %>
<% end %>
<% end %>
<%= render template: "rescues/_trace", format: :text %>

View File

@ -10,7 +10,7 @@
<p>
Showing <i><%= @exception.file_name %></i> where line <b>#<%= @exception.line_number %></b> raised:
</p>
<pre><code><%= @exception.message %></code></pre>
<pre><code><%= h @exception.message %></code></pre>
<div class="source">
<div class="info">

View File

@ -0,0 +1,8 @@
<% @source_extract = @exception.source_extract(0, :html) %>
<%= @exception.original_exception.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised:
<%= @exception.message %>
<%= @exception.sub_template_message %>
<%= render template: "rescues/_trace", format: :text %>
<%= render template: "rescues/_request_and_response", format: :text %>

View File

@ -2,5 +2,5 @@
<h1>Unknown action</h1>
</header>
<div id="container">
<h2><%= @exception.message %></h2>
<h2><%= h @exception.message %></h2>
</div>

View File

@ -0,0 +1,3 @@
Unknown action
<%= @exception.message %>

View File

@ -64,28 +64,6 @@ module RackTestUtils
extend self
end
module RenderERBUtils
def view
@view ||= begin
path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
view_paths = ActionView::PathSet.new([path])
ActionView::Base.new(view_paths)
end
end
def render_erb(string)
@virtual_path = nil
template = ActionView::Template.new(
string.strip,
"test template",
ActionView::Template::Handlers::ERB,
{})
template.render(self, {}).strip
end
end
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
module ActionDispatch
@ -268,6 +246,8 @@ class Rack::TestCase < ActionDispatch::IntegrationTest
end
end
ActionController::Base.superclass.send(:include, ActionView::Layouts)
module ActionController
class Base
include ActionController::Testing
@ -290,15 +270,8 @@ module ActionController
end
end
class ::ApplicationController < ActionController::Base
end
module ActionView
class TestCase
# Must repeat the setup because AV::TestCase is a duplication
# of AC::TestCase
include ActionDispatch::SharedRoutes
end
class ::ApplicationController < ActionController::Base
end
class Workshop

View File

@ -8,6 +8,9 @@ require 'abstract_unit'
require 'controller/fake_controllers'
require 'action_mailer'
require 'action_view'
ActionMailer::Base.send(:include, ActionView::Layouts)
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
class AssertSelectTest < ActionController::TestCase

View File

@ -17,7 +17,7 @@ class ActionController::Base
def assigns(key = nil)
assigns = {}
instance_variables.each do |ivar|
next if ActionController::Base.protected_instance_variables.include?(ivar)
next if ActionController::Base.default_protected_instance_vars.include?(ivar)
assigns[ivar[1..-1]] = instance_variable_get(ivar)
end

View File

@ -2,6 +2,94 @@ require 'abstract_unit'
require 'active_support/concurrency/latch'
module ActionController
class SSETest < ActionController::TestCase
class SSETestController < ActionController::Base
include ActionController::Live
def basic_sse
response.headers['Content-Type'] = 'text/event-stream'
sse = SSE.new(response.stream)
sse.write("{\"name\":\"John\"}")
sse.write({ name: "Ryan" })
ensure
sse.close
end
def sse_with_event
sse = SSE.new(response.stream, event: "send-name")
sse.write("{\"name\":\"John\"}")
sse.write({ name: "Ryan" })
ensure
sse.close
end
def sse_with_retry
sse = SSE.new(response.stream, retry: 1000)
sse.write("{\"name\":\"John\"}")
sse.write({ name: "Ryan" }, retry: 1500)
ensure
sse.close
end
def sse_with_id
sse = SSE.new(response.stream)
sse.write("{\"name\":\"John\"}", id: 1)
sse.write({ name: "Ryan" }, id: 2)
ensure
sse.close
end
end
tests SSETestController
def wait_for_response_stream_close
while !response.stream.closed?
sleep 0.01
end
end
def test_basic_sse
get :basic_sse
wait_for_response_stream_close
assert_match(/data: {\"name\":\"John\"}/, response.body)
assert_match(/data: {\"name\":\"Ryan\"}/, response.body)
end
def test_sse_with_event_name
get :sse_with_event
wait_for_response_stream_close
assert_match(/data: {\"name\":\"John\"}/, response.body)
assert_match(/data: {\"name\":\"Ryan\"}/, response.body)
assert_match(/event: send-name/, response.body)
end
def test_sse_with_retry
get :sse_with_retry
wait_for_response_stream_close
first_response, second_response = response.body.split("\n\n")
assert_match(/data: {\"name\":\"John\"}/, first_response)
assert_match(/retry: 1000/, first_response)
assert_match(/data: {\"name\":\"Ryan\"}/, second_response)
assert_match(/retry: 1500/, second_response)
end
def test_sse_with_id
get :sse_with_id
wait_for_response_stream_close
first_response, second_response = response.body.split("\n\n")
assert_match(/data: {\"name\":\"John\"}/, first_response)
assert_match(/id: 1/, first_response)
assert_match(/data: {\"name\":\"Ryan\"}/, second_response)
assert_match(/id: 2/, second_response)
end
end
class LiveStreamTest < ActionController::TestCase
class TestController < ActionController::Base
include ActionController::Live

View File

@ -0,0 +1,94 @@
require 'abstract_unit'
class StarStarMimeController < ActionController::Base
layout nil
def index
render
end
end
class StarStarMimeControllerTest < ActionController::TestCase
tests StarStarMimeController
def test_javascript_with_format
@request.accept = "text/javascript"
get :index, :format => 'js'
assert_match "function addition(a,b){ return a+b; }", @response.body
end
def test_javascript_with_no_format
@request.accept = "text/javascript"
get :index
assert_match "function addition(a,b){ return a+b; }", @response.body
end
def test_javascript_with_no_format_only_star_star
@request.accept = "*/*"
get :index
assert_match "function addition(a,b){ return a+b; }", @response.body
end
end
class AbstractPostController < ActionController::Base
self.view_paths = File.dirname(__FILE__) + "/../../fixtures/post_test/"
end
# For testing layouts which are set automatically
class PostController < AbstractPostController
around_action :with_iphone
def index
respond_to(:html, :iphone, :js)
end
protected
def with_iphone
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
yield
end
end
class SuperPostController < PostController
end
class MimeControllerLayoutsTest < ActionController::TestCase
tests PostController
def setup
super
@request.host = "www.example.com"
Mime::Type.register_alias("text/html", :iphone)
end
def teardown
super
Mime::Type.unregister(:iphone)
end
def test_missing_layout_renders_properly
get :index
assert_equal '<html><div id="html">Hello Firefox</div></html>', @response.body
@request.accept = "text/iphone"
get :index
assert_equal 'Hello iPhone', @response.body
end
def test_format_with_inherited_layouts
@controller = SuperPostController.new
get :index
assert_equal '<html><div id="html">Super Firefox</div></html>', @response.body
@request.accept = "text/iphone"
get :index
assert_equal '<html><div id="super_iphone">Super iPhone</div></html>', @response.body
end
def test_non_navigational_format_with_no_template_fallbacks_to_html_template_with_no_layout
get :index, :format => :js
assert_equal "Hello Firefox", @response.body
end
end

View File

@ -0,0 +1,493 @@
require 'abstract_unit'
class RespondToController < ActionController::Base
layout :set_layout
def html_xml_or_rss
respond_to do |type|
type.html { render :text => "HTML" }
type.xml { render :text => "XML" }
type.rss { render :text => "RSS" }
type.all { render :text => "Nothing" }
end
end
def js_or_html
respond_to do |type|
type.html { render :text => "HTML" }
type.js { render :text => "JS" }
type.all { render :text => "Nothing" }
end
end
def json_or_yaml
respond_to do |type|
type.json { render :text => "JSON" }
type.yaml { render :text => "YAML" }
end
end
def html_or_xml
respond_to do |type|
type.html { render :text => "HTML" }
type.xml { render :text => "XML" }
type.all { render :text => "Nothing" }
end
end
def json_xml_or_html
respond_to do |type|
type.json { render :text => 'JSON' }
type.xml { render :xml => 'XML' }
type.html { render :text => 'HTML' }
end
end
def forced_xml
request.format = :xml
respond_to do |type|
type.html { render :text => "HTML" }
type.xml { render :text => "XML" }
end
end
def just_xml
respond_to do |type|
type.xml { render :text => "XML" }
end
end
def using_defaults
respond_to do |type|
type.html
type.xml
end
end
def using_defaults_with_type_list
respond_to(:html, :xml)
end
def using_defaults_with_all
respond_to do |type|
type.html
type.all{ render text: "ALL" }
end
end
def made_for_content_type
respond_to do |type|
type.rss { render :text => "RSS" }
type.atom { render :text => "ATOM" }
type.all { render :text => "Nothing" }
end
end
def custom_type_handling
respond_to do |type|
type.html { render :text => "HTML" }
type.custom("application/crazy-xml") { render :text => "Crazy XML" }
type.all { render :text => "Nothing" }
end
end
def custom_constant_handling
respond_to do |type|
type.html { render :text => "HTML" }
type.mobile { render :text => "Mobile" }
end
end
def custom_constant_handling_without_block
respond_to do |type|
type.html { render :text => "HTML" }
type.mobile
end
end
def handle_any
respond_to do |type|
type.html { render :text => "HTML" }
type.any(:js, :xml) { render :text => "Either JS or XML" }
end
end
def handle_any_any
respond_to do |type|
type.html { render :text => 'HTML' }
type.any { render :text => 'Whatever you ask for, I got it' }
end
end
def all_types_with_layout
respond_to do |type|
type.html
end
end
def iphone_with_html_response_type
request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox" }
type.iphone { @type = "iPhone" }
end
end
def iphone_with_html_response_type_without_layout
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" }
type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" }
end
end
protected
def set_layout
case action_name
when "all_types_with_layout", "iphone_with_html_response_type"
"respond_to/layouts/standard"
when "iphone_with_html_response_type_without_layout"
"respond_to/layouts/missing"
end
end
end
class RespondToControllerTest < ActionController::TestCase
tests RespondToController
def setup
super
@request.host = "www.example.com"
Mime::Type.register_alias("text/html", :iphone)
Mime::Type.register("text/x-mobile", :mobile)
end
def teardown
super
Mime::Type.unregister(:iphone)
Mime::Type.unregister(:mobile)
end
def test_html
@request.accept = "text/html"
get :js_or_html
assert_equal 'HTML', @response.body
get :html_or_xml
assert_equal 'HTML', @response.body
assert_raises(ActionController::UnknownFormat) do
get :just_xml
end
end
def test_all
@request.accept = "*/*"
get :js_or_html
assert_equal 'HTML', @response.body # js is not part of all
get :html_or_xml
assert_equal 'HTML', @response.body
get :just_xml
assert_equal 'XML', @response.body
end
def test_xml
@request.accept = "application/xml"
get :html_xml_or_rss
assert_equal 'XML', @response.body
end
def test_js_or_html
@request.accept = "text/javascript, text/html"
xhr :get, :js_or_html
assert_equal 'JS', @response.body
@request.accept = "text/javascript, text/html"
xhr :get, :html_or_xml
assert_equal 'HTML', @response.body
@request.accept = "text/javascript, text/html"
assert_raises(ActionController::UnknownFormat) do
xhr :get, :just_xml
end
end
def test_json_or_yaml_with_leading_star_star
@request.accept = "*/*, application/json"
get :json_xml_or_html
assert_equal 'HTML', @response.body
@request.accept = "*/* , application/json"
get :json_xml_or_html
assert_equal 'HTML', @response.body
end
def test_json_or_yaml
xhr :get, :json_or_yaml
assert_equal 'JSON', @response.body
get :json_or_yaml, :format => 'json'
assert_equal 'JSON', @response.body
get :json_or_yaml, :format => 'yaml'
assert_equal 'YAML', @response.body
{ 'YAML' => %w(text/yaml),
'JSON' => %w(application/json text/x-json)
}.each do |body, content_types|
content_types.each do |content_type|
@request.accept = content_type
get :json_or_yaml
assert_equal body, @response.body
end
end
end
def test_js_or_anything
@request.accept = "text/javascript, */*"
xhr :get, :js_or_html
assert_equal 'JS', @response.body
xhr :get, :html_or_xml
assert_equal 'HTML', @response.body
xhr :get, :just_xml
assert_equal 'XML', @response.body
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 = "application/xml"
get :using_defaults
assert_equal "application/xml", @response.content_type
assert_equal "<p>Hello world!</p>\n", @response.body
end
def test_using_defaults_with_all
@request.accept = "*/*"
get :using_defaults_with_all
assert_equal "HTML!", @response.body.strip
@request.accept = "text/html"
get :using_defaults_with_all
assert_equal "HTML!", @response.body.strip
@request.accept = "application/json"
get :using_defaults_with_all
assert_equal "ALL", @response.body
end
def test_using_defaults_with_type_list
@request.accept = "*/*"
get :using_defaults_with_type_list
assert_equal "text/html", @response.content_type
assert_equal 'Hello world!', @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_with_atom_content_type
@request.accept = ""
@request.env["CONTENT_TYPE"] = "application/atom+xml"
xhr :get, :made_for_content_type
assert_equal "ATOM", @response.body
end
def test_with_rss_content_type
@request.accept = ""
@request.env["CONTENT_TYPE"] = "application/rss+xml"
xhr :get, :made_for_content_type
assert_equal "RSS", @response.body
end
def test_synonyms
@request.accept = "application/javascript"
get :js_or_html
assert_equal 'JS', @response.body
@request.accept = "application/x-xml"
get :html_xml_or_rss
assert_equal "XML", @response.body
end
def test_custom_types
@request.accept = "application/crazy-xml"
get :custom_type_handling
assert_equal "application/crazy-xml", @response.content_type
assert_equal 'Crazy XML', @response.body
@request.accept = "text/html"
get :custom_type_handling
assert_equal "text/html", @response.content_type
assert_equal 'HTML', @response.body
end
def test_xhtml_alias
@request.accept = "application/xhtml+xml,application/xml"
get :html_or_xml
assert_equal 'HTML', @response.body
end
def test_firefox_simulation
@request.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
get :html_or_xml
assert_equal 'HTML', @response.body
end
def test_handle_any
@request.accept = "*/*"
get :handle_any
assert_equal 'HTML', @response.body
@request.accept = "text/javascript"
get :handle_any
assert_equal 'Either JS or XML', @response.body
@request.accept = "text/xml"
get :handle_any
assert_equal 'Either JS or XML', @response.body
end
def test_handle_any_any
@request.accept = "*/*"
get :handle_any_any
assert_equal 'HTML', @response.body
end
def test_handle_any_any_parameter_format
get :handle_any_any, {:format=>'html'}
assert_equal 'HTML', @response.body
end
def test_handle_any_any_explicit_html
@request.accept = "text/html"
get :handle_any_any
assert_equal 'HTML', @response.body
end
def test_handle_any_any_javascript
@request.accept = "text/javascript"
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
def test_handle_any_any_xml
@request.accept = "text/xml"
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
def test_browser_check_with_any_any
@request.accept = "application/json, application/xml"
get :json_xml_or_html
assert_equal 'JSON', @response.body
@request.accept = "application/json, application/xml, */*"
get :json_xml_or_html
assert_equal 'HTML', @response.body
end
def test_html_type_with_layout
@request.accept = "text/html"
get :all_types_with_layout
assert_equal '<html><div id="html">HTML for all_types_with_layout</div></html>', @response.body
end
def test_xhr
xhr :get, :js_or_html
assert_equal 'JS', @response.body
end
def test_custom_constant
get :custom_constant_handling, :format => "mobile"
assert_equal "text/x-mobile", @response.content_type
assert_equal "Mobile", @response.body
end
def test_custom_constant_handling_without_block
get :custom_constant_handling_without_block, :format => "mobile"
assert_equal "text/x-mobile", @response.content_type
assert_equal "Mobile", @response.body
end
def test_forced_format
get :html_xml_or_rss
assert_equal "HTML", @response.body
get :html_xml_or_rss, :format => "html"
assert_equal "HTML", @response.body
get :html_xml_or_rss, :format => "xml"
assert_equal "XML", @response.body
get :html_xml_or_rss, :format => "rss"
assert_equal "RSS", @response.body
end
def test_internally_forced_format
get :forced_xml
assert_equal "XML", @response.body
get :forced_xml, :format => "html"
assert_equal "XML", @response.body
end
def test_extension_synonyms
get :html_xml_or_rss, :format => "xhtml"
assert_equal "HTML", @response.body
end
def test_render_action_for_html
@controller.instance_eval do
def render(*args)
@action = args.first[:action] unless args.empty?
@action ||= action_name
response.body = "#{@action} - #{formats}"
end
end
get :using_defaults
assert_equal "using_defaults - #{[:html].to_s}", @response.body
get :using_defaults, :format => "xml"
assert_equal "using_defaults - #{[:xml].to_s}", @response.body
end
def test_format_with_custom_response_type
get :iphone_with_html_response_type
assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body
get :iphone_with_html_response_type, :format => "iphone"
assert_equal "text/html", @response.content_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
end
def test_format_with_custom_response_type_and_request_headers
@request.accept = "text/iphone"
get :iphone_with_html_response_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
assert_equal "text/html", @response.content_type
end
def test_invalid_format
assert_raises(ActionController::UnknownFormat) do
get :using_defaults, :format => "invalidformat"
end
end
end

View File

@ -1,529 +1,5 @@
require 'abstract_unit'
require 'controller/fake_models'
require 'active_support/core_ext/hash/conversions'
class StarStarMimeController < ActionController::Base
layout nil
def index
render
end
end
class RespondToController < ActionController::Base
layout :set_layout
def html_xml_or_rss
respond_to do |type|
type.html { render :text => "HTML" }
type.xml { render :text => "XML" }
type.rss { render :text => "RSS" }
type.all { render :text => "Nothing" }
end
end
def js_or_html
respond_to do |type|
type.html { render :text => "HTML" }
type.js { render :text => "JS" }
type.all { render :text => "Nothing" }
end
end
def json_or_yaml
respond_to do |type|
type.json { render :text => "JSON" }
type.yaml { render :text => "YAML" }
end
end
def html_or_xml
respond_to do |type|
type.html { render :text => "HTML" }
type.xml { render :text => "XML" }
type.all { render :text => "Nothing" }
end
end
def json_xml_or_html
respond_to do |type|
type.json { render :text => 'JSON' }
type.xml { render :xml => 'XML' }
type.html { render :text => 'HTML' }
end
end
def forced_xml
request.format = :xml
respond_to do |type|
type.html { render :text => "HTML" }
type.xml { render :text => "XML" }
end
end
def just_xml
respond_to do |type|
type.xml { render :text => "XML" }
end
end
def using_defaults
respond_to do |type|
type.html
type.xml
end
end
def using_defaults_with_type_list
respond_to(:html, :xml)
end
def using_defaults_with_all
respond_to do |type|
type.html
type.all{ render text: "ALL" }
end
end
def made_for_content_type
respond_to do |type|
type.rss { render :text => "RSS" }
type.atom { render :text => "ATOM" }
type.all { render :text => "Nothing" }
end
end
def custom_type_handling
respond_to do |type|
type.html { render :text => "HTML" }
type.custom("application/crazy-xml") { render :text => "Crazy XML" }
type.all { render :text => "Nothing" }
end
end
def custom_constant_handling
respond_to do |type|
type.html { render :text => "HTML" }
type.mobile { render :text => "Mobile" }
end
end
def custom_constant_handling_without_block
respond_to do |type|
type.html { render :text => "HTML" }
type.mobile
end
end
def handle_any
respond_to do |type|
type.html { render :text => "HTML" }
type.any(:js, :xml) { render :text => "Either JS or XML" }
end
end
def handle_any_any
respond_to do |type|
type.html { render :text => 'HTML' }
type.any { render :text => 'Whatever you ask for, I got it' }
end
end
def all_types_with_layout
respond_to do |type|
type.html
end
end
def iphone_with_html_response_type
request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox" }
type.iphone { @type = "iPhone" }
end
end
def iphone_with_html_response_type_without_layout
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
respond_to do |type|
type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" }
type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" }
end
end
protected
def set_layout
case action_name
when "all_types_with_layout", "iphone_with_html_response_type"
"respond_to/layouts/standard"
when "iphone_with_html_response_type_without_layout"
"respond_to/layouts/missing"
end
end
end
class StarStarMimeControllerTest < ActionController::TestCase
tests StarStarMimeController
def test_javascript_with_format
@request.accept = "text/javascript"
get :index, :format => 'js'
assert_match "function addition(a,b){ return a+b; }", @response.body
end
def test_javascript_with_no_format
@request.accept = "text/javascript"
get :index
assert_match "function addition(a,b){ return a+b; }", @response.body
end
def test_javascript_with_no_format_only_star_star
@request.accept = "*/*"
get :index
assert_match "function addition(a,b){ return a+b; }", @response.body
end
end
class RespondToControllerTest < ActionController::TestCase
tests RespondToController
def setup
super
@request.host = "www.example.com"
Mime::Type.register_alias("text/html", :iphone)
Mime::Type.register("text/x-mobile", :mobile)
end
def teardown
super
Mime::Type.unregister(:iphone)
Mime::Type.unregister(:mobile)
end
def test_html
@request.accept = "text/html"
get :js_or_html
assert_equal 'HTML', @response.body
get :html_or_xml
assert_equal 'HTML', @response.body
assert_raises(ActionController::UnknownFormat) do
get :just_xml
end
end
def test_all
@request.accept = "*/*"
get :js_or_html
assert_equal 'HTML', @response.body # js is not part of all
get :html_or_xml
assert_equal 'HTML', @response.body
get :just_xml
assert_equal 'XML', @response.body
end
def test_xml
@request.accept = "application/xml"
get :html_xml_or_rss
assert_equal 'XML', @response.body
end
def test_js_or_html
@request.accept = "text/javascript, text/html"
xhr :get, :js_or_html
assert_equal 'JS', @response.body
@request.accept = "text/javascript, text/html"
xhr :get, :html_or_xml
assert_equal 'HTML', @response.body
@request.accept = "text/javascript, text/html"
assert_raises(ActionController::UnknownFormat) do
xhr :get, :just_xml
end
end
def test_json_or_yaml_with_leading_star_star
@request.accept = "*/*, application/json"
get :json_xml_or_html
assert_equal 'HTML', @response.body
@request.accept = "*/* , application/json"
get :json_xml_or_html
assert_equal 'HTML', @response.body
end
def test_json_or_yaml
xhr :get, :json_or_yaml
assert_equal 'JSON', @response.body
get :json_or_yaml, :format => 'json'
assert_equal 'JSON', @response.body
get :json_or_yaml, :format => 'yaml'
assert_equal 'YAML', @response.body
{ 'YAML' => %w(text/yaml),
'JSON' => %w(application/json text/x-json)
}.each do |body, content_types|
content_types.each do |content_type|
@request.accept = content_type
get :json_or_yaml
assert_equal body, @response.body
end
end
end
def test_js_or_anything
@request.accept = "text/javascript, */*"
xhr :get, :js_or_html
assert_equal 'JS', @response.body
xhr :get, :html_or_xml
assert_equal 'HTML', @response.body
xhr :get, :just_xml
assert_equal 'XML', @response.body
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 = "application/xml"
get :using_defaults
assert_equal "application/xml", @response.content_type
assert_equal "<p>Hello world!</p>\n", @response.body
end
def test_using_defaults_with_all
@request.accept = "*/*"
get :using_defaults_with_all
assert_equal "HTML!", @response.body.strip
@request.accept = "text/html"
get :using_defaults_with_all
assert_equal "HTML!", @response.body.strip
@request.accept = "application/json"
get :using_defaults_with_all
assert_equal "ALL", @response.body
end
def test_using_defaults_with_type_list
@request.accept = "*/*"
get :using_defaults_with_type_list
assert_equal "text/html", @response.content_type
assert_equal 'Hello world!', @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_with_atom_content_type
@request.accept = ""
@request.env["CONTENT_TYPE"] = "application/atom+xml"
xhr :get, :made_for_content_type
assert_equal "ATOM", @response.body
end
def test_with_rss_content_type
@request.accept = ""
@request.env["CONTENT_TYPE"] = "application/rss+xml"
xhr :get, :made_for_content_type
assert_equal "RSS", @response.body
end
def test_synonyms
@request.accept = "application/javascript"
get :js_or_html
assert_equal 'JS', @response.body
@request.accept = "application/x-xml"
get :html_xml_or_rss
assert_equal "XML", @response.body
end
def test_custom_types
@request.accept = "application/crazy-xml"
get :custom_type_handling
assert_equal "application/crazy-xml", @response.content_type
assert_equal 'Crazy XML', @response.body
@request.accept = "text/html"
get :custom_type_handling
assert_equal "text/html", @response.content_type
assert_equal 'HTML', @response.body
end
def test_xhtml_alias
@request.accept = "application/xhtml+xml,application/xml"
get :html_or_xml
assert_equal 'HTML', @response.body
end
def test_firefox_simulation
@request.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
get :html_or_xml
assert_equal 'HTML', @response.body
end
def test_handle_any
@request.accept = "*/*"
get :handle_any
assert_equal 'HTML', @response.body
@request.accept = "text/javascript"
get :handle_any
assert_equal 'Either JS or XML', @response.body
@request.accept = "text/xml"
get :handle_any
assert_equal 'Either JS or XML', @response.body
end
def test_handle_any_any
@request.accept = "*/*"
get :handle_any_any
assert_equal 'HTML', @response.body
end
def test_handle_any_any_parameter_format
get :handle_any_any, {:format=>'html'}
assert_equal 'HTML', @response.body
end
def test_handle_any_any_explicit_html
@request.accept = "text/html"
get :handle_any_any
assert_equal 'HTML', @response.body
end
def test_handle_any_any_javascript
@request.accept = "text/javascript"
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
def test_handle_any_any_xml
@request.accept = "text/xml"
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
def test_browser_check_with_any_any
@request.accept = "application/json, application/xml"
get :json_xml_or_html
assert_equal 'JSON', @response.body
@request.accept = "application/json, application/xml, */*"
get :json_xml_or_html
assert_equal 'HTML', @response.body
end
def test_html_type_with_layout
@request.accept = "text/html"
get :all_types_with_layout
assert_equal '<html><div id="html">HTML for all_types_with_layout</div></html>', @response.body
end
def test_xhr
xhr :get, :js_or_html
assert_equal 'JS', @response.body
end
def test_custom_constant
get :custom_constant_handling, :format => "mobile"
assert_equal "text/x-mobile", @response.content_type
assert_equal "Mobile", @response.body
end
def test_custom_constant_handling_without_block
get :custom_constant_handling_without_block, :format => "mobile"
assert_equal "text/x-mobile", @response.content_type
assert_equal "Mobile", @response.body
end
def test_forced_format
get :html_xml_or_rss
assert_equal "HTML", @response.body
get :html_xml_or_rss, :format => "html"
assert_equal "HTML", @response.body
get :html_xml_or_rss, :format => "xml"
assert_equal "XML", @response.body
get :html_xml_or_rss, :format => "rss"
assert_equal "RSS", @response.body
end
def test_internally_forced_format
get :forced_xml
assert_equal "XML", @response.body
get :forced_xml, :format => "html"
assert_equal "XML", @response.body
end
def test_extension_synonyms
get :html_xml_or_rss, :format => "xhtml"
assert_equal "HTML", @response.body
end
def test_render_action_for_html
@controller.instance_eval do
def render(*args)
@action = args.first[:action] unless args.empty?
@action ||= action_name
response.body = "#{@action} - #{formats}"
end
end
get :using_defaults
assert_equal "using_defaults - #{[:html].to_s}", @response.body
get :using_defaults, :format => "xml"
assert_equal "using_defaults - #{[:xml].to_s}", @response.body
end
def test_format_with_custom_response_type
get :iphone_with_html_response_type
assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body
get :iphone_with_html_response_type, :format => "iphone"
assert_equal "text/html", @response.content_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
end
def test_format_with_custom_response_type_and_request_headers
@request.accept = "text/iphone"
get :iphone_with_html_response_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
assert_equal "text/html", @response.content_type
end
def test_invalid_format
assert_raises(ActionController::UnknownFormat) do
get :using_defaults, :format => "invalidformat"
end
end
end
class RespondWithController < ActionController::Base
respond_to :html, :json, :touch
@ -631,6 +107,20 @@ class RenderJsonRespondWithController < RespondWithController
end
end
class CsvRespondWithController < ActionController::Base
respond_to :csv
class RespondWithCsv
def to_csv
"c,s,v"
end
end
def index
respond_with(RespondWithCsv.new)
end
end
class EmptyRespondWithController < ActionController::Base
def index
respond_with(Customer.new("david", 13))
@ -847,6 +337,7 @@ class RespondWithControllerTest < ActionController::TestCase
errors = { :name => :invalid }
Customer.any_instance.stubs(:errors).returns(errors)
put :using_resource
assert_equal "text/html", @response.content_type
assert_equal 200, @response.status
assert_equal "Edit world!\n", @response.body
@ -1131,6 +622,23 @@ class RespondWithControllerTest < ActionController::TestCase
RespondWithController.responder = ActionController::Responder
end
def test_uses_renderer_if_an_api_behavior
ActionController::Renderers.add :csv do |obj, options|
send_data obj.to_csv, type: Mime::CSV
end
@controller = CsvRespondWithController.new
get :index, format: 'csv'
assert_equal Mime::CSV, @response.content_type
assert_equal "c,s,v", @response.body
end
def test_raises_missing_renderer_if_an_api_behavior_with_no_renderer
@controller = CsvRespondWithController.new
assert_raise ActionController::MissingRenderer do
get :index, format: 'csv'
end
end
def test_error_is_raised_if_no_respond_to_is_declared_and_respond_with_is_called
@controller = EmptyRespondWithController.new
@request.accept = "*/*"
@ -1154,69 +662,6 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
class AbstractPostController < ActionController::Base
self.view_paths = File.dirname(__FILE__) + "/../fixtures/post_test/"
end
# For testing layouts which are set automatically
class PostController < AbstractPostController
around_action :with_iphone
def index
respond_to(:html, :iphone, :js)
end
protected
def with_iphone
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
yield
end
end
class SuperPostController < PostController
end
class MimeControllerLayoutsTest < ActionController::TestCase
tests PostController
def setup
super
@request.host = "www.example.com"
Mime::Type.register_alias("text/html", :iphone)
end
def teardown
super
Mime::Type.unregister(:iphone)
end
def test_missing_layout_renders_properly
get :index
assert_equal '<html><div id="html">Hello Firefox</div></html>', @response.body
@request.accept = "text/iphone"
get :index
assert_equal 'Hello iPhone', @response.body
end
def test_format_with_inherited_layouts
@controller = SuperPostController.new
get :index
assert_equal '<html><div id="html">Super Firefox</div></html>', @response.body
@request.accept = "text/iphone"
get :index
assert_equal '<html><div id="super_iphone">Super iPhone</div></html>', @response.body
end
def test_non_navigational_format_with_no_template_fallbacks_to_html_template_with_no_layout
get :index, :format => :js
assert_equal "Hello Firefox", @response.body
end
end
class FlashResponder < ActionController::Responder
def initialize(controller, resources, options={})
super

File diff suppressed because it is too large Load Diff

View File

@ -128,6 +128,47 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_match(/ActionController::ParameterMissing/, body)
end
test "rescue with text error for xhr request" do
@app = DevelopmentApp
xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'}
get "/", {}, xhr_request_env
assert_response 500
assert_no_match(/<body>/, body)
assert_equal response.content_type, "text/plain"
assert_match(/puke/, body)
get "/not_found", {}, xhr_request_env
assert_response 404
assert_no_match(/<body>/, body)
assert_equal response.content_type, "text/plain"
assert_match(/#{AbstractController::ActionNotFound.name}/, body)
get "/method_not_allowed", {}, xhr_request_env
assert_response 405
assert_no_match(/<body>/, body)
assert_equal response.content_type, "text/plain"
assert_match(/ActionController::MethodNotAllowed/, body)
get "/unknown_http_method", {}, xhr_request_env
assert_response 405
assert_no_match(/<body>/, body)
assert_equal response.content_type, "text/plain"
assert_match(/ActionController::UnknownHttpMethod/, body)
get "/bad_request", {}, xhr_request_env
assert_response 400
assert_no_match(/<body>/, body)
assert_equal response.content_type, "text/plain"
assert_match(/ActionController::BadRequest/, body)
get "/parameter_missing", {}, xhr_request_env
assert_response 400
assert_no_match(/<body>/, body)
assert_equal response.content_type, "text/plain"
assert_match(/ActionController::ParameterMissing/, body)
end
test "does not show filtered parameters" do
@app = DevelopmentApp

View File

@ -1 +0,0 @@
../../symlink_parent

View File

@ -28,12 +28,6 @@ class Customer < Struct.new(:name, :id)
end
end
class BadCustomer < Customer
end
class GoodCustomer < Customer
end
class ValidatedCustomer < Customer
def errors
if name =~ /Sikachu/i

View File

@ -1,3 +1,7 @@
* Only cache template digests if `config.cache_template_loading` id true.
*Josh Lauer*, *Justin Ridgewell*
* Added an `extname` hash option for `javascript_include_tag` method.
Before:

View File

@ -7,14 +7,7 @@ task :default => :test
# Run the unit tests
desc "Run all unit tests"
task :test => [:test_action_view, :test_active_record_integration]
Rake::TestTask.new(:test_action_view) do |t|
t.libs << 'test'
t.test_files = Dir.glob('test/template/**/*_test.rb').sort
t.warning = true
t.verbose = true
end
task :test => ["test:template", "test:integration:action_pack", "test:integration:active_record"]
namespace :test do
task :isolated do
@ -25,16 +18,28 @@ namespace :test do
Rake::TestTask.new(:template) do |t|
t.libs << 'test'
t.pattern = 'test/template/**/*.rb'
t.test_files = Dir.glob('test/template/**/*_test.rb').sort
t.warning = true
t.verbose = true
end
end
desc 'ActiveRecord Integration Tests'
Rake::TestTask.new(:test_active_record_integration) do |t|
t.libs << 'test'
t.test_files = Dir.glob("test/activerecord/*_test.rb")
t.warning = true
t.verbose = true
namespace :integration do
desc 'ActiveRecord Integration Tests'
Rake::TestTask.new(:active_record) do |t|
t.libs << 'test'
t.test_files = Dir.glob("test/activerecord/*_test.rb")
t.warning = true
t.verbose = true
end
desc 'ActionPack Integration Tests'
Rake::TestTask.new(:action_pack) do |t|
t.libs << 'test'
t.test_files = Dir.glob("test/actionpack/**/*_test.rb")
t.warning = true
t.verbose = true
end
end
end
spec = eval(File.read('actionview.gemspec'))

View File

@ -34,10 +34,13 @@ module ActionView
autoload :Digestor
autoload :Helpers
autoload :LookupContext
autoload :Layouts
autoload :PathSet
autoload :RecordIdentifier
autoload :Rendering
autoload :RoutingUrlFor
autoload :Template
autoload :ViewPaths
autoload_under "renderer" do
autoload :Renderer
@ -82,6 +85,7 @@ module ActionView
def self.eager_load!
super
ActionView::Template.eager_load!
HTML.eager_load!
end
end

View File

@ -2,6 +2,10 @@ require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/ordered_options'
require 'action_view/log_subscriber'
require 'action_view/helpers'
require 'action_view/context'
require 'action_view/template'
require 'action_view/lookup_context'
module ActionView #:nodoc:
# = Action View Base

View File

@ -32,9 +32,13 @@ module ActionView
Digestor
end
@@cache[cache_key] = digest = klass.new(name, format, finder, options).digest # Store the actual digest
ensure
@@cache.delete_pair(cache_key, false) if pre_stored && !digest # something went wrong, make sure not to corrupt the @@cache
# Store the actual digest if config.cache_template_loading is true
klass.new(name, format, finder, options).digest.tap do |digest|
@@cache[cache_key] = digest if ActionView::Resolver.caching?
end
rescue Exception
@@cache.delete_pair(cache_key, false) if pre_stored # something went wrong, make sure not to corrupt the @@cache
raise
end
end

View File

@ -1,3 +1,5 @@
require 'action_view/record_identifier'
module ActionView
# = Action View Record Tag Helpers
module Helpers

View File

@ -1,6 +1,7 @@
require "action_view/rendering"
require "active_support/core_ext/module/remove_method"
module AbstractController
module ActionView
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
# repeated setups. The inclusion pattern has pages that look like this:
#
@ -200,7 +201,7 @@ module AbstractController
module Layouts
extend ActiveSupport::Concern
include Rendering
include ActionView::Rendering
included do
class_attribute :_layout, :_layout_conditions, :instance_accessor => false

View File

@ -1,3 +1,5 @@
require 'active_support/log_subscriber'
module ActionView
# = Action View Log Subscriber
#

View File

@ -35,5 +35,18 @@ module ActionView
end
end
end
initializer "action_view.setup_action_pack", before: :add_view_paths do |app|
ActiveSupport.on_load(:action_controller) do
ActionController::Base.superclass.send(:include, ActionView::Layouts)
ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
end
end
initializer "action_view.setup_action_mailer", before: :add_view_paths do |app|
ActiveSupport.on_load(:action_mailer) do
ActionMailer::Base.send(:include, ActionView::Layouts)
end
end
end
end

View File

@ -0,0 +1,162 @@
require "action_view/view_paths"
module ActionView
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
# it will trigger the lookup_context and consequently expire the cache.
class I18nProxy < ::I18n::Config #:nodoc:
attr_reader :original_config, :lookup_context
def initialize(original_config, lookup_context)
original_config = original_config.original_config if original_config.respond_to?(:original_config)
@original_config, @lookup_context = original_config, lookup_context
end
def locale
@original_config.locale
end
def locale=(value)
@lookup_context.locale = value
end
end
module Rendering
extend ActiveSupport::Concern
include ActionView::ViewPaths
# Overwrite process to setup I18n proxy.
def process(*) #:nodoc:
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
super
ensure
I18n.config = old_config
end
module ClassMethods
def view_context_class
@view_context_class ||= begin
routes = respond_to?(:_routes) && _routes
helpers = respond_to?(:_helpers) && _helpers
Class.new(ActionView::Base) do
if routes
include routes.url_helpers
include routes.mounted_helpers
end
if helpers
include helpers
end
end
end
end
end
attr_internal_writer :view_context_class
def view_context_class
@_view_context_class ||= self.class.view_context_class
end
# An instance of a view class. The default view class is ActionView::Base
#
# The view class must have the following methods:
# View.new[lookup_context, assigns, controller]
# Create a new ActionView instance for a controller
# View#render[options]
# Returns String with the rendered template
#
# Override this method in a module to change the default behavior.
def view_context
view_context_class.new(view_renderer, view_assigns, self)
end
# Returns an object that is able to render templates.
# :api: private
def view_renderer
@_view_renderer ||= ActionView::Renderer.new(lookup_context)
end
# Render template to response_body
# :api: public
def render(*args, &block)
options = _normalize_render(*args, &block)
self.response_body = render_to_body(options)
end
# Raw rendering of a template to a string.
# :api: public
def render_to_string(*args, &block)
options = _normalize_render(*args, &block)
render_to_body(options)
end
# Raw rendering of a template.
# :api: public
def render_to_body(options = {})
_process_options(options)
_render_template(options)
end
# Find and renders a template based on the options given.
# :api: private
def _render_template(options) #:nodoc:
lookup_context.rendered_format = nil if options[:formats]
view_renderer.render(view_context, options)
end
def rendered_format
Mime[lookup_context.rendered_format]
end
def default_protected_instance_vars
super.concat([:@_view_context_class, :@_view_renderer, :@_lookup_context])
end
private
# Normalize args and options.
# :api: private
def _normalize_render(*args, &block)
options = _normalize_args(*args, &block)
_normalize_options(options)
options
end
# Normalize args by converting render "foo" to render :action => "foo" and
# render "foo/bar" to render :file => "foo/bar".
# :api: private
def _normalize_args(action=nil, options={})
options = super(action, options)
case action
when NilClass
when Hash
options = action
when String, Symbol
action = action.to_s
key = action.include?(?/) ? :file : :action
options[key] = action
else
options[:partial] = action
end
options
end
# Normalize options.
# :api: private
def _normalize_options(options)
options = super(options)
if options[:partial] == true
options[:partial] = action_name
end
if (options.keys & [:partial, :file, :template]).empty?
options[:prefixes] ||= _prefixes
end
options[:template] ||= (options[:action] || action_name).to_s
options
end
end
end

View File

@ -1,6 +1,6 @@
require 'action_view/base'
module AbstractController
module ActionView
module ViewPaths
extend ActiveSupport::Concern

View File

@ -24,7 +24,6 @@ require 'action_dispatch'
require 'active_support/dependencies'
require 'active_model'
require 'active_record'
require 'action_controller/caching'
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
@ -268,6 +267,10 @@ class Rack::TestCase < ActionDispatch::IntegrationTest
end
end
# Emulate AV railtie.
ActionController::Base.superclass.send(:include, ActionView::Layouts)
ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
module ActionController
class Base
include ActionController::Testing
@ -290,9 +293,6 @@ module ActionController
end
end
class ::ApplicationController < ActionController::Base
end
module ActionView
class TestCase
# Must repeat the setup because AV::TestCase is a duplication
@ -330,53 +330,3 @@ module ActionDispatch
end
end
module ActionDispatch
module RoutingVerbs
def get(uri_or_host, path = nil)
host = uri_or_host.host unless path
path ||= uri_or_host.path
params = {'PATH_INFO' => path,
'REQUEST_METHOD' => 'GET',
'HTTP_HOST' => host}
routes.call(params)[2].join
end
end
end
module RoutingTestHelpers
def url_for(set, options, recall = nil)
set.send(:url_for, options.merge(:only_path => true, :_recall => recall))
end
end
class ResourcesController < ActionController::Base
def index() render :nothing => true end
alias_method :show, :index
end
class ThreadsController < ResourcesController; end
class MessagesController < ResourcesController; end
class CommentsController < ResourcesController; end
class ReviewsController < ResourcesController; end
class AuthorsController < ResourcesController; end
class LogosController < ResourcesController; end
class AccountsController < ResourcesController; end
class AdminController < ResourcesController; end
class ProductsController < ResourcesController; end
class ImagesController < ResourcesController; end
class PreferencesController < ResourcesController; end
module Backoffice
class ProductsController < ResourcesController; end
class TagsController < ResourcesController; end
class ManufacturersController < ResourcesController; end
class ImagesController < ResourcesController; end
module Admin
class ProductsController < ResourcesController; end
class ImagesController < ResourcesController; end
end
end

View File

@ -30,6 +30,7 @@ module AbstractController
# ====
class RenderingController < AbstractController::Base
include AbstractController::Rendering
include ActionView::Rendering
def _prefixes
[]
@ -153,7 +154,7 @@ module AbstractController
# ====
# self._layout is used when defined
class WithLayouts < PrefixedViews
include AbstractController::Layouts
include ActionView::Layouts
private
def self.layout(formats)

View File

@ -1,13 +1,14 @@
require 'abstract_unit'
ActionController::Base.helpers_path = File.expand_path('../../fixtures/helpers', __FILE__)
ActionController::Base.helpers_path = File.expand_path('../../../fixtures/helpers', __FILE__)
module AbstractController
module Testing
class ControllerWithHelpers < AbstractController::Base
include AbstractController::Rendering
include AbstractController::Helpers
include AbstractController::Rendering
include ActionView::Rendering
def with_module
render :inline => "Module <%= included_method %>"
@ -51,7 +52,7 @@ module AbstractController
class AbstractInvalidHelpers < AbstractHelpers
include ActionController::Helpers
path = File.join(File.expand_path('../../fixtures', __FILE__), "helpers_missing")
path = File.join(File.expand_path('../../../fixtures', __FILE__), "helpers_missing")
$:.unshift(path)
self.helpers_path = path
end

View File

@ -6,7 +6,8 @@ module AbstractControllerTests
# Base controller for these tests
class Base < AbstractController::Base
include AbstractController::Rendering
include AbstractController::Layouts
include ActionView::Rendering
include ActionView::Layouts
abstract!

View File

@ -5,6 +5,7 @@ module AbstractController
class ControllerRenderer < AbstractController::Base
include AbstractController::Rendering
include ActionView::Rendering
def _prefixes
%w[renderer]

View File

@ -2,6 +2,8 @@ require 'abstract_unit'
require 'active_support/logger'
class CaptureController < ActionController::Base
self.view_paths = [ File.dirname(__FILE__) + '/../../fixtures/actionpack' ]
def self.controller_name; "test"; end
def self.controller_path; "test"; end

View File

@ -9,7 +9,7 @@ old_load_paths = ActionController::Base.view_paths
ActionView::Template::register_template_handler :mab,
lambda { |template| template.source.inspect }
ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/layout_tests/' ]
ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../../fixtures/actionpack/layout_tests/' ]
class LayoutTest < ActionController::Base
def self.controller_path; 'views' end
@ -87,7 +87,7 @@ class StreamingLayoutController < LayoutTest
end
class AbsolutePathLayoutController < LayoutTest
layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test')
layout File.expand_path(File.expand_path(__FILE__) + '/../../../fixtures/actionpack/layout_tests/layouts/layout_test')
end
class HasOwnLayoutController < LayoutTest
@ -108,7 +108,7 @@ end
class PrependsViewPathController < LayoutTest
def hello
prepend_view_path File.dirname(__FILE__) + '/../fixtures/layout_tests/alt/'
prepend_view_path File.dirname(__FILE__) + '/../../fixtures/actionpack/layout_tests/alt/'
render :layout => 'alt'
end
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<%= greeting %> bad customer: <%= bad_customer.name %><%= bad_customer_counter %>

View File

@ -0,0 +1,5 @@
This is my layout
<%= yield %>
End.

View File

@ -0,0 +1,2 @@
<div id="column"><%= yield :column %></div>
<div id="content"><%= yield %></div>

View File

@ -0,0 +1 @@
<title><%= yield Struct.new(:name).new("David") %></title>

View File

@ -0,0 +1,2 @@
<%= render :partial => 'test/partial' %>
<%= yield %>

View File

@ -0,0 +1 @@
<%= yield %>

View File

@ -0,0 +1 @@
<%= yield 'Yield!' %>

View File

@ -0,0 +1,3 @@
<%= render(:layout => "layout_for_partial", :locals => { :name => "Anthony" }) do %>Inside from first block in layout<% "Return value should be discarded" %><% end %>
<%= yield %>
<%= render(:layout => "layout_for_partial", :locals => { :name => "Ramm" }) do %>Inside from second block in layout<% end %>

Some files were not shown because too many files have changed in this diff Show More