mirror of https://github.com/rails/rails
Merge commit 'mainstream/master'
This commit is contained in:
commit
66ee2654ff
|
@ -30,5 +30,4 @@ railties/guides/output
|
|||
actionpack/bin
|
||||
vendor/gems/
|
||||
*/vendor/gems/
|
||||
bin/
|
||||
railties/tmp
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module ExampleHelper
|
||||
def example_format(text)
|
||||
"<em><strong><small>#{text}</small></strong></em>"
|
||||
"<em><strong><small>#{h(text)}</small></strong></em>".html_safe!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ gem "rack", "~> 1.0.0"
|
|||
gem "rack-test", "~> 0.5.0"
|
||||
gem "activesupport", "3.0.pre", :vendored_at => rails_root.join("activesupport")
|
||||
gem "activemodel", "3.0.pre", :vendored_at => rails_root.join("activemodel")
|
||||
gem "erubis", "~> 2.6.0"
|
||||
|
||||
only :test do
|
||||
gem "mocha"
|
||||
|
|
|
@ -34,22 +34,21 @@ end
|
|||
desc "Run all unit tests"
|
||||
task :test => [:test_action_pack, :test_active_record_integration]
|
||||
|
||||
TESTS_GLOB = "test/{abstract,controller,dispatch,new_base,template,html-scanner,view}/**/*_test.rb"
|
||||
|
||||
Rake::TestTask.new(:test_action_pack) do |t|
|
||||
t.libs << 'test'
|
||||
|
||||
# make sure we include the tests in alphabetical order as on some systems
|
||||
# this will not happen automatically and the tests (as a whole) will error
|
||||
t.test_files = Dir.glob(TESTS_GLOB).sort
|
||||
t.test_files = Dir.glob('test/{abstract,controller,dispatch,template}/**/*_test.rb').sort
|
||||
|
||||
t.verbose = true
|
||||
# t.warning = true
|
||||
end
|
||||
|
||||
task :isolated_test do
|
||||
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
|
||||
Dir.glob(TESTS_GLOB).all? { |file| system(ruby, '-Ilib:test', file) } or raise "Failures"
|
||||
namespace :test do
|
||||
Rake::TestTask.new(:isolated) do |t|
|
||||
t.pattern = 'test/ts_isolated.rb'
|
||||
end
|
||||
end
|
||||
|
||||
desc 'ActiveRecord Integration Tests'
|
||||
|
|
|
@ -50,7 +50,7 @@ module ActionController
|
|||
|
||||
def new
|
||||
# DEPRECATE Rails application fallback
|
||||
Rails.application
|
||||
Rails.application.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ module ActionController #:nodoc:
|
|||
self.session_store = ActiveRecord::SessionStore
|
||||
else
|
||||
@@session_store = store.is_a?(Symbol) ?
|
||||
Session.const_get(store.to_s.camelize) :
|
||||
ActionDispatch::Session.const_get(store.to_s.camelize) :
|
||||
store
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,6 +39,7 @@ module ActionDispatch
|
|||
autoload :Rescue, 'action_dispatch/middleware/rescue'
|
||||
autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions'
|
||||
autoload :Static, 'action_dispatch/middleware/static'
|
||||
autoload :StringCoercion, 'action_dispatch/middleware/string_coercion'
|
||||
|
||||
autoload :Assertions, 'action_dispatch/testing/assertions'
|
||||
autoload :Integration, 'action_dispatch/testing/integration'
|
||||
|
|
|
@ -10,7 +10,12 @@ module Mime
|
|||
%w(<< concat shift unshift push pop []= clear compact! collect!
|
||||
delete delete_at delete_if flatten! map! insert reject! reverse!
|
||||
replace slice! sort! uniq!).each do |method|
|
||||
define_method(method) {|*args| @symbols = nil; super(*args) }
|
||||
module_eval <<-CODE
|
||||
def #{method}(*args)
|
||||
@symbols = nil
|
||||
super
|
||||
end
|
||||
CODE
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
module ActionDispatch
|
||||
class StringCoercion
|
||||
class UglyBody < ActiveSupport::BasicObject
|
||||
def initialize(body)
|
||||
@body = body
|
||||
end
|
||||
|
||||
def each
|
||||
@body.each do |part|
|
||||
yield part.to_s
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def method_missing(*args, &block)
|
||||
@body.__send__(*args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, body = @app.call(env)
|
||||
[status, headers, UglyBody.new(body)]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -44,11 +44,11 @@ module ActionView
|
|||
autoload :TextTemplate, 'action_view/template/text'
|
||||
autoload :Helpers, 'action_view/helpers'
|
||||
autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
|
||||
autoload :SafeBuffer, 'action_view/safe_buffer'
|
||||
end
|
||||
|
||||
class ERB
|
||||
autoload :Util, 'action_view/erb/util'
|
||||
end
|
||||
require 'action_view/erb/util'
|
||||
|
||||
|
||||
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
|
||||
|
||||
|
|
|
@ -236,7 +236,16 @@ module ActionView #:nodoc:
|
|||
# they are in AC.
|
||||
if controller.class.respond_to?(:_helper_serial)
|
||||
klass = @views[controller.class._helper_serial] ||= Class.new(self) do
|
||||
Subclasses.const_set(controller.class.name.gsub(/::/, '__'), self)
|
||||
const_set(:CONTROLLER_CLASS, controller.class)
|
||||
|
||||
# Try to make stack traces clearer
|
||||
def self.name
|
||||
"ActionView for #{CONTROLLER_CLASS}"
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class.name}>"
|
||||
end
|
||||
|
||||
if controller.respond_to?(:_helpers)
|
||||
include controller._helpers
|
||||
|
@ -255,7 +264,7 @@ module ActionView #:nodoc:
|
|||
@assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
|
||||
@controller = controller
|
||||
@helpers = self.class.helpers || Module.new
|
||||
@_content_for = Hash.new {|h,k| h[k] = "" }
|
||||
@_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new }
|
||||
self.view_paths = view_paths
|
||||
end
|
||||
|
||||
|
|
|
@ -15,9 +15,19 @@ class ERB
|
|||
# puts html_escape("is a > 0 & a < 10?")
|
||||
# # => is a > 0 & a < 10?
|
||||
def html_escape(s)
|
||||
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
|
||||
s = s.to_s
|
||||
if s.html_safe?
|
||||
s
|
||||
else
|
||||
s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe!
|
||||
end
|
||||
end
|
||||
|
||||
alias h html_escape
|
||||
|
||||
module_function :html_escape
|
||||
module_function :h
|
||||
|
||||
# A utility method for escaping HTML entities in JSON strings.
|
||||
# This method is also aliased as <tt>j</tt>.
|
||||
#
|
||||
|
|
|
@ -15,6 +15,7 @@ module ActionView #:nodoc:
|
|||
autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper'
|
||||
autoload :NumberHelper, 'action_view/helpers/number_helper'
|
||||
autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
|
||||
autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper'
|
||||
autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
|
||||
autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper'
|
||||
autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper'
|
||||
|
@ -46,6 +47,7 @@ module ActionView #:nodoc:
|
|||
include JavaScriptHelper
|
||||
include NumberHelper
|
||||
include PrototypeHelper
|
||||
include RawOutputHelper
|
||||
include RecordIdentificationHelper
|
||||
include RecordTagHelper
|
||||
include SanitizeHelper
|
||||
|
|
|
@ -6,7 +6,7 @@ require 'active_support/core_ext/kernel/reporting'
|
|||
|
||||
module ActionView
|
||||
class Base
|
||||
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>" }
|
||||
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe! }
|
||||
cattr_accessor :field_error_proc
|
||||
end
|
||||
|
||||
|
@ -91,6 +91,7 @@ module ActionView
|
|||
yield contents if block_given?
|
||||
contents << submit_tag(submit_value)
|
||||
contents << '</form>'
|
||||
contents.html_safe!
|
||||
end
|
||||
|
||||
# Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
|
||||
|
|
|
@ -289,7 +289,7 @@ module ActionView
|
|||
else
|
||||
sources = expand_javascript_sources(sources, recursive)
|
||||
ensure_javascript_sources!(sources) if cache
|
||||
sources.collect { |source| javascript_src_tag(source, options) }.join("\n")
|
||||
sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe!
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -440,7 +440,7 @@ module ActionView
|
|||
else
|
||||
sources = expand_stylesheet_sources(sources, recursive)
|
||||
ensure_stylesheet_sources!(sources) if cache
|
||||
sources.collect { |source| stylesheet_tag(source, options) }.join("\n")
|
||||
sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe!
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -584,7 +584,7 @@ module ActionView
|
|||
|
||||
if sources.is_a?(Array)
|
||||
content_tag("video", options) do
|
||||
sources.map { |source| tag("source", :src => source) }.join
|
||||
sources.map { |source| tag("source", :src => source) }.join.html_safe!
|
||||
end
|
||||
else
|
||||
options[:src] = path_to_video(sources)
|
||||
|
|
|
@ -143,7 +143,7 @@ module ActionView
|
|||
# Defaults to a new empty string.
|
||||
def with_output_buffer(buf = nil) #:nodoc:
|
||||
unless buf
|
||||
buf = ''
|
||||
buf = ActionView::SafeBuffer.new
|
||||
buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding)
|
||||
end
|
||||
self.output_buffer, old_buffer = buf, output_buffer
|
||||
|
|
|
@ -916,15 +916,15 @@ module ActionView
|
|||
|
||||
class InstanceTag #:nodoc:
|
||||
def to_date_select_tag(options = {}, html_options = {})
|
||||
datetime_selector(options, html_options).select_date
|
||||
datetime_selector(options, html_options).select_date.html_safe!
|
||||
end
|
||||
|
||||
def to_time_select_tag(options = {}, html_options = {})
|
||||
datetime_selector(options, html_options).select_time
|
||||
datetime_selector(options, html_options).select_time.html_safe!
|
||||
end
|
||||
|
||||
def to_datetime_select_tag(options = {}, html_options = {})
|
||||
datetime_selector(options, html_options).select_datetime
|
||||
datetime_selector(options, html_options).select_datetime.html_safe!
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -282,7 +282,7 @@ module ActionView
|
|||
|
||||
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
|
||||
fields_for(object_name, *(args << options), &proc)
|
||||
concat('</form>')
|
||||
concat('</form>'.html_safe!)
|
||||
end
|
||||
|
||||
def apply_form_for_options!(object_or_array, options) #:nodoc:
|
||||
|
@ -809,7 +809,7 @@ module ActionView
|
|||
add_default_name_and_id(options)
|
||||
hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value)
|
||||
checkbox = tag("input", options)
|
||||
hidden + checkbox
|
||||
(hidden + checkbox).html_safe!
|
||||
end
|
||||
|
||||
def to_boolean_select_tag(options = {})
|
||||
|
|
|
@ -296,7 +296,7 @@ module ActionView
|
|||
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
|
||||
end
|
||||
|
||||
options_for_select.join("\n")
|
||||
options_for_select.join("\n").html_safe!
|
||||
end
|
||||
|
||||
# Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
|
||||
|
|
|
@ -440,7 +440,7 @@ module ActionView
|
|||
concat(tag(:fieldset, options, true))
|
||||
concat(content_tag(:legend, legend)) unless legend.blank?
|
||||
concat(content)
|
||||
concat("</fieldset>")
|
||||
concat("</fieldset>".html_safe!)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -467,14 +467,14 @@ module ActionView
|
|||
|
||||
def form_tag_html(html_options)
|
||||
extra_tags = extra_tags_for_form(html_options)
|
||||
tag(:form, html_options, true) + extra_tags
|
||||
(tag(:form, html_options, true) + extra_tags).html_safe!
|
||||
end
|
||||
|
||||
def form_tag_in_block(html_options, &block)
|
||||
content = capture(&block)
|
||||
concat(form_tag_html(html_options))
|
||||
concat(content)
|
||||
concat("</form>")
|
||||
concat("</form>".html_safe!)
|
||||
end
|
||||
|
||||
def token_tag
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
require 'active_support/core_ext/big_decimal/conversions'
|
||||
require 'active_support/core_ext/float/rounding'
|
||||
|
||||
module ActionView
|
||||
|
|
|
@ -395,7 +395,7 @@ module ActionView
|
|||
|
||||
concat(form_remote_tag(options))
|
||||
fields_for(object_name, *(args << options), &proc)
|
||||
concat('</form>')
|
||||
concat('</form>'.html_safe!)
|
||||
end
|
||||
alias_method :form_remote_for, :remote_form_for
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
module ActionView #:nodoc:
|
||||
module Helpers #:nodoc:
|
||||
module RawOutputHelper
|
||||
def raw(stringish)
|
||||
stringish.to_s.html_safe!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,7 +15,7 @@ module ActionView
|
|||
def div_for(record, *args, &block)
|
||||
content_tag_for(:div, record, *args, &block)
|
||||
end
|
||||
|
||||
|
||||
# content_tag_for creates an HTML element with id and class parameters
|
||||
# that relate to the specified Active Record object. For example:
|
||||
#
|
||||
|
@ -34,7 +34,7 @@ module ActionView
|
|||
# <% content_tag_for(:tr, @person, :foo) do %> ...
|
||||
#
|
||||
# produces:
|
||||
#
|
||||
#
|
||||
# <tr id="foo_person_123" class="person">...
|
||||
#
|
||||
# content_tag_for also accepts a hash of options, which will be converted to
|
||||
|
@ -50,7 +50,7 @@ module ActionView
|
|||
def content_tag_for(tag_name, record, *args, &block)
|
||||
prefix = args.first.is_a?(Hash) ? nil : args.shift
|
||||
options = args.extract_options!
|
||||
options.merge!({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
|
||||
options.merge!({ :class => "#{dom_class(record, prefix)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
|
||||
content_tag(tag_name, options, &block)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,7 +49,11 @@ module ActionView
|
|||
# confuse browsers.
|
||||
#
|
||||
def sanitize(html, options = {})
|
||||
self.class.white_list_sanitizer.sanitize(html, options)
|
||||
returning self.class.white_list_sanitizer.sanitize(html, options) do |sanitized|
|
||||
if sanitized
|
||||
sanitized.html_safe!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
|
||||
|
@ -72,7 +76,11 @@ module ActionView
|
|||
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
|
||||
# # => Welcome to my website!
|
||||
def strip_tags(html)
|
||||
self.class.full_sanitizer.sanitize(html)
|
||||
returning self.class.full_sanitizer.sanitize(html) do |sanitized|
|
||||
if sanitized
|
||||
sanitized.html_safe!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Strips all link tags from +text+ leaving just the link text.
|
||||
|
|
|
@ -41,7 +41,7 @@ module ActionView
|
|||
# tag("img", { :src => "open & shut.png" }, false, false)
|
||||
# # => <img src="open & shut.png" />
|
||||
def tag(name, options = nil, open = false, escape = true)
|
||||
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}"
|
||||
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe!
|
||||
end
|
||||
|
||||
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
|
||||
|
@ -94,7 +94,7 @@ module ActionView
|
|||
# cdata_section(File.read("hello_world.txt"))
|
||||
# # => <![CDATA[<hello from a text file]]>
|
||||
def cdata_section(content)
|
||||
"<![CDATA[#{content}]]>"
|
||||
"<![CDATA[#{content}]]>".html_safe!
|
||||
end
|
||||
|
||||
# Returns an escaped version of +html+ without affecting existing escaped entities.
|
||||
|
@ -128,7 +128,7 @@ module ActionView
|
|||
|
||||
def content_tag_string(name, content, options, escape = true)
|
||||
tag_options = tag_options(options, escape) if options
|
||||
"<#{name}#{tag_options}>#{content}</#{name}>"
|
||||
"<#{name}#{tag_options}>#{content}</#{name}>".html_safe!
|
||||
end
|
||||
|
||||
def tag_options(options, escape = true)
|
||||
|
@ -143,7 +143,7 @@ module ActionView
|
|||
attrs << %(#{key}="#{final_value}")
|
||||
end
|
||||
end
|
||||
" #{attrs.sort * ' '}" unless attrs.empty?
|
||||
" #{attrs.sort * ' '}".html_safe! unless attrs.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -93,7 +93,7 @@ module ActionView
|
|||
polymorphic_path(options)
|
||||
end
|
||||
|
||||
escape ? escape_once(url) : url
|
||||
(escape ? escape_once(url) : url).html_safe!
|
||||
end
|
||||
|
||||
# Creates a link tag of the given +name+ using a URL created by the set
|
||||
|
@ -220,7 +220,7 @@ module ActionView
|
|||
if block_given?
|
||||
options = args.first || {}
|
||||
html_options = args.second
|
||||
concat(link_to(capture(&block), options, html_options))
|
||||
concat(link_to(capture(&block), options, html_options).html_safe!)
|
||||
else
|
||||
name = args[0]
|
||||
options = args[1] || {}
|
||||
|
@ -238,7 +238,7 @@ module ActionView
|
|||
end
|
||||
|
||||
href_attr = "href=\"#{url}\"" unless href
|
||||
"<a #{href_attr}#{tag_options}>#{name || url}</a>"
|
||||
"<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe!
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -309,8 +309,8 @@ module ActionView
|
|||
|
||||
html_options.merge!("type" => "submit", "value" => name)
|
||||
|
||||
"<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +
|
||||
method_tag + tag("input", html_options) + request_token_tag + "</div></form>"
|
||||
("<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +
|
||||
method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe!
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
module ActionView #:nodoc:
|
||||
class PathSet < Array #:nodoc:
|
||||
def self.type_cast(obj)
|
||||
def self.type_cast(obj, cache = nil)
|
||||
# TODO: Clean this up
|
||||
if obj.is_a?(String)
|
||||
cache = !defined?(Rails) || !Rails.respond_to?(:configuration) || Rails.configuration.cache_classes
|
||||
if cache.nil?
|
||||
cache = !defined?(Rails) || Rails.application.config.cache_classes
|
||||
end
|
||||
FileSystemResolverWithFallback.new(obj, :cache => cache)
|
||||
else
|
||||
obj
|
||||
|
|
|
@ -223,7 +223,7 @@ module ActionView
|
|||
end
|
||||
|
||||
result = template ? collection_with_template(template) : collection_without_template
|
||||
result.join(spacer)
|
||||
result.join(spacer).html_safe!
|
||||
end
|
||||
|
||||
def collection_with_template(template)
|
||||
|
@ -296,7 +296,10 @@ module ActionView
|
|||
end
|
||||
|
||||
def _find_template(path)
|
||||
prefix = @view.controller.controller_path unless path.include?(?/)
|
||||
if controller = @view.controller
|
||||
prefix = controller.controller_path unless path.include?(?/)
|
||||
end
|
||||
|
||||
@view.find(path, {:formats => @view.formats}, prefix, true)
|
||||
end
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ module ActionView
|
|||
case options
|
||||
when Hash
|
||||
layout = options[:layout]
|
||||
options[:locals] ||= {}
|
||||
|
||||
if block_given?
|
||||
return concat(_render_partial(options.merge(:partial => layout), &block))
|
||||
|
@ -25,11 +26,11 @@ module ActionView
|
|||
|
||||
if file = options[:file]
|
||||
template = find(file, {:formats => formats})
|
||||
_render_template(template, layout, :locals => options[:locals] || {})
|
||||
_render_template(template, layout, :locals => options[:locals])
|
||||
elsif inline = options[:inline]
|
||||
_render_inline(inline, layout, options)
|
||||
elsif text = options[:text]
|
||||
_render_text(text, layout, options)
|
||||
_render_text(text, layout, options[:locals])
|
||||
end
|
||||
when :update
|
||||
update_page(&block)
|
||||
|
@ -80,16 +81,19 @@ module ActionView
|
|||
|
||||
def _render_inline(inline, layout, options)
|
||||
handler = Template.handler_class_for_extension(options[:type] || "erb")
|
||||
template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
|
||||
locals = options[:locals] || {}
|
||||
template = Template.new(options[:inline],
|
||||
"inline #{options[:inline].inspect}", handler, {})
|
||||
|
||||
locals = options[:locals]
|
||||
content = template.render(self, locals)
|
||||
content = layout.render(self, locals) {|*name| _layout_for(*name) { content } } if layout
|
||||
content
|
||||
_render_text(content, layout, locals)
|
||||
end
|
||||
|
||||
def _render_text(text, layout, options)
|
||||
text = layout.render(self, options[:locals]) { text } if layout
|
||||
text
|
||||
def _render_text(content, layout, locals)
|
||||
content = layout.render(self, locals) do |*name|
|
||||
_layout_for(*name) { content }
|
||||
end if layout
|
||||
content
|
||||
end
|
||||
|
||||
# This is the API to render a ViewContext's template from a controller.
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
module ActionView #:nodoc:
|
||||
class SafeBuffer < String
|
||||
def <<(value)
|
||||
if value.html_safe?
|
||||
super(value)
|
||||
else
|
||||
super(CGI.escapeHTML(value))
|
||||
end
|
||||
end
|
||||
|
||||
def concat(value)
|
||||
self << value
|
||||
end
|
||||
|
||||
def html_safe?
|
||||
true
|
||||
end
|
||||
|
||||
def html_safe!
|
||||
self
|
||||
end
|
||||
|
||||
def to_s
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,31 @@
|
|||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
require 'active_support/core_ext/string/output_safety'
|
||||
require 'erubis'
|
||||
|
||||
module ActionView
|
||||
module TemplateHandlers
|
||||
class Erubis < ::Erubis::Eruby
|
||||
def add_preamble(src)
|
||||
src << "@output_buffer = ActionView::SafeBuffer.new;"
|
||||
end
|
||||
|
||||
def add_text(src, text)
|
||||
src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
|
||||
end
|
||||
|
||||
def add_expr_literal(src, code)
|
||||
src << '@output_buffer << ((' << code << ').to_s);'
|
||||
end
|
||||
|
||||
def add_expr_escaped(src, code)
|
||||
src << '@output_buffer << ' << escaped_expr(code) << ';'
|
||||
end
|
||||
|
||||
def add_postamble(src)
|
||||
src << '@output_buffer.to_s'
|
||||
end
|
||||
end
|
||||
|
||||
class ERB < TemplateHandler
|
||||
include Compilable
|
||||
|
||||
|
@ -15,11 +39,9 @@ module ActionView
|
|||
self.default_format = Mime::HTML
|
||||
|
||||
def compile(template)
|
||||
require 'erb'
|
||||
|
||||
magic = $1 if template.source =~ /\A(<%#.*coding[:=]\s*(\S+)\s*-?%>)/
|
||||
erb = "#{magic}<% __in_erb_template=true %>#{template.source}"
|
||||
::ERB.new(erb, nil, erb_trim_mode, '@output_buffer').src
|
||||
Erubis.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -55,7 +55,7 @@ module ActionView
|
|||
setup :setup_with_controller
|
||||
def setup_with_controller
|
||||
@controller = TestController.new
|
||||
@output_buffer = ''
|
||||
@output_buffer = ActionView::SafeBuffer.new
|
||||
@rendered = ''
|
||||
|
||||
self.class.send(:include_helper_modules!)
|
||||
|
|
|
@ -51,23 +51,73 @@ I18n.backend.store_translations 'pt-BR', {}
|
|||
ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort
|
||||
|
||||
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
||||
FIXTURES = Pathname.new(FIXTURE_LOAD_PATH)
|
||||
|
||||
class ActionController::IntegrationTest < ActiveSupport::TestCase
|
||||
@@app = ActionDispatch::MiddlewareStack.new { |middleware|
|
||||
middleware.use "ActionDispatch::ShowExceptions"
|
||||
middleware.use "ActionDispatch::Callbacks"
|
||||
middleware.use "ActionDispatch::ParamsParser"
|
||||
middleware.use "Rack::Head"
|
||||
}.build(ActionController::Routing::Routes)
|
||||
end
|
||||
module SetupOnce
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ActionView
|
||||
class TestCase
|
||||
setup do
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.connect ':controller/:action/:id'
|
||||
included do
|
||||
cattr_accessor :setup_once_block
|
||||
self.setup_once_block = nil
|
||||
|
||||
setup :run_setup_once
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def setup_once(&block)
|
||||
self.setup_once_block = block
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def run_setup_once
|
||||
if self.setup_once_block
|
||||
self.setup_once_block.call
|
||||
self.setup_once_block = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ActiveSupport::TestCase
|
||||
include SetupOnce
|
||||
|
||||
# Hold off drawing routes until all the possible controller classes
|
||||
# have been loaded.
|
||||
setup_once do
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ActionController::IntegrationTest < ActiveSupport::TestCase
|
||||
def self.build_app(routes = nil)
|
||||
ActionDispatch::MiddlewareStack.new { |middleware|
|
||||
middleware.use "ActionDispatch::StringCoercion"
|
||||
middleware.use "ActionDispatch::ShowExceptions"
|
||||
middleware.use "ActionDispatch::Callbacks"
|
||||
middleware.use "ActionDispatch::ParamsParser"
|
||||
middleware.use "Rack::Head"
|
||||
}.build(routes || ActionController::Routing::Routes)
|
||||
end
|
||||
|
||||
self.app = build_app
|
||||
|
||||
def with_routing(&block)
|
||||
real_routes = ActionController::Routing::Routes
|
||||
ActionController::Routing.module_eval { remove_const :Routes }
|
||||
|
||||
temporary_routes = ActionController::Routing::RouteSet.new
|
||||
self.class.app = self.class.build_app(temporary_routes)
|
||||
ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
|
||||
|
||||
yield temporary_routes
|
||||
ensure
|
||||
if ActionController::Routing.const_defined? :Routes
|
||||
ActionController::Routing.module_eval { remove_const :Routes }
|
||||
end
|
||||
ActionController::Routing.const_set(:Routes, real_routes) if real_routes
|
||||
self.class.app = self.class.build_app
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -138,18 +188,12 @@ module ActionController
|
|||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Base.view_paths = FIXTURE_LOAD_PATH
|
||||
|
||||
|
||||
class TestCase
|
||||
include TestProcess
|
||||
|
||||
setup do
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
end
|
||||
|
||||
def assert_template(options = {}, message = nil)
|
||||
validate_request!
|
||||
|
||||
|
@ -192,11 +236,3 @@ module ActionController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class SimpleRouteCase < Rack::TestCase
|
||||
setup do
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -158,7 +158,6 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
|
|||
map.connect "/:action", :controller => "active_record_store_test/test"
|
||||
end
|
||||
@app = ActiveRecord::SessionStore.new(set, options.reverse_merge(:key => '_session_id'))
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,14 +46,8 @@ end
|
|||
class PageCachingTest < ActionController::TestCase
|
||||
def setup
|
||||
super
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.main '', :controller => 'posts', :format => nil
|
||||
map.formatted_posts 'posts.:format', :controller => 'posts'
|
||||
map.resources :posts
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
ActionController::Base.perform_caching = true
|
||||
|
||||
@request = ActionController::TestRequest.new
|
||||
@request.host = 'hostname.com'
|
||||
|
@ -74,10 +68,16 @@ class PageCachingTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
|
||||
@params[:format] = 'rss'
|
||||
assert_equal '/posts.rss', @rewriter.rewrite(@params)
|
||||
@params[:format] = nil
|
||||
assert_equal '/', @rewriter.rewrite(@params)
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
map.main '', :controller => 'posts', :format => nil
|
||||
map.formatted_posts 'posts.:format', :controller => 'posts'
|
||||
end
|
||||
@params[:format] = 'rss'
|
||||
assert_equal '/posts.rss', @rewriter.rewrite(@params)
|
||||
@params[:format] = nil
|
||||
assert_equal '/', @rewriter.rewrite(@params)
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_cache_get_with_ok_status
|
||||
|
|
|
@ -372,11 +372,8 @@ class IntegrationProcessTest < ActionController::IntegrationTest
|
|||
def with_test_route_set
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
map.with_options :controller => "IntegrationProcessTest::Integration" do |c|
|
||||
c.connect "/:action"
|
||||
end
|
||||
map.connect "/:action", :controller => "integration_process_test/integration"
|
||||
end
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -527,12 +527,6 @@ class RespondWithControllerTest < ActionController::TestCase
|
|||
super
|
||||
ActionController::Base.use_accept_header = true
|
||||
@request.host = "www.example.com"
|
||||
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.resources :customers
|
||||
map.resources :quiz_stores, :has_many => :customers
|
||||
map.connect ":controller/:action/:id"
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
|
@ -593,53 +587,59 @@ class RespondWithControllerTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_using_resource_for_post_with_html
|
||||
post :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 302, @response.status
|
||||
assert_equal "http://www.example.com/customers/13", @response.location
|
||||
assert @response.redirect?
|
||||
with_test_route_set do
|
||||
post :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 302, @response.status
|
||||
assert_equal "http://www.example.com/customers/13", @response.location
|
||||
assert @response.redirect?
|
||||
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
post :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 200, @response.status
|
||||
assert_equal "New world!\n", @response.body
|
||||
assert_nil @response.location
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
post :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 200, @response.status
|
||||
assert_equal "New world!\n", @response.body
|
||||
assert_nil @response.location
|
||||
end
|
||||
end
|
||||
|
||||
def test_using_resource_for_post_with_xml
|
||||
@request.accept = "application/xml"
|
||||
with_test_route_set do
|
||||
@request.accept = "application/xml"
|
||||
|
||||
post :using_resource
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 201, @response.status
|
||||
assert_equal "<name>david</name>", @response.body
|
||||
assert_equal "http://www.example.com/customers/13", @response.location
|
||||
post :using_resource
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 201, @response.status
|
||||
assert_equal "<name>david</name>", @response.body
|
||||
assert_equal "http://www.example.com/customers/13", @response.location
|
||||
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
post :using_resource
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 422, @response.status
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_nil @response.location
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
post :using_resource
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 422, @response.status
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_nil @response.location
|
||||
end
|
||||
end
|
||||
|
||||
def test_using_resource_for_put_with_html
|
||||
put :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 302, @response.status
|
||||
assert_equal "http://www.example.com/customers/13", @response.location
|
||||
assert @response.redirect?
|
||||
with_test_route_set do
|
||||
put :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 302, @response.status
|
||||
assert_equal "http://www.example.com/customers/13", @response.location
|
||||
assert @response.redirect?
|
||||
|
||||
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
|
||||
assert_nil @response.location
|
||||
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
|
||||
assert_nil @response.location
|
||||
end
|
||||
end
|
||||
|
||||
def test_using_resource_for_put_with_xml
|
||||
|
@ -660,11 +660,13 @@ class RespondWithControllerTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_using_resource_for_delete_with_html
|
||||
Customer.any_instance.stubs(:destroyed?).returns(true)
|
||||
delete :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 302, @response.status
|
||||
assert_equal "http://www.example.com/customers", @response.location
|
||||
with_test_route_set do
|
||||
Customer.any_instance.stubs(:destroyed?).returns(true)
|
||||
delete :using_resource
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal 302, @response.status
|
||||
assert_equal "http://www.example.com/customers", @response.location
|
||||
end
|
||||
end
|
||||
|
||||
def test_using_resource_for_delete_with_xml
|
||||
|
@ -685,21 +687,23 @@ class RespondWithControllerTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_using_resource_with_parent_for_post
|
||||
@request.accept = "application/xml"
|
||||
with_test_route_set do
|
||||
@request.accept = "application/xml"
|
||||
|
||||
post :using_resource_with_parent
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 201, @response.status
|
||||
assert_equal "<name>david</name>", @response.body
|
||||
assert_equal "http://www.example.com/quiz_stores/11/customers/13", @response.location
|
||||
post :using_resource_with_parent
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 201, @response.status
|
||||
assert_equal "<name>david</name>", @response.body
|
||||
assert_equal "http://www.example.com/quiz_stores/11/customers/13", @response.location
|
||||
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
post :using_resource
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 422, @response.status
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_nil @response.location
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
post :using_resource
|
||||
assert_equal "application/xml", @response.content_type
|
||||
assert_equal 422, @response.status
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_nil @response.location
|
||||
end
|
||||
end
|
||||
|
||||
def test_using_resource_with_collection
|
||||
|
@ -773,6 +777,18 @@ class RespondWithControllerTest < ActionController::TestCase
|
|||
get :default_overwritten
|
||||
assert_equal 406, @response.status
|
||||
end
|
||||
|
||||
private
|
||||
def with_test_route_set
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
map.resources :customers
|
||||
map.resources :quiz_stores, :has_many => :customers
|
||||
map.connect ":controller/:action/:id"
|
||||
end
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class AbstractPostController < ActionController::Base
|
||||
|
|
|
@ -26,7 +26,7 @@ module Dispatching
|
|||
class ContainedEmptyController < ActionController::Base ; end
|
||||
end
|
||||
|
||||
class BaseTest < SimpleRouteCase
|
||||
class BaseTest < Rack::TestCase
|
||||
# :api: plugin
|
||||
test "simple dispatching" do
|
||||
get "/dispatching/simple/index"
|
|
@ -9,7 +9,7 @@ module ContentNegotiation
|
|||
)]
|
||||
end
|
||||
|
||||
class TestContentNegotiation < SimpleRouteCase
|
||||
class TestContentNegotiation < Rack::TestCase
|
||||
test "A */* Accept header will return HTML" do
|
||||
get "/content_negotiation/basic/hello", {}, "HTTP_ACCEPT" => "*/*"
|
||||
assert_body "Hello world */*!"
|
|
@ -44,7 +44,7 @@ module ContentType
|
|||
end
|
||||
end
|
||||
|
||||
class ExplicitContentTypeTest < SimpleRouteCase
|
||||
class ExplicitContentTypeTest < Rack::TestCase
|
||||
test "default response is HTML and UTF8" do
|
||||
get "/content_type/base"
|
||||
|
||||
|
@ -67,7 +67,7 @@ module ContentType
|
|||
end
|
||||
end
|
||||
|
||||
class ImpliedContentTypeTest < SimpleRouteCase
|
||||
class ImpliedContentTypeTest < Rack::TestCase
|
||||
test "sets Content-Type as text/html when rendering *.html.erb" do
|
||||
get "/content_type/implied/i_am_html_erb"
|
||||
|
||||
|
@ -93,7 +93,7 @@ module ContentType
|
|||
end
|
||||
end
|
||||
|
||||
class ExplicitCharsetTest < SimpleRouteCase
|
||||
class ExplicitCharsetTest < Rack::TestCase
|
||||
test "setting the charset of the response directly on the response object" do
|
||||
get "/content_type/charset/set_on_response_obj"
|
||||
|
|
@ -16,7 +16,7 @@ module Etags
|
|||
end
|
||||
end
|
||||
|
||||
class EtagTest < SimpleRouteCase
|
||||
class EtagTest < Rack::TestCase
|
||||
describe "Rendering without any special etag options returns an etag that is an MD5 hash of its text"
|
||||
|
||||
test "an action without a layout" do
|
|
@ -45,7 +45,7 @@ module RenderAction
|
|||
|
||||
end
|
||||
|
||||
class RenderActionTest < SimpleRouteCase
|
||||
class RenderActionTest < Rack::TestCase
|
||||
test "rendering an action using :action => <String>" do
|
||||
get "/render_action/basic/hello_world"
|
||||
|
||||
|
@ -82,7 +82,7 @@ module RenderAction
|
|||
end
|
||||
end
|
||||
|
||||
class RenderLayoutTest < SimpleRouteCase
|
||||
class RenderLayoutTest < Rack::TestCase
|
||||
describe "Both <controller_path>.html.erb and application.html.erb are missing"
|
||||
|
||||
test "rendering with layout => true" do
|
||||
|
@ -150,7 +150,7 @@ module RenderActionWithApplicationLayout
|
|||
end
|
||||
end
|
||||
|
||||
class LayoutTest < SimpleRouteCase
|
||||
class LayoutTest < Rack::TestCase
|
||||
describe "Only application.html.erb is present and <controller_path>.html.erb is missing"
|
||||
|
||||
test "rendering implicit application.html.erb as layout" do
|
||||
|
@ -189,7 +189,7 @@ module RenderActionWithApplicationLayout
|
|||
end
|
||||
end
|
||||
|
||||
class TestLayout < SimpleRouteCase
|
||||
class TestLayout < Rack::TestCase
|
||||
testing BasicController
|
||||
|
||||
test "builder works with layouts" do
|
||||
|
@ -228,7 +228,7 @@ module RenderActionWithControllerLayout
|
|||
end
|
||||
end
|
||||
|
||||
class ControllerLayoutTest < SimpleRouteCase
|
||||
class ControllerLayoutTest < Rack::TestCase
|
||||
describe "Only <controller_path>.html.erb is present and application.html.erb is missing"
|
||||
|
||||
test "render hello_world and implicitly use <controller_path>.html.erb as a layout." do
|
||||
|
@ -286,7 +286,7 @@ module RenderActionWithBothLayouts
|
|||
end
|
||||
end
|
||||
|
||||
class ControllerLayoutTest < SimpleRouteCase
|
||||
class ControllerLayoutTest < Rack::TestCase
|
||||
describe "Both <controller_path>.html.erb and application.html.erb are present"
|
||||
|
||||
test "rendering implicitly use <controller_path>.html.erb over application.html.erb as a layout" do
|
|
@ -1,110 +1,99 @@
|
|||
require 'abstract_unit'
|
||||
|
||||
module RenderFile
|
||||
|
||||
class BasicController < ActionController::Base
|
||||
self.view_paths = File.dirname(__FILE__)
|
||||
|
||||
self.view_paths = File.dirname(__FILE__)
|
||||
|
||||
def index
|
||||
render :file => File.join(File.dirname(__FILE__), *%w[.. fixtures test hello_world])
|
||||
render :file => File.join(File.dirname(__FILE__), *%w[.. .. fixtures test hello_world])
|
||||
end
|
||||
|
||||
|
||||
def with_instance_variables
|
||||
@secret = 'in the sauce'
|
||||
render :file => File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
|
||||
render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar.erb')
|
||||
end
|
||||
|
||||
|
||||
def without_file_key
|
||||
render File.join(File.dirname(__FILE__), *%w[.. fixtures test hello_world])
|
||||
render File.join(File.dirname(__FILE__), *%w[.. .. fixtures test hello_world])
|
||||
end
|
||||
|
||||
|
||||
def without_file_key_with_instance_variable
|
||||
@secret = 'in the sauce'
|
||||
render File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
|
||||
render File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar.erb')
|
||||
end
|
||||
|
||||
|
||||
def relative_path
|
||||
@secret = 'in the sauce'
|
||||
render :file => '../fixtures/test/render_file_with_ivar'
|
||||
render :file => '../../fixtures/test/render_file_with_ivar'
|
||||
end
|
||||
|
||||
|
||||
def relative_path_with_dot
|
||||
@secret = 'in the sauce'
|
||||
render :file => '../fixtures/test/dot.directory/render_file_with_ivar'
|
||||
render :file => '../../fixtures/test/dot.directory/render_file_with_ivar'
|
||||
end
|
||||
|
||||
|
||||
def pathname
|
||||
@secret = 'in the sauce'
|
||||
render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. fixtures test dot.directory render_file_with_ivar.erb])
|
||||
render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar.erb])
|
||||
end
|
||||
|
||||
|
||||
def with_locals
|
||||
path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')
|
||||
path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals.erb')
|
||||
render :file => path, :locals => {:secret => 'in the sauce'}
|
||||
end
|
||||
|
||||
|
||||
def without_file_key_with_locals
|
||||
path = File.expand_path('../fixtures/test/render_file_with_locals.erb')
|
||||
path = FIXTURES.join('test/render_file_with_locals.erb').to_s
|
||||
render path, :locals => {:secret => 'in the sauce'}
|
||||
end
|
||||
end
|
||||
|
||||
class TestBasic < SimpleRouteCase
|
||||
|
||||
class TestBasic < Rack::TestCase
|
||||
testing RenderFile::BasicController
|
||||
|
||||
def setup
|
||||
@old_pwd = Dir.pwd
|
||||
Dir.chdir(File.dirname(__FILE__))
|
||||
end
|
||||
|
||||
def teardown
|
||||
Dir.chdir(@old_pwd)
|
||||
end
|
||||
|
||||
|
||||
test "rendering simple template" do
|
||||
get :index
|
||||
assert_response "Hello world!"
|
||||
end
|
||||
|
||||
|
||||
test "rendering template with ivar" do
|
||||
get :with_instance_variables
|
||||
assert_response "The secret is in the sauce\n"
|
||||
end
|
||||
|
||||
|
||||
test "rendering path without specifying the :file key" do
|
||||
get :without_file_key
|
||||
assert_response "Hello world!"
|
||||
end
|
||||
|
||||
|
||||
test "rendering path without specifying the :file key with ivar" do
|
||||
get :without_file_key_with_instance_variable
|
||||
assert_response "The secret is in the sauce\n"
|
||||
end
|
||||
|
||||
|
||||
test "rendering a relative path" do
|
||||
get :relative_path
|
||||
assert_response "The secret is in the sauce\n"
|
||||
end
|
||||
|
||||
|
||||
test "rendering a relative path with dot" do
|
||||
get :relative_path_with_dot
|
||||
assert_response "The secret is in the sauce\n"
|
||||
end
|
||||
|
||||
|
||||
test "rendering a Pathname" do
|
||||
get :pathname
|
||||
assert_response "The secret is in the sauce\n"
|
||||
end
|
||||
|
||||
|
||||
test "rendering file with locals" do
|
||||
get :with_locals
|
||||
assert_response "The secret is in the sauce\n"
|
||||
end
|
||||
|
||||
|
||||
test "rendering path without specifying the :file key with locals" do
|
||||
get :without_file_key_with_locals
|
||||
assert_response "The secret is in the sauce\n"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -10,7 +10,7 @@ module RenderImplicitAction
|
|||
def hello_world() end
|
||||
end
|
||||
|
||||
class RenderImplicitActionTest < SimpleRouteCase
|
||||
class RenderImplicitActionTest < Rack::TestCase
|
||||
test "render a simple action with new explicit call to render" do
|
||||
get "/render_implicit_action/simple/hello_world"
|
||||
|
|
@ -36,7 +36,7 @@ module ControllerLayouts
|
|||
end
|
||||
end
|
||||
|
||||
class RenderLayoutTest < SimpleRouteCase
|
||||
class RenderLayoutTest < Rack::TestCase
|
||||
test "rendering a normal template, but using the implicit layout" do
|
||||
get "/controller_layouts/implicit/index"
|
||||
|
||||
|
@ -58,7 +58,7 @@ module ControllerLayouts
|
|||
|
||||
end
|
||||
|
||||
class LayoutOptionsTest < SimpleRouteCase
|
||||
class LayoutOptionsTest < Rack::TestCase
|
||||
testing ControllerLayouts::ImplicitController
|
||||
|
||||
test "rendering with :layout => false leaves out the implicit layout" do
|
||||
|
@ -79,7 +79,7 @@ module ControllerLayouts
|
|||
end
|
||||
end
|
||||
|
||||
class MismatchFormatTest < SimpleRouteCase
|
||||
class MismatchFormatTest < Rack::TestCase
|
||||
testing ControllerLayouts::MismatchFormatController
|
||||
|
||||
test "if JS is selected, an HTML template is not also selected" do
|
|
@ -15,7 +15,7 @@ module RenderPartial
|
|||
end
|
||||
end
|
||||
|
||||
class TestPartial < SimpleRouteCase
|
||||
class TestPartial < Rack::TestCase
|
||||
testing BasicController
|
||||
|
||||
test "rendering a partial in ActionView doesn't pull the ivars again from the controller" do
|
|
@ -21,7 +21,7 @@ module RenderRjs
|
|||
end
|
||||
end
|
||||
|
||||
class TestBasic < SimpleRouteCase
|
||||
class TestBasic < Rack::TestCase
|
||||
testing BasicController
|
||||
|
||||
def setup
|
|
@ -39,7 +39,7 @@ module RenderTemplate
|
|||
end
|
||||
end
|
||||
|
||||
class TestWithoutLayout < SimpleRouteCase
|
||||
class TestWithoutLayout < Rack::TestCase
|
||||
testing RenderTemplate::WithoutLayoutController
|
||||
|
||||
test "rendering a normal template with full path without layout" do
|
||||
|
@ -107,7 +107,7 @@ module RenderTemplate
|
|||
end
|
||||
end
|
||||
|
||||
class TestWithLayout < SimpleRouteCase
|
||||
class TestWithLayout < Rack::TestCase
|
||||
describe "Rendering with :template using implicit or explicit layout"
|
||||
|
||||
test "rendering with implicit layout" do
|
||||
|
@ -158,7 +158,7 @@ module RenderTemplate
|
|||
end
|
||||
end
|
||||
|
||||
class TestTemplateRenderWithForwardSlash < SimpleRouteCase
|
||||
class TestTemplateRenderWithForwardSlash < Rack::TestCase
|
||||
test "rendering a normal template with full path starting with a leading slash" do
|
||||
get "/render_template/compatibility/without_layout/with_forward_slash"
|
||||
|
|
@ -35,7 +35,7 @@ module Render
|
|||
end
|
||||
end
|
||||
|
||||
class RenderTest < SimpleRouteCase
|
||||
class RenderTest < Rack::TestCase
|
||||
test "render with blank" do
|
||||
get "/render/blank_render"
|
||||
|
||||
|
@ -50,7 +50,7 @@ module Render
|
|||
end
|
||||
end
|
||||
|
||||
class TestOnlyRenderPublicActions < SimpleRouteCase
|
||||
class TestOnlyRenderPublicActions < Rack::TestCase
|
||||
describe "Only public methods on actual controllers are callable actions"
|
||||
|
||||
test "raises an exception when a method of Object is called" do
|
||||
|
@ -66,7 +66,7 @@ module Render
|
|||
end
|
||||
end
|
||||
|
||||
class TestVariousObjectsAvailableInView < SimpleRouteCase
|
||||
class TestVariousObjectsAvailableInView < Rack::TestCase
|
||||
test "The request object is accessible in the view" do
|
||||
get "/render/blank_render/access_request"
|
||||
assert_body "The request: GET"
|
|
@ -62,7 +62,7 @@ module RenderText
|
|||
end
|
||||
end
|
||||
|
||||
class RenderTextTest < SimpleRouteCase
|
||||
class RenderTextTest < Rack::TestCase
|
||||
describe "Rendering text using render :text"
|
||||
|
||||
test "rendering text from a action with default options renders the text with the layout" do
|
|
@ -0,0 +1,19 @@
|
|||
require 'abstract_unit'
|
||||
|
||||
class OutputEscapingTest < ActiveSupport::TestCase
|
||||
|
||||
test "escape_html shouldn't die when passed nil" do
|
||||
assert ERB::Util.h(nil).blank?
|
||||
end
|
||||
|
||||
test "escapeHTML should escape strings" do
|
||||
assert_equal "<>"", ERB::Util.h("<>\"")
|
||||
end
|
||||
|
||||
test "escapeHTML shouldn't touch explicitly safe strings" do
|
||||
# TODO this seems easier to compose and reason about, but
|
||||
# this should be verified
|
||||
assert_equal "<", ERB::Util.h("<".html_safe!)
|
||||
end
|
||||
|
||||
end
|
|
@ -1050,7 +1050,7 @@ class RenderTest < ActionController::TestCase
|
|||
|
||||
def test_action_talk_to_layout
|
||||
get :action_talk_to_layout
|
||||
assert_equal "<title>Talking to the layout</title>\nAction was here!", @response.body
|
||||
assert_equal "<title>Talking to the layout</title>\n\nAction was here!", @response.body
|
||||
end
|
||||
|
||||
# :addressed:
|
||||
|
|
|
@ -347,7 +347,6 @@ class RescueTest < ActionController::IntegrationTest
|
|||
map.connect 'invalid', :controller => "rescue_test/test", :action => 'invalid'
|
||||
map.connect 'b00m', :controller => "rescue_test/test", :action => 'b00m'
|
||||
end
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -669,21 +669,13 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
|||
|
||||
%w(GET POST PUT DELETE).each do |request_method|
|
||||
define_method("test_request_method_recognized_with_#{request_method}") do
|
||||
begin
|
||||
Object.const_set(:BooksController, Class.new(ActionController::Base))
|
||||
|
||||
setup_request_method_routes_for(request_method)
|
||||
|
||||
assert_nothing_raised { rs.recognize(@request) }
|
||||
assert_equal request_method.downcase, @request.path_parameters[:action]
|
||||
ensure
|
||||
Object.send(:remove_const, :BooksController) rescue nil
|
||||
end
|
||||
setup_request_method_routes_for(request_method)
|
||||
assert_nothing_raised { rs.recognize(@request) }
|
||||
assert_equal request_method.downcase, @request.path_parameters[:action]
|
||||
end
|
||||
end
|
||||
|
||||
def test_recognize_array_of_methods
|
||||
Object.const_set(:BooksController, Class.new(ActionController::Base))
|
||||
rs.draw do |r|
|
||||
r.connect '/match', :controller => 'books', :action => 'get_or_post', :conditions => { :method => [:get, :post] }
|
||||
r.connect '/match', :controller => 'books', :action => 'not_get_or_post'
|
||||
|
@ -701,13 +693,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
|||
@request.request_uri = "/match"
|
||||
assert_nothing_raised { rs.recognize(@request) }
|
||||
assert_equal 'not_get_or_post', @request.path_parameters[:action]
|
||||
ensure
|
||||
Object.send(:remove_const, :BooksController) rescue nil
|
||||
end
|
||||
|
||||
def test_subpath_recognized
|
||||
Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
|
||||
|
||||
rs.draw do |r|
|
||||
r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
|
||||
r.connect '/items/:id/:action', :controller => 'subpath_books'
|
||||
|
@ -730,13 +718,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
|||
hash = rs.recognize_path "/posts/7"
|
||||
assert_not_nil hash
|
||||
assert_equal %w(subpath_books show 7), [hash[:controller], hash[:action], hash[:id]]
|
||||
ensure
|
||||
Object.send(:remove_const, :SubpathBooksController) rescue nil
|
||||
end
|
||||
|
||||
def test_subpath_generated
|
||||
Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
|
||||
|
||||
rs.draw do |r|
|
||||
r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
|
||||
r.connect '/items/:id/:action', :controller => 'subpath_books'
|
||||
|
@ -746,8 +730,6 @@ class LegacyRouteSetTests < Test::Unit::TestCase
|
|||
assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit")
|
||||
assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete")
|
||||
assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview")
|
||||
ensure
|
||||
Object.send(:remove_const, :SubpathBooksController) rescue nil
|
||||
end
|
||||
|
||||
def test_failed_requirements_raises_exception_with_violated_requirements
|
||||
|
@ -1122,8 +1104,6 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def test_recognize_with_conditions
|
||||
Object.const_set(:PeopleController, Class.new)
|
||||
|
||||
set.draw do |map|
|
||||
map.with_options(:controller => "people") do |people|
|
||||
people.people "/people", :action => "index", :conditions => { :method => :get }
|
||||
|
@ -1183,14 +1163,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_equal [:get, :put, :delete], e.allowed_methods
|
||||
end
|
||||
request.recycle!
|
||||
|
||||
ensure
|
||||
Object.send(:remove_const, :PeopleController)
|
||||
end
|
||||
|
||||
def test_recognize_with_alias_in_conditions
|
||||
Object.const_set(:PeopleController, Class.new)
|
||||
|
||||
set.draw do |map|
|
||||
map.people "/people", :controller => 'people', :action => "index",
|
||||
:conditions => { :method => :get }
|
||||
|
@ -1208,13 +1183,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_nothing_raised { set.recognize(request) }
|
||||
assert_equal("people", request.path_parameters[:controller])
|
||||
assert_equal("index", request.path_parameters[:action])
|
||||
ensure
|
||||
Object.send(:remove_const, :PeopleController)
|
||||
end
|
||||
|
||||
def test_typo_recognition
|
||||
Object.const_set(:ArticlesController, Class.new)
|
||||
|
||||
set.draw do |map|
|
||||
map.connect 'articles/:year/:month/:day/:title',
|
||||
:controller => 'articles', :action => 'permalink',
|
||||
|
@ -1229,9 +1200,6 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_equal("11", request.path_parameters[:month])
|
||||
assert_equal("05", request.path_parameters[:day])
|
||||
assert_equal("a-very-interesting-article", request.path_parameters[:title])
|
||||
|
||||
ensure
|
||||
Object.send(:remove_const, :ArticlesController)
|
||||
end
|
||||
|
||||
def test_routing_traversal_does_not_load_extra_classes
|
||||
|
@ -1248,8 +1216,6 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def test_recognize_with_conditions_and_format
|
||||
Object.const_set(:PeopleController, Class.new)
|
||||
|
||||
set.draw do |map|
|
||||
map.with_options(:controller => "people") do |people|
|
||||
people.person "/people/:id", :action => "show", :conditions => { :method => :get }
|
||||
|
@ -1276,8 +1242,6 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_equal("show", request.path_parameters[:action])
|
||||
assert_equal("5", request.path_parameters[:id])
|
||||
assert_equal("png", request.path_parameters[:_format])
|
||||
ensure
|
||||
Object.send(:remove_const, :PeopleController)
|
||||
end
|
||||
|
||||
def test_generate_with_default_action
|
||||
|
@ -1291,8 +1255,6 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def test_root_map
|
||||
Object.const_set(:PeopleController, Class.new)
|
||||
|
||||
set.draw { |map| map.root :controller => "people" }
|
||||
|
||||
request.path = ""
|
||||
|
@ -1300,13 +1262,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_nothing_raised { set.recognize(request) }
|
||||
assert_equal("people", request.path_parameters[:controller])
|
||||
assert_equal("index", request.path_parameters[:action])
|
||||
ensure
|
||||
Object.send(:remove_const, :PeopleController)
|
||||
end
|
||||
|
||||
def test_namespace
|
||||
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
|
||||
|
||||
set.draw do |map|
|
||||
|
||||
map.namespace 'api' do |api|
|
||||
|
@ -1320,13 +1278,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_nothing_raised { set.recognize(request) }
|
||||
assert_equal("api/products", request.path_parameters[:controller])
|
||||
assert_equal("inventory", request.path_parameters[:action])
|
||||
ensure
|
||||
Object.send(:remove_const, :Api)
|
||||
end
|
||||
|
||||
def test_namespaced_root_map
|
||||
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
|
||||
|
||||
set.draw do |map|
|
||||
|
||||
map.namespace 'api' do |api|
|
||||
|
@ -1340,13 +1294,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_nothing_raised { set.recognize(request) }
|
||||
assert_equal("api/products", request.path_parameters[:controller])
|
||||
assert_equal("index", request.path_parameters[:action])
|
||||
ensure
|
||||
Object.send(:remove_const, :Api)
|
||||
end
|
||||
|
||||
def test_namespace_with_path_prefix
|
||||
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
|
||||
|
||||
set.draw do |map|
|
||||
map.namespace 'api', :path_prefix => 'prefix' do |api|
|
||||
api.route 'inventory', :controller => "products", :action => 'inventory'
|
||||
|
@ -1358,13 +1308,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_nothing_raised { set.recognize(request) }
|
||||
assert_equal("api/products", request.path_parameters[:controller])
|
||||
assert_equal("inventory", request.path_parameters[:action])
|
||||
ensure
|
||||
Object.send(:remove_const, :Api)
|
||||
end
|
||||
|
||||
def test_namespace_with_blank_path_prefix
|
||||
Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
|
||||
|
||||
set.draw do |map|
|
||||
map.namespace 'api', :path_prefix => '' do |api|
|
||||
api.route 'inventory', :controller => "products", :action => 'inventory'
|
||||
|
@ -1376,8 +1322,6 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_nothing_raised { set.recognize(request) }
|
||||
assert_equal("api/products", request.path_parameters[:controller])
|
||||
assert_equal("inventory", request.path_parameters[:action])
|
||||
ensure
|
||||
Object.send(:remove_const, :Api)
|
||||
end
|
||||
|
||||
def test_generate_changes_controller_module
|
||||
|
|
|
@ -111,13 +111,6 @@ class VerificationTest < ActionController::TestCase
|
|||
|
||||
tests TestController
|
||||
|
||||
setup do
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.foo '/foo', :controller => 'test', :action => 'foo'
|
||||
map.connect ":controller/:action/:id"
|
||||
end
|
||||
end
|
||||
|
||||
def test_using_symbol_back_with_no_referrer
|
||||
assert_raise(ActionController::RedirectBackError) { get :guarded_with_back }
|
||||
end
|
||||
|
@ -130,8 +123,14 @@ class VerificationTest < ActionController::TestCase
|
|||
|
||||
def test_no_deprecation_warning_for_named_route
|
||||
assert_not_deprecated do
|
||||
get :guarded_one_for_named_route_test, :two => "not one"
|
||||
assert_redirected_to '/foo'
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
map.foo '/foo', :controller => 'test', :action => 'foo'
|
||||
map.connect ":controller/:action/:id"
|
||||
end
|
||||
get :guarded_one_for_named_route_test, :two => "not one"
|
||||
assert_redirected_to '/foo'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -259,7 +259,6 @@ class WebServiceTest < ActionController::IntegrationTest
|
|||
c.connect "/", :action => "assign_parameters"
|
||||
end
|
||||
end
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -59,7 +59,6 @@ class JsonParamsParsingTest < ActionController::IntegrationTest
|
|||
set.draw do |map|
|
||||
map.connect ':action', :controller => "json_params_parsing_test/test"
|
||||
end
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -153,7 +153,6 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest
|
|||
set.draw do |map|
|
||||
map.connect ':action', :controller => "multipart_params_parsing_test/test"
|
||||
end
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -111,7 +111,6 @@ class QueryStringParsingTest < ActionController::IntegrationTest
|
|||
set.draw do |map|
|
||||
map.connect ':action', :controller => "query_string_parsing_test/test"
|
||||
end
|
||||
reset!
|
||||
|
||||
get "/parse", actual
|
||||
assert_response :ok
|
||||
|
|
|
@ -132,7 +132,6 @@ class UrlEncodedParamsParsingTest < ActionController::IntegrationTest
|
|||
set.draw do |map|
|
||||
map.connect ':action', :controller => "url_encoded_params_parsing_test/test"
|
||||
end
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -86,7 +86,6 @@ class XmlParamsParsingTest < ActionController::IntegrationTest
|
|||
set.draw do |map|
|
||||
map.connect ':action', :controller => "xml_params_parsing_test/test"
|
||||
end
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -223,7 +223,6 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
end
|
||||
options = {:key => SessionKey, :secret => SessionSecret}.merge(options)
|
||||
@app = ActionDispatch::Session::CookieStore.new(set, options)
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -115,7 +115,6 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
|||
map.connect "/:action", :controller => "mem_cache_store_test/test"
|
||||
end
|
||||
@app = ActionDispatch::Session::MemCacheStore.new(set, :key => '_session_id')
|
||||
reset!
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
require 'abstract_unit'
|
||||
|
||||
class StringCoercionTest < ActiveSupport::TestCase
|
||||
test "body responds to each" do
|
||||
original_body = []
|
||||
body = ActionDispatch::StringCoercion::UglyBody.new(original_body)
|
||||
|
||||
assert original_body.respond_to?(:each)
|
||||
assert body.respond_to?(:each)
|
||||
end
|
||||
|
||||
test "body responds to to_path" do
|
||||
original_body = []
|
||||
def original_body.to_path; end
|
||||
body = ActionDispatch::StringCoercion::UglyBody.new(original_body)
|
||||
|
||||
assert original_body.respond_to?(:to_path)
|
||||
assert body.respond_to?(:to_path)
|
||||
end
|
||||
|
||||
test "body does not responds to to_path" do
|
||||
original_body = []
|
||||
body = ActionDispatch::StringCoercion::UglyBody.new(original_body)
|
||||
|
||||
assert !original_body.respond_to?(:to_path)
|
||||
assert !body.respond_to?(:to_path)
|
||||
end
|
||||
|
||||
test "calls to_s on body parts" do
|
||||
app = lambda { |env|
|
||||
[200, {'Content-Type' => 'html'}, [1, 2, 3]]
|
||||
}
|
||||
app = ActionDispatch::StringCoercion.new(app)
|
||||
parts = []
|
||||
status, headers, body = app.call({})
|
||||
body.each { |part| parts << part }
|
||||
|
||||
assert_equal %w( 1 2 3 ), parts
|
||||
end
|
||||
end
|
|
@ -1,22 +1,32 @@
|
|||
class << Object; alias_method :const_available?, :const_defined?; end
|
||||
|
||||
class ContentController < ActionController::Base
|
||||
end
|
||||
class NotAController
|
||||
end
|
||||
class ContentController < ActionController::Base; end
|
||||
class NotAController; end
|
||||
|
||||
module Admin
|
||||
class << self; alias_method :const_available?, :const_defined?; end
|
||||
class UserController < ActionController::Base; end
|
||||
class NewsFeedController < ActionController::Base; end
|
||||
end
|
||||
class ElsewhereController < ActionController::Base; end
|
||||
|
||||
module Api
|
||||
class ProductsController < ActionController::Base; end
|
||||
end
|
||||
|
||||
# TODO: Reduce the number of test controllers we use
|
||||
class AddressesController < ActionController::Base; end
|
||||
class SessionsController < ActionController::Base; end
|
||||
class FooController < ActionController::Base; end
|
||||
class CController < ActionController::Base; end
|
||||
class HiController < ActionController::Base; end
|
||||
class ArticlesController < ActionController::Base; end
|
||||
class BarController < ActionController::Base; end
|
||||
class BooksController < ActionController::Base; end
|
||||
class BraveController < ActionController::Base; end
|
||||
class CController < ActionController::Base; end
|
||||
class ElsewhereController < ActionController::Base; end
|
||||
class FooController < ActionController::Base; end
|
||||
class HiController < ActionController::Base; end
|
||||
class ImageController < ActionController::Base; end
|
||||
class PeopleController < ActionController::Base; end
|
||||
class SessionsController < ActionController::Base; end
|
||||
class SubpathBooksController < ActionController::Base; end
|
||||
class WeblogController < ActionController::Base; end
|
||||
|
||||
# For speed test
|
||||
|
@ -34,8 +44,3 @@ class ChannelsController < SpeedController; end
|
|||
class ChannelVideosController < SpeedController; end
|
||||
class LostPasswordsController < SpeedController; end
|
||||
class PagesController < SpeedController; end
|
||||
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.route_one 'route_one', :controller => 'elsewhere', :action => 'flash_me'
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
|
|
|
@ -51,3 +51,99 @@ module Quiz
|
|||
end
|
||||
end
|
||||
|
||||
class Post < Struct.new(:title, :author_name, :body, :secret, :written_on, :cost)
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
alias_method :secret?, :secret
|
||||
|
||||
def new_record=(boolean)
|
||||
@new_record = boolean
|
||||
end
|
||||
|
||||
def new_record?
|
||||
@new_record
|
||||
end
|
||||
|
||||
attr_accessor :author
|
||||
def author_attributes=(attributes); end
|
||||
|
||||
attr_accessor :comments
|
||||
def comments_attributes=(attributes); end
|
||||
|
||||
attr_accessor :tags
|
||||
def tags_attributes=(attributes); end
|
||||
end
|
||||
|
||||
class Comment
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :post_id
|
||||
def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
|
||||
def save; @id = 1; @post_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def name
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
|
||||
attr_accessor :relevances
|
||||
def relevances_attributes=(attributes); end
|
||||
|
||||
end
|
||||
|
||||
class Tag
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :post_id
|
||||
def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
|
||||
def save; @id = 1; @post_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def value
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
|
||||
attr_accessor :relevances
|
||||
def relevances_attributes=(attributes); end
|
||||
|
||||
end
|
||||
|
||||
class CommentRelevance
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :comment_id
|
||||
def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end
|
||||
def save; @id = 1; @comment_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def value
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
end
|
||||
|
||||
class TagRelevance
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :tag_id
|
||||
def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end
|
||||
def save; @id = 1; @tag_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def value
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
end
|
||||
|
||||
class Author < Comment
|
||||
attr_accessor :post
|
||||
def post_attributes=(attributes); end
|
||||
end
|
||||
|
|
|
@ -32,7 +32,7 @@ class LinkToRemoteTest < AjaxTestCase
|
|||
end
|
||||
|
||||
test "with no update" do
|
||||
assert_html link, %w(href="/blog/destroy/3" Delete\ this\ post data-remote="true")
|
||||
assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true")
|
||||
end
|
||||
|
||||
test "basic" do
|
||||
|
@ -46,7 +46,7 @@ class LinkToRemoteTest < AjaxTestCase
|
|||
end
|
||||
|
||||
test "with :html options" do
|
||||
expected = %{<a href="/blog/destroy/3" data-custom="me" data-update-success="#posts">Delete this post</a>}
|
||||
expected = %{<a href="/blog/destroy/4" data-custom="me" data-remote="true" data-update-success="#posts">Delete this post</a>}
|
||||
assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"})
|
||||
end
|
||||
|
||||
|
@ -74,7 +74,7 @@ class LinkToRemoteTest < AjaxTestCase
|
|||
end
|
||||
|
||||
test "basic link_to_remote with :url =>" do
|
||||
expected = %{<a href="/blog/destroy/3" data-update-success="#posts">Delete this post</a>}
|
||||
expected = %{<a href="/blog/destroy/3" data-remote="true" data-update-success="#posts">Delete this post</a>}
|
||||
assert_equal expected,
|
||||
link_to_remote("Delete this post", :url => "/blog/destroy/3", :update => "#posts")
|
||||
end
|
||||
|
@ -93,7 +93,7 @@ class ButtonToRemoteTest < AjaxTestCase
|
|||
def url_for(*)
|
||||
"/whatnot"
|
||||
end
|
||||
|
||||
|
||||
class StandardTest < ButtonToRemoteTest
|
||||
test "basic" do
|
||||
button = button({:url => {:action => "whatnot"}}, {:class => "fine"})
|
||||
|
@ -103,13 +103,12 @@ class ButtonToRemoteTest < AjaxTestCase
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class LegacyButtonToRemoteTest < ButtonToRemoteTest
|
||||
include ActionView::Helpers::AjaxHelper::Rails2Compatibility
|
||||
|
||||
|
||||
assert_callbacks_work do |callback|
|
||||
button(callback => "undoRequestCompleted(request)")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -231,6 +231,11 @@ class AssetTagHelperTest < ActionView::TestCase
|
|||
assert_dom_equal(%(<script src="/javascripts/prototype.js?1" type="text/javascript"></script>\n<script src="/javascripts/effects.js?1" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js?1" type="text/javascript"></script>\n<script src="/javascripts/controls.js?1" type="text/javascript"></script>\n<script src="/javascripts/application.js?1" type="text/javascript"></script>), javascript_include_tag(:defaults))
|
||||
end
|
||||
|
||||
def test_javascript_include_tag_is_html_safe
|
||||
assert javascript_include_tag(:defaults).html_safe?
|
||||
assert javascript_include_tag("prototype").html_safe?
|
||||
end
|
||||
|
||||
def test_register_javascript_include_default
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'bank'
|
||||
|
@ -285,6 +290,13 @@ class AssetTagHelperTest < ActionView::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_stylesheet_link_tag_is_html_safe
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
||||
assert stylesheet_link_tag('dir/file').html_safe?
|
||||
assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe?
|
||||
assert stylesheet_tag('dir/file', {}).html_safe?
|
||||
end
|
||||
|
||||
def test_custom_stylesheet_expansions
|
||||
ENV["RAILS_ASSET_ID"] = ''
|
||||
ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :robbery => ["bank", "robber"]
|
||||
|
|
|
@ -15,6 +15,18 @@ class ErbUtilTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_html_escape_is_html_safe
|
||||
escaped = h("<p>")
|
||||
assert_equal "<p>", escaped
|
||||
assert escaped.html_safe?
|
||||
end
|
||||
|
||||
def test_html_escape_passes_html_escpe_unmodified
|
||||
escaped = h("<p>".html_safe!)
|
||||
assert_equal "<p>", escaped
|
||||
assert escaped.html_safe?
|
||||
end
|
||||
|
||||
def test_rest_in_ascii
|
||||
(0..127).to_a.map {|int| int.chr }.each do |chr|
|
||||
next if %w(& " < >).include?(chr)
|
||||
|
|
|
@ -1,103 +1,5 @@
|
|||
require 'abstract_unit'
|
||||
|
||||
silence_warnings do
|
||||
class Post < Struct.new(:title, :author_name, :body, :secret, :written_on, :cost)
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
alias_method :secret?, :secret
|
||||
|
||||
def new_record=(boolean)
|
||||
@new_record = boolean
|
||||
end
|
||||
|
||||
def new_record?
|
||||
@new_record
|
||||
end
|
||||
|
||||
attr_accessor :author
|
||||
def author_attributes=(attributes); end
|
||||
|
||||
attr_accessor :comments
|
||||
def comments_attributes=(attributes); end
|
||||
|
||||
attr_accessor :tags
|
||||
def tags_attributes=(attributes); end
|
||||
end
|
||||
|
||||
class Comment
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :post_id
|
||||
def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
|
||||
def save; @id = 1; @post_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def name
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
|
||||
attr_accessor :relevances
|
||||
def relevances_attributes=(attributes); end
|
||||
|
||||
end
|
||||
|
||||
class Tag
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :post_id
|
||||
def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
|
||||
def save; @id = 1; @post_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def value
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
|
||||
attr_accessor :relevances
|
||||
def relevances_attributes=(attributes); end
|
||||
|
||||
end
|
||||
|
||||
class CommentRelevance
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :comment_id
|
||||
def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end
|
||||
def save; @id = 1; @comment_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def value
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
end
|
||||
|
||||
class TagRelevance
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :id
|
||||
attr_reader :tag_id
|
||||
def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end
|
||||
def save; @id = 1; @tag_id = 1 end
|
||||
def new_record?; @id.nil? end
|
||||
def to_param; @id; end
|
||||
def value
|
||||
@id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
|
||||
end
|
||||
end
|
||||
|
||||
class Author < Comment
|
||||
attr_accessor :post
|
||||
def post_attributes=(attributes); end
|
||||
end
|
||||
end
|
||||
require 'controller/fake_models'
|
||||
|
||||
class FormHelperTest < ActionView::TestCase
|
||||
tests ActionView::Helpers::FormHelper
|
||||
|
@ -1072,7 +974,7 @@ class FormHelperTest < ActionView::TestCase
|
|||
(field_helpers - %w(hidden_field)).each do |selector|
|
||||
src = <<-END_SRC
|
||||
def #{selector}(field, *args, &proc)
|
||||
"<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>"
|
||||
("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe!
|
||||
end
|
||||
END_SRC
|
||||
class_eval src, __FILE__, __LINE__
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
require 'abstract_unit'
|
||||
require 'testing_sandbox'
|
||||
|
||||
class RawOutputHelperTest < ActionView::TestCase
|
||||
tests ActionView::Helpers::RawOutputHelper
|
||||
include TestingSandbox
|
||||
|
||||
def setup
|
||||
@string = "hello"
|
||||
end
|
||||
|
||||
test "raw returns the safe string" do
|
||||
result = raw(@string)
|
||||
assert_equal @string, result
|
||||
assert result.html_safe?
|
||||
end
|
||||
|
||||
test "raw handles nil values correctly" do
|
||||
assert_equal "", raw(nil)
|
||||
end
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
require 'abstract_unit'
|
||||
require 'controller/fake_models'
|
||||
|
||||
class Post
|
||||
extend ActiveModel::Naming
|
||||
|
@ -26,7 +27,7 @@ class RecordTagHelperTest < ActionView::TestCase
|
|||
end
|
||||
|
||||
def test_content_tag_for_prefix
|
||||
expected = %(<ul class="post" id="archived_post_45"></ul>)
|
||||
expected = %(<ul class="archived_post" id="archived_post_45"></ul>)
|
||||
actual = content_tag_for(:ul, @post, :archived) { }
|
||||
assert_dom_equal expected, actual
|
||||
end
|
||||
|
|
|
@ -229,7 +229,7 @@ module RenderTestCases
|
|||
end
|
||||
|
||||
def test_render_with_nested_layout
|
||||
assert_equal %(<title>title</title>\n<div id="column">column</div>\n<div id="content">content</div>\n),
|
||||
assert_equal %(<title>title</title>\n\n\n<div id="column">column</div>\n<div id="content">content</div>\n),
|
||||
@view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield")
|
||||
end
|
||||
|
||||
|
|
|
@ -39,7 +39,16 @@ class SanitizeHelperTest < ActionView::TestCase
|
|||
%{This is a test.\n\n\nIt no longer contains any HTML.\n}, strip_tags(
|
||||
%{<title>This is <b>a <a href="" target="_blank">test</a></b>.</title>\n\n<!-- it has a comment -->\n\n<p>It no <b>longer <strong>contains <em>any <strike>HTML</strike></em>.</strong></b></p>\n}))
|
||||
assert_equal "This has a here.", strip_tags("This has a <!-- comment --> here.")
|
||||
[nil, '', ' '].each { |blank| assert_equal blank, strip_tags(blank) }
|
||||
[nil, '', ' '].each do |blank|
|
||||
stripped = strip_tags(blank)
|
||||
assert_equal blank, stripped
|
||||
assert stripped.html_safe? unless blank.nil?
|
||||
end
|
||||
assert strip_tags("<script>").html_safe?
|
||||
end
|
||||
|
||||
def test_sanitize_is_marked_safe
|
||||
assert sanitize("<html><script></script></html>").html_safe?
|
||||
end
|
||||
|
||||
def assert_sanitized(text, expected = nil)
|
||||
|
|
|
@ -34,6 +34,7 @@ class TagHelperTest < ActionView::TestCase
|
|||
|
||||
def test_content_tag
|
||||
assert_equal "<a href=\"create\">Create</a>", content_tag("a", "Create", "href" => "create")
|
||||
assert content_tag("a", "Create", "href" => "create").html_safe?
|
||||
assert_equal content_tag("a", "Create", "href" => "create"),
|
||||
content_tag("a", "Create", :href => "create")
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'abstract_unit'
|
||||
require 'controller/fake_controllers'
|
||||
|
||||
module ActionView
|
||||
class TestCase
|
||||
|
@ -154,7 +155,7 @@ module ActionView
|
|||
class AssertionsTest < ActionView::TestCase
|
||||
def render_from_helper
|
||||
form_tag('/foo') do
|
||||
concat render(:text => '<ul><li>foo</li></ul>')
|
||||
concat render(:text => '<ul><li>foo</li></ul>').html_safe!
|
||||
end
|
||||
end
|
||||
helper_method :render_from_helper
|
|
@ -19,32 +19,41 @@ module PeopleHelper
|
|||
end
|
||||
|
||||
class PeopleHelperTest < ActionView::TestCase
|
||||
def setup
|
||||
super
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.people 'people', :controller => 'people', :action => 'index'
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
end
|
||||
|
||||
def test_title
|
||||
assert_equal "<h1>Ruby on Rails</h1>", title("Ruby on Rails")
|
||||
end
|
||||
|
||||
def test_homepage_path
|
||||
assert_equal "/people", homepage_path
|
||||
with_test_route_set do
|
||||
assert_equal "/people", homepage_path
|
||||
end
|
||||
end
|
||||
|
||||
def test_homepage_url
|
||||
assert_equal "http://test.host/people", homepage_url
|
||||
with_test_route_set do
|
||||
assert_equal "http://test.host/people", homepage_url
|
||||
end
|
||||
end
|
||||
|
||||
def test_link_to_person
|
||||
person = mock(:name => "David")
|
||||
person.class.extend ActiveModel::Naming
|
||||
expects(:mocha_mock_path).with(person).returns("/people/1")
|
||||
assert_equal '<a href="/people/1">David</a>', link_to_person(person)
|
||||
with_test_route_set do
|
||||
person = mock(:name => "David")
|
||||
person.class.extend ActiveModel::Naming
|
||||
expects(:mocha_mock_path).with(person).returns("/people/1")
|
||||
assert_equal '<a href="/people/1">David</a>', link_to_person(person)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def with_test_route_set
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
map.people 'people', :controller => 'people', :action => 'index'
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class CrazyHelperTest < ActionView::TestCase
|
||||
|
|
|
@ -139,7 +139,7 @@ class UrlHelperTest < ActionView::TestCase
|
|||
end
|
||||
|
||||
def test_link_tag_with_img
|
||||
assert_dom_equal "<a href=\"http://www.example.com\"><img src='/favicon.jpg' /></a>", link_to("<img src='/favicon.jpg' />", "http://www.example.com")
|
||||
assert_dom_equal "<a href=\"http://www.example.com\"><img src='/favicon.jpg' alt=\"Favicon\" /></a>", link_to(image_tag("/favicon.jpg"), "http://www.example.com")
|
||||
end
|
||||
|
||||
def test_link_with_nil_html_options
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib')
|
||||
|
||||
require 'test/unit'
|
||||
require 'rbconfig'
|
||||
require 'active_support/core_ext/kernel/reporting'
|
||||
|
||||
class TestIsolated < Test::Unit::TestCase
|
||||
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
|
||||
|
||||
Dir["#{File.dirname(__FILE__)}/{abstract,controller,dispatch,template}/**/*_test.rb"].each do |file|
|
||||
define_method("test #{file}") do
|
||||
command = "#{ruby} -Ilib:test #{file}"
|
||||
silence_stderr { `#{command}` }
|
||||
assert_equal 0, $?.to_i, command
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
require 'abstract_unit'
|
||||
|
||||
class SafeBufferTest < ActionView::TestCase
|
||||
def setup
|
||||
@buffer = ActionView::SafeBuffer.new
|
||||
end
|
||||
|
||||
test "Should look like a string" do
|
||||
assert @buffer.is_a?(String)
|
||||
assert_equal "", @buffer
|
||||
end
|
||||
|
||||
test "Should escape a raw string which is passed to them" do
|
||||
@buffer << "<script>"
|
||||
assert_equal "<script>", @buffer
|
||||
end
|
||||
|
||||
test "Should NOT escape a safe value passed to it" do
|
||||
@buffer << "<script>".html_safe!
|
||||
assert_equal "<script>", @buffer
|
||||
end
|
||||
|
||||
test "Should not mess with an innocuous string" do
|
||||
@buffer << "Hello"
|
||||
assert_equal "Hello", @buffer
|
||||
end
|
||||
|
||||
test "Should not mess with a previously escape test" do
|
||||
@buffer << CGI.escapeHTML("<script>")
|
||||
assert_equal "<script>", @buffer
|
||||
end
|
||||
|
||||
test "Should be considered safe" do
|
||||
assert @buffer.html_safe?
|
||||
end
|
||||
|
||||
test "Should return a safe buffer when calling to_s" do
|
||||
new_buffer = @buffer.to_s
|
||||
assert_equal ActionView::SafeBuffer, new_buffer.class
|
||||
end
|
||||
end
|
|
@ -1,3 +1,6 @@
|
|||
require 'active_support/core_ext/hash/keys'
|
||||
require 'active_support/core_ext/class/inheritable_attributes'
|
||||
|
||||
module ActiveModel
|
||||
class MissingAttributeError < NoMethodError
|
||||
end
|
||||
|
@ -162,6 +165,7 @@ module ActiveModel
|
|||
end
|
||||
end
|
||||
end
|
||||
@attribute_methods_generated = true
|
||||
end
|
||||
|
||||
def undefine_attribute_methods
|
||||
|
@ -173,7 +177,6 @@ module ActiveModel
|
|||
|
||||
def generated_attribute_methods #:nodoc:
|
||||
@generated_attribute_methods ||= begin
|
||||
@attribute_methods_generated = true
|
||||
mod = Module.new
|
||||
include mod
|
||||
mod
|
||||
|
@ -219,7 +222,7 @@ module ActiveModel
|
|||
end
|
||||
|
||||
def attribute_method_matchers #:nodoc:
|
||||
@@attribute_method_matchers ||= []
|
||||
read_inheritable_attribute(:attribute_method_matchers) || write_inheritable_attribute(:attribute_method_matchers, [])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# You can test whether an object is compliant with the ActiveModel API by
|
||||
# calling ActiveModel::Lint.test(object). It will emit a Test::Unit
|
||||
# output that tells you whether your object is fully compliant, or if not,
|
||||
# including ActiveModel::Lint::Tests in your TestCase. It will included
|
||||
# tests that tell you whether your object is fully compliant, or if not,
|
||||
# which aspects of the API are not implemented.
|
||||
#
|
||||
# These tests do not attempt to determine the semantic correctness of the
|
||||
|
@ -12,36 +12,15 @@
|
|||
# call to to_model. It is perfectly fine for to_model to return self.
|
||||
module ActiveModel
|
||||
module Lint
|
||||
def self.test(object, verbosity = 2, output = STDOUT)
|
||||
require "test/unit"
|
||||
require "test/unit/ui/console/testrunner"
|
||||
|
||||
test_class = Class.new(::Test::Unit::TestCase) do
|
||||
include Test
|
||||
|
||||
define_method(:setup) do
|
||||
assert object.respond_to?(:to_model), "The object should respond_to :to_model"
|
||||
@object = object.to_model
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
::Test::Unit::UI::Console::TestRunner.new(test_class, verbosity, output).start
|
||||
end
|
||||
|
||||
module Test
|
||||
def assert_boolean(name, result)
|
||||
assert result == true || result == false, "#{name} should be a boolean"
|
||||
end
|
||||
|
||||
module Tests
|
||||
# valid?
|
||||
# ------
|
||||
#
|
||||
# Returns a boolean that specifies whether the object is in a valid or invalid
|
||||
# state.
|
||||
def test_valid?
|
||||
assert @object.respond_to?(:valid?), "The model should respond to valid?"
|
||||
assert_boolean "valid?", @object.valid?
|
||||
assert model.respond_to?(:valid?), "The model should respond to valid?"
|
||||
assert_boolean model.valid?, "valid?"
|
||||
end
|
||||
|
||||
# new_record?
|
||||
|
@ -53,13 +32,13 @@ module ActiveModel
|
|||
# collection. If it is persisted, a form for the object will put PUTed to the
|
||||
# URL for the object.
|
||||
def test_new_record?
|
||||
assert @object.respond_to?(:new_record?), "The model should respond to new_record?"
|
||||
assert_boolean "new_record?", @object.new_record?
|
||||
assert model.respond_to?(:new_record?), "The model should respond to new_record?"
|
||||
assert_boolean model.new_record?, "new_record?"
|
||||
end
|
||||
|
||||
def test_destroyed?
|
||||
assert @object.respond_to?(:destroyed?), "The model should respond to destroyed?"
|
||||
assert_boolean "destroyed?", @object.destroyed?
|
||||
assert model.respond_to?(:destroyed?), "The model should respond to destroyed?"
|
||||
assert_boolean model.destroyed?, "destroyed?"
|
||||
end
|
||||
|
||||
# errors
|
||||
|
@ -67,29 +46,32 @@ module ActiveModel
|
|||
#
|
||||
# Returns an object that has :[] and :full_messages defined on it. See below
|
||||
# for more details.
|
||||
def setup
|
||||
assert @object.respond_to?(:errors), "The model should respond to errors"
|
||||
@errors = @object.errors
|
||||
|
||||
# Returns an Array of Strings that are the errors for the attribute in
|
||||
# question. If localization is used, the Strings should be localized
|
||||
# for the current locale. If no error is present, this method should
|
||||
# return an empty Array.
|
||||
def test_errors_aref
|
||||
assert model.respond_to?(:errors), "The model should respond to errors"
|
||||
assert model.errors[:hello].is_a?(Array), "errors#[] should return an Array"
|
||||
end
|
||||
|
||||
# This module tests the #errors object
|
||||
module Errors
|
||||
# Returns an Array of Strings that are the errors for the attribute in
|
||||
# question. If localization is used, the Strings should be localized
|
||||
# for the current locale. If no error is present, this method should
|
||||
# return an empty Array.
|
||||
def test_errors_aref
|
||||
assert @errors[:hello].is_a?(Array), "errors#[] should return an Array"
|
||||
end
|
||||
|
||||
# Returns an Array of all error messages for the object. Each message
|
||||
# should contain information about the field, if applicable.
|
||||
def test_errors_full_messages
|
||||
assert @errors.full_messages.is_a?(Array), "errors#full_messages should return an Array"
|
||||
end
|
||||
# Returns an Array of all error messages for the object. Each message
|
||||
# should contain information about the field, if applicable.
|
||||
def test_errors_full_messages
|
||||
assert model.respond_to?(:errors), "The model should respond to errors"
|
||||
assert model.errors.full_messages.is_a?(Array), "errors#full_messages should return an Array"
|
||||
end
|
||||
|
||||
include Errors
|
||||
private
|
||||
def model
|
||||
assert @model.respond_to?(:to_model), "The object should respond_to to_model"
|
||||
@model.to_model
|
||||
end
|
||||
|
||||
def assert_boolean(result, name)
|
||||
assert result == true || result == false, "#{name} should be a boolean"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
require 'cases/helper'
|
||||
|
||||
class ModelWithAttributes
|
||||
include ActiveModel::AttributeMethods
|
||||
|
||||
attribute_method_suffix ''
|
||||
|
||||
def attributes
|
||||
{ :foo => 'value of foo' }
|
||||
end
|
||||
|
||||
private
|
||||
def attribute(name)
|
||||
attributes[name.to_sym]
|
||||
end
|
||||
end
|
||||
|
||||
class ModelWithAttributes2
|
||||
include ActiveModel::AttributeMethods
|
||||
|
||||
attribute_method_suffix '_test'
|
||||
end
|
||||
|
||||
class AttributeMethodsTest < ActiveModel::TestCase
|
||||
test 'unrelated classes should not share attribute method matchers' do
|
||||
assert_not_equal ModelWithAttributes.send(:attribute_method_matchers),
|
||||
ModelWithAttributes2.send(:attribute_method_matchers)
|
||||
end
|
||||
|
||||
test '#define_attribute_methods generates attribute methods' do
|
||||
ModelWithAttributes.define_attribute_methods([:foo])
|
||||
|
||||
assert ModelWithAttributes.attribute_methods_generated?
|
||||
assert ModelWithAttributes.new.respond_to?(:foo)
|
||||
assert_equal "value of foo", ModelWithAttributes.new.foo
|
||||
end
|
||||
|
||||
test '#undefine_attribute_methods removes attribute methods' do
|
||||
ModelWithAttributes.define_attribute_methods([:foo])
|
||||
ModelWithAttributes.undefine_attribute_methods
|
||||
|
||||
assert !ModelWithAttributes.attribute_methods_generated?
|
||||
assert !ModelWithAttributes.new.respond_to?(:foo)
|
||||
assert_raises(NoMethodError) { ModelWithAttributes.new.foo }
|
||||
end
|
||||
end
|
|
@ -1,15 +1,17 @@
|
|||
require "cases/helper"
|
||||
|
||||
class TestLint < ActiveModel::TestCase
|
||||
class CompliantObject
|
||||
class LintTest < ActiveModel::TestCase
|
||||
include ActiveModel::Lint::Tests
|
||||
|
||||
class CompliantModel
|
||||
def to_model
|
||||
self
|
||||
end
|
||||
|
||||
|
||||
def valid?() true end
|
||||
def new_record?() true end
|
||||
def destroyed?() true end
|
||||
|
||||
|
||||
def errors
|
||||
obj = Object.new
|
||||
def obj.[](key) [] end
|
||||
|
@ -17,34 +19,8 @@ class TestLint < ActiveModel::TestCase
|
|||
obj
|
||||
end
|
||||
end
|
||||
|
||||
def assert_output(object, failures, errors, *test_names)
|
||||
ActiveModel::Lint.test(object, 3, output = StringIO.new)
|
||||
regex = %r{#{failures} failures, #{errors} errors}
|
||||
assert_match regex, output.string
|
||||
|
||||
test_names.each do |test_name|
|
||||
assert_match test_name, output.string
|
||||
end
|
||||
end
|
||||
|
||||
def test_valid
|
||||
assert_output(CompliantObject.new, 0, 0, /test_valid/)
|
||||
end
|
||||
|
||||
def test_new_record
|
||||
assert_output(CompliantObject.new, 0, 0, /test_new_record?/)
|
||||
end
|
||||
|
||||
def test_destroyed
|
||||
assert_output(CompliantObject.new, 0, 0, /test_destroyed/)
|
||||
end
|
||||
|
||||
def test_errors_aref
|
||||
assert_output(CompliantObject.new, 0, 0, /test_errors_aref/)
|
||||
end
|
||||
|
||||
def test_errors_full_messages
|
||||
assert_output(CompliantObject.new, 0, 0, /test_errors_aref/)
|
||||
def setup
|
||||
@model = CompliantModel.new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2427,6 +2427,29 @@ module ActiveRecord #:nodoc:
|
|||
result
|
||||
end
|
||||
|
||||
# Cloned objects have no id assigned and are treated as new records. Note that this is a "shallow" clone
|
||||
# as it copies the object's attributes only, not its associations. The extent of a "deep" clone is
|
||||
# application specific and is therefore left to the application to implement according to its need.
|
||||
def initialize_copy(other)
|
||||
# Think the assertion which fails if the after_initialize callback goes at the end of the method is wrong. The
|
||||
# deleted clone method called new which therefore called the after_initialize callback. It then went on to copy
|
||||
# over the attributes. But if it's copying the attributes afterwards then it hasn't finished initializing right?
|
||||
# For example in the test suite the topic model's after_initialize method sets the author_email_address to
|
||||
# test@test.com. I would have thought this would mean that all cloned models would have an author email address
|
||||
# of test@test.com. However the test_clone test method seems to test that this is not the case. As a result the
|
||||
# after_initialize callback has to be run *before* the copying of the atrributes rather than afterwards in order
|
||||
# for all tests to pass. This makes no sense to me.
|
||||
callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
|
||||
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
|
||||
cloned_attributes.delete(self.class.primary_key)
|
||||
@attributes = cloned_attributes
|
||||
clear_aggregation_cache
|
||||
@attributes_cache = {}
|
||||
@new_record = true
|
||||
ensure_proper_type
|
||||
self.class.send(:scope, :create).each { |att, value| self.send("#{att}=", value) } if self.class.send(:scoped?, :create)
|
||||
end
|
||||
|
||||
# Returns a String, which Action Pack uses for constructing an URL to this
|
||||
# object. The default implementation returns this record's id as a String,
|
||||
# or nil if this record's unsaved.
|
||||
|
@ -2555,19 +2578,6 @@ module ActiveRecord #:nodoc:
|
|||
freeze
|
||||
end
|
||||
|
||||
# Returns a clone of the record that hasn't been assigned an id yet and
|
||||
# is treated as a new record. Note that this is a "shallow" clone:
|
||||
# it copies the object's attributes only, not its associations.
|
||||
# The extent of a "deep" clone is application-specific and is therefore
|
||||
# left to the application to implement according to its need.
|
||||
def clone
|
||||
attrs = clone_attributes(:read_attribute_before_type_cast)
|
||||
attrs.delete(self.class.primary_key)
|
||||
record = self.class.new
|
||||
record.send :instance_variable_set, '@attributes', attrs
|
||||
record
|
||||
end
|
||||
|
||||
# Returns an instance of the specified +klass+ with the attributes of the current record. This is mostly useful in relation to
|
||||
# single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record
|
||||
# identification in Action Pack to allow, say, <tt>Client < Company</tt> to do something like render <tt>:partial => @client.becomes(Company)</tt>
|
||||
|
@ -2831,6 +2841,21 @@ module ActiveRecord #:nodoc:
|
|||
"#<#{self.class} #{attributes_as_nice_string}>"
|
||||
end
|
||||
|
||||
protected
|
||||
def clone_attributes(reader_method = :read_attribute, attributes = {})
|
||||
self.attribute_names.inject(attributes) do |attrs, name|
|
||||
attrs[name] = clone_attribute_value(reader_method, name)
|
||||
attrs
|
||||
end
|
||||
end
|
||||
|
||||
def clone_attribute_value(reader_method, attribute_name)
|
||||
value = send(reader_method, attribute_name)
|
||||
value.duplicable? ? value.clone : value
|
||||
rescue TypeError, NoMethodError
|
||||
value
|
||||
end
|
||||
|
||||
private
|
||||
def create_or_update
|
||||
raise ReadOnlyRecord if readonly?
|
||||
|
@ -3093,20 +3118,6 @@ module ActiveRecord #:nodoc:
|
|||
return string unless string.is_a?(String) && string =~ /^---/
|
||||
YAML::load(string) rescue string
|
||||
end
|
||||
|
||||
def clone_attributes(reader_method = :read_attribute, attributes = {})
|
||||
self.attribute_names.inject(attributes) do |attrs, name|
|
||||
attrs[name] = clone_attribute_value(reader_method, name)
|
||||
attrs
|
||||
end
|
||||
end
|
||||
|
||||
def clone_attribute_value(reader_method, attribute_name)
|
||||
value = send(reader_method, attribute_name)
|
||||
value.duplicable? ? value.clone : value
|
||||
rescue TypeError, NoMethodError
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
Base.class_eval do
|
||||
|
|
|
@ -3,11 +3,14 @@ require 'active_support/core_ext/object/try'
|
|||
|
||||
module ActiveRecord
|
||||
module NestedAttributes #:nodoc:
|
||||
class TooManyRecords < ActiveRecordError
|
||||
end
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_inheritable_accessor :reject_new_nested_attributes_procs, :instance_writer => false
|
||||
self.reject_new_nested_attributes_procs = {}
|
||||
class_inheritable_accessor :nested_attributes_options, :instance_writer => false
|
||||
self.nested_attributes_options = {}
|
||||
end
|
||||
|
||||
# == Nested Attributes
|
||||
|
@ -127,6 +130,22 @@ module ActiveRecord
|
|||
# member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
|
||||
# member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
|
||||
#
|
||||
# Alternatively, :reject_if also accepts a symbol for using methods:
|
||||
#
|
||||
# class Member < ActiveRecord::Base
|
||||
# has_many :posts
|
||||
# accepts_nested_attributes_for :posts, :reject_if => :new_record?
|
||||
# end
|
||||
#
|
||||
# class Member < ActiveRecord::Base
|
||||
# has_many :posts
|
||||
# accepts_nested_attributes_for :posts, :reject_if => :reject_posts
|
||||
#
|
||||
# def reject_posts(attributed)
|
||||
# attributed['title].blank?
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# If the hash contains an <tt>id</tt> key that matches an already
|
||||
# associated record, the matching record will be modified:
|
||||
#
|
||||
|
@ -179,13 +198,20 @@ module ActiveRecord
|
|||
# <tt>_destroy</tt> key and a value that evaluates to +true+
|
||||
# (eg. 1, '1', true, or 'true'). This option is off by default.
|
||||
# [:reject_if]
|
||||
# Allows you to specify a Proc that checks whether a record should be
|
||||
# built for a certain attribute hash. The hash is passed to the Proc
|
||||
# and the Proc should return either +true+ or +false+. When no Proc
|
||||
# is specified a record will be built for all attribute hashes that
|
||||
# Allows you to specify a Proc or a Symbol pointing to a method
|
||||
# that checks whether a record should be built for a certain attribute
|
||||
# hash. The hash is passed to the supplied Proc or the method
|
||||
# and it should return either +true+ or +false+. When no :reject_if
|
||||
# is specified, a record will be built for all attribute hashes that
|
||||
# do not have a <tt>_destroy</tt> value that evaluates to true.
|
||||
# Passing <tt>:all_blank</tt> instead of a Proc will create a proc
|
||||
# that will reject a record where all the attributes are blank.
|
||||
# [:limit]
|
||||
# Allows you to specify the maximum number of the associated records that
|
||||
# can be processes with the nested attributes. If the size of the
|
||||
# nested attributes array exceeds the specified limit, NestedAttributes::TooManyRecords
|
||||
# exception is raised. If omitted, any number associations can be processed.
|
||||
# Note that the :limit option is only applicable to one-to-many associations.
|
||||
#
|
||||
# Examples:
|
||||
# # creates avatar_attributes=
|
||||
|
@ -197,7 +223,7 @@ module ActiveRecord
|
|||
def accepts_nested_attributes_for(*attr_names)
|
||||
options = { :allow_destroy => false }
|
||||
options.update(attr_names.extract_options!)
|
||||
options.assert_valid_keys(:allow_destroy, :reject_if)
|
||||
options.assert_valid_keys(:allow_destroy, :reject_if, :limit)
|
||||
|
||||
attr_names.each do |association_name|
|
||||
if reflection = reflect_on_association(association_name)
|
||||
|
@ -210,10 +236,10 @@ module ActiveRecord
|
|||
|
||||
reflection.options[:autosave] = true
|
||||
|
||||
self.reject_new_nested_attributes_procs[association_name.to_sym] = if options[:reject_if] == :all_blank
|
||||
proc { |attributes| attributes.all? {|k,v| v.blank?} }
|
||||
else
|
||||
options[:reject_if]
|
||||
self.nested_attributes_options[association_name.to_sym] = options
|
||||
|
||||
if options[:reject_if] == :all_blank
|
||||
self.nested_attributes_options[association_name.to_sym][:reject_if] = proc { |attributes| attributes.all? {|k,v| v.blank?} }
|
||||
end
|
||||
|
||||
# def pirate_attributes=(attributes)
|
||||
|
@ -221,7 +247,7 @@ module ActiveRecord
|
|||
# end
|
||||
class_eval %{
|
||||
def #{association_name}_attributes=(attributes)
|
||||
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes, #{options[:allow_destroy]})
|
||||
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
|
||||
end
|
||||
}, __FILE__, __LINE__
|
||||
else
|
||||
|
@ -265,8 +291,9 @@ module ActiveRecord
|
|||
# If the given attributes include a matching <tt>:id</tt> attribute _and_ a
|
||||
# <tt>:_destroy</tt> key set to a truthy value, then the existing record
|
||||
# will be marked for destruction.
|
||||
def assign_nested_attributes_for_one_to_one_association(association_name, attributes, allow_destroy)
|
||||
attributes = attributes.stringify_keys
|
||||
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
||||
options = self.nested_attributes_options[association_name]
|
||||
attributes = attributes.with_indifferent_access
|
||||
|
||||
if attributes['id'].blank?
|
||||
unless reject_new_record?(association_name, attributes)
|
||||
|
@ -278,7 +305,7 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
elsif (existing_record = send(association_name)) && existing_record.id.to_s == attributes['id'].to_s
|
||||
assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
|
||||
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -309,24 +336,30 @@ module ActiveRecord
|
|||
# { :name => 'John' },
|
||||
# { :id => '2', :_destroy => true }
|
||||
# ])
|
||||
def assign_nested_attributes_for_collection_association(association_name, attributes_collection, allow_destroy)
|
||||
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
|
||||
options = self.nested_attributes_options[association_name]
|
||||
|
||||
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
||||
raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
|
||||
end
|
||||
|
||||
if options[:limit] && attributes_collection.size > options[:limit]
|
||||
raise TooManyRecords, "Maximum #{options[:limit]} records are allowed. Got #{attributes_collection.size} records instead."
|
||||
end
|
||||
|
||||
if attributes_collection.is_a? Hash
|
||||
attributes_collection = attributes_collection.sort_by { |index, _| index.to_i }.map { |_, attributes| attributes }
|
||||
end
|
||||
|
||||
attributes_collection.each do |attributes|
|
||||
attributes = attributes.stringify_keys
|
||||
attributes = attributes.with_indifferent_access
|
||||
|
||||
if attributes['id'].blank?
|
||||
unless reject_new_record?(association_name, attributes)
|
||||
send(association_name).build(attributes.except(*UNASSIGNABLE_KEYS))
|
||||
end
|
||||
elsif existing_record = send(association_name).detect { |record| record.id.to_s == attributes['id'].to_s }
|
||||
assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
|
||||
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -351,8 +384,18 @@ module ActiveRecord
|
|||
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
||||
# association and evaluates to +true+.
|
||||
def reject_new_record?(association_name, attributes)
|
||||
has_destroy_flag?(attributes) ||
|
||||
self.class.reject_new_nested_attributes_procs[association_name].try(:call, attributes)
|
||||
has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
|
||||
end
|
||||
|
||||
def call_reject_if(association_name, attributes)
|
||||
callback = self.nested_attributes_options[association_name][:reject_if]
|
||||
|
||||
case callback
|
||||
when Symbol
|
||||
method(callback).arity == 0 ? send(callback) : send(callback, attributes)
|
||||
when Proc
|
||||
callback.try(:call, attributes)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1352,7 +1352,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
cloned_topic.title["a"] = "c"
|
||||
assert_equal "b", topic.title["a"]
|
||||
|
||||
#test if attributes set as part of after_initialize are cloned correctly
|
||||
# test if attributes set as part of after_initialize are cloned correctly
|
||||
assert_equal topic.author_email_address, cloned_topic.author_email_address
|
||||
|
||||
# test if saved clone object differs from original
|
||||
|
|
|
@ -29,13 +29,13 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
|
|||
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
||||
end
|
||||
|
||||
def test_base_should_have_an_empty_reject_new_nested_attributes_procs
|
||||
assert_equal Hash.new, ActiveRecord::Base.reject_new_nested_attributes_procs
|
||||
def test_base_should_have_an_empty_nested_attributes_options
|
||||
assert_equal Hash.new, ActiveRecord::Base.nested_attributes_options
|
||||
end
|
||||
|
||||
def test_should_add_a_proc_to_reject_new_nested_attributes_procs
|
||||
def test_should_add_a_proc_to_nested_attributes_options
|
||||
[:parrots, :birds, :birds_with_reject_all_blank].each do |name|
|
||||
assert_instance_of Proc, Pirate.reject_new_nested_attributes_procs[name]
|
||||
assert_instance_of Proc, Pirate.nested_attributes_options[name][:reject_if]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -84,6 +84,34 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
|
|||
ship = Ship.create!(:name => 'Nights Dirty Lightning')
|
||||
ship._delete
|
||||
end
|
||||
|
||||
def test_reject_if_method_without_arguments
|
||||
Pirate.accepts_nested_attributes_for :ship, :reject_if => :new_record?
|
||||
|
||||
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
||||
pirate.ship_attributes = { :name => 'Black Pearl' }
|
||||
assert_no_difference('Ship.count') { pirate.save! }
|
||||
end
|
||||
|
||||
def test_reject_if_method_with_arguments
|
||||
Pirate.accepts_nested_attributes_for :ship, :reject_if => :reject_empty_ships_on_create
|
||||
|
||||
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
||||
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
||||
assert_no_difference('Ship.count') { pirate.save! }
|
||||
|
||||
# pirate.reject_empty_ships_on_create returns false for saved records
|
||||
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
||||
assert_difference('Ship.count') { pirate.save! }
|
||||
end
|
||||
|
||||
def test_reject_if_with_indifferent_keys
|
||||
Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:name].blank? }
|
||||
|
||||
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
||||
pirate.ship_attributes = { :name => 'Hello Pearl' }
|
||||
assert_difference('Ship.count') { pirate.save! }
|
||||
end
|
||||
end
|
||||
|
||||
class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
||||
|
@ -575,3 +603,33 @@ class TestNestedAttributesOnAHasAndBelongsToManyAssociation < ActiveRecord::Test
|
|||
|
||||
include NestedAttributesOnACollectionAssociationTests
|
||||
end
|
||||
|
||||
class TestNestedAttributesLimit < ActiveRecord::TestCase
|
||||
def setup
|
||||
Pirate.accepts_nested_attributes_for :parrots, :limit => 2
|
||||
|
||||
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
||||
end
|
||||
|
||||
def teardown
|
||||
Pirate.accepts_nested_attributes_for :parrots, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
||||
end
|
||||
|
||||
def test_limit_with_less_records
|
||||
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Big Big Love' } } }
|
||||
assert_difference('Parrot.count') { @pirate.save! }
|
||||
end
|
||||
|
||||
def test_limit_with_number_exact_records
|
||||
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' }, 'bar' => { :name => 'Blown Away' } } }
|
||||
assert_difference('Parrot.count', 2) { @pirate.save! }
|
||||
end
|
||||
|
||||
def test_limit_with_exceeding_records
|
||||
assert_raises(ActiveRecord::NestedAttributes::TooManyRecords) do
|
||||
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' },
|
||||
'bar' => { :name => 'Blown Away' },
|
||||
'car' => { :name => 'The Happening' }} }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -45,6 +45,10 @@ class Pirate < ActiveRecord::Base
|
|||
@ship_log ||= []
|
||||
end
|
||||
|
||||
def reject_empty_ships_on_create(attributes)
|
||||
attributes.delete('_reject_me_if_new').present? && new_record?
|
||||
end
|
||||
|
||||
private
|
||||
def log_before_add(record)
|
||||
log(record, "before_adding_method")
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue