diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2008-09-03 17:44:58 +0100 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2008-09-03 17:44:58 +0100 |
commit | 2933f4481f8b70b3b809fab6e818d80c2af1b919 (patch) | |
tree | c83d1308545cc82215b90ab37208cc81b4712276 /actionpack | |
parent | 36ee17d458b86c5f3f371810160e8839d318bbf1 (diff) | |
parent | 10fe6a6d8940300dd6698ec38e9c9573404e687d (diff) | |
download | rails-2933f4481f8b70b3b809fab6e818d80c2af1b919.tar.gz rails-2933f4481f8b70b3b809fab6e818d80c2af1b919.tar.bz2 rails-2933f4481f8b70b3b809fab6e818d80c2af1b919.zip |
Merge commit 'mainstream/master'
Conflicts:
actionpack/lib/action_controller/resources.rb
Diffstat (limited to 'actionpack')
48 files changed, 1533 insertions, 1465 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index f6942b43f1..88af60ed62 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,29 @@ *Edge* +* Add support for shallow nesting of routes. #838 [S. Brent Faulkner] + + Example : + + map.resources :users, :shallow => true do |user| + user.resources :posts + end + + - GET /users/1/posts (maps to PostsController#index action as usual) + named route "user_posts" is added as usual. + + - GET /posts/2 (maps to PostsController#show action as if it were not nested) + Additionally, named route "post" is added too. + +* Added button_to_remote helper. #3641 [Donald Piret, Tarmo Tänav] + +* Deprecate render_component. Please use render_component plugin from http://github.com/rails/render_component/tree/master [Pratik] + +* Routes may be restricted to lists of HTTP methods instead of a single method or :any. #407 [Brennan Dunn, Gaius Centus Novus] + map.resource :posts, :collection => { :search => [:get, :post] } + map.session 'session', :requirements => { :method => [:get, :post, :delete] } + +* Deprecated implicit local assignments when rendering partials [Josh Peek] + * Introduce current_cycle helper method to return the current value without bumping the cycle. #417 [Ken Collins] * Allow polymorphic_url helper to take url options. #880 [Tarmo Tänav] diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/assertions/selector_assertions.rb index 9114894b1d..bcbb570e4b 100644 --- a/actionpack/lib/action_controller/assertions/selector_assertions.rb +++ b/actionpack/lib/action_controller/assertions/selector_assertions.rb @@ -396,54 +396,31 @@ module ActionController # # The same, but shorter. # assert_select "ol>li", 4 def assert_select_rjs(*args, &block) - rjs_type = nil - arg = args.shift + rjs_type = args.first.is_a?(Symbol) ? args.shift : nil + id = args.first.is_a?(String) ? args.shift : nil # If the first argument is a symbol, it's the type of RJS statement we're looking # for (update, replace, insertion, etc). Otherwise, we're looking for just about # any RJS statement. - if arg.is_a?(Symbol) - rjs_type = arg - + if rjs_type if rjs_type == :insert - arg = args.shift - position = arg - insertion = "insert_#{arg}".to_sym - raise ArgumentError, "Unknown RJS insertion type #{arg}" unless RJS_STATEMENTS[insertion] + position = args.shift + insertion = "insert_#{position}".to_sym + raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion] statement = "(#{RJS_STATEMENTS[insertion]})" else raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type] statement = "(#{RJS_STATEMENTS[rjs_type]})" end - arg = args.shift else statement = "#{RJS_STATEMENTS[:any]}" end - position ||= Regexp.new(RJS_INSERTIONS.join('|')) # Next argument we're looking for is the element identifier. If missing, we pick - # any element. - if arg.is_a?(String) - id = Regexp.quote(arg) - arg = args.shift - else - id = "[^\"]*" - end - - pattern = - case rjs_type - when :chained_replace, :chained_replace_html - Regexp.new("\\$\\(\"#{id}\"\\)#{statement}\\(#{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE) - when :remove, :show, :hide, :toggle - Regexp.new("#{statement}\\(\"#{id}\"\\)") - when :replace, :replace_html - Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)") - when :insert, :insert_html - Regexp.new("Element.insert\\(\\\"#{id}\\\", \\{ #{position}: #{RJS_PATTERN_HTML} \\}\\);") - else - Regexp.union(Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)"), - Regexp.new("Element.insert\\(\\\"#{id}\\\", \\{ #{position}: #{RJS_PATTERN_HTML} \\}\\);")) - end + # any element, otherwise we replace it in the statement. + pattern = Regexp.new( + id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement + ) # Duplicate the body since the next step involves destroying it. matches = nil @@ -472,7 +449,13 @@ module ActionController matches else # RJS statement not found. - flunk args.shift || "No RJS statement that replaces or inserts HTML content." + case rjs_type + when :remove, :show, :hide, :toggle + flunk_message = "No RJS statement that #{rjs_type.to_s}s '#{id}' was rendered." + else + flunk_message = "No RJS statement that replaces or inserts HTML content." + end + flunk args.shift || flunk_message end end @@ -582,26 +565,23 @@ module ActionController protected unless const_defined?(:RJS_STATEMENTS) - RJS_STATEMENTS = { - :replace => /Element\.replace/, - :replace_html => /Element\.update/, - :chained_replace => /\.replace/, - :chained_replace_html => /\.update/, - :remove => /Element\.remove/, - :show => /Element\.show/, - :hide => /Element\.hide/, - :toggle => /Element\.toggle/ + RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\"" + RJS_ANY_ID = "\"([^\"])*\"" + RJS_STATEMENTS = { + :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)", + :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)", + :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)", + :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)" } - RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})") - RJS_PATTERN_HTML = /"((\\"|[^"])*)"/ - RJS_INSERTIONS = [:top, :bottom, :before, :after] + [:remove, :show, :hide, :toggle].each do |action| + RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)" + end + RJS_INSERTIONS = ["top", "bottom", "before", "after"] RJS_INSERTIONS.each do |insertion| - RJS_STATEMENTS["insert_#{insertion}".to_sym] = /Element.insert\(\"([^\"]*)\", \{ #{insertion.to_s.downcase}: #{RJS_PATTERN_HTML} \}\);/ + RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)" end - RJS_STATEMENTS[:insert_html] = Regexp.new(RJS_INSERTIONS.collect do |insertion| - /Element.insert\(\"([^\"]*)\", \{ #{insertion.to_s.downcase}: #{RJS_PATTERN_HTML} \}\);/ - end.join('|')) - RJS_PATTERN_EVERYTHING = Regexp.new("#{RJS_STATEMENTS[:any]}\\(\"([^\"]*)\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE) + RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)" + RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})") RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/ end @@ -615,8 +595,8 @@ module ActionController root = HTML::Node.new(nil) while true - next if body.sub!(RJS_PATTERN_EVERYTHING) do |match| - html = unescape_rjs($3) + next if body.sub!(RJS_STATEMENTS[:any]) do |match| + html = unescape_rjs(match) matches = HTML::Document.new(html).root.children.select { |n| n.tag? } root.children.concat matches "" diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 55e1d48949..670a049497 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -260,10 +260,11 @@ module ActionController #:nodoc: include StatusCodes + cattr_reader :protected_instance_variables # Controller specific instance variables which will not be accessible inside views. - @@protected_view_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller - @action_name @before_filter_chain_aborted @action_cache_path @_session @_cookies @_headers @_params - @_flash @_response) + @@protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller + @action_name @before_filter_chain_aborted @action_cache_path @_session @_cookies @_headers @_params + @_flash @_response) # Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets, # and images to a dedicated asset server away from the main web server. Example: @@ -393,16 +394,9 @@ module ActionController #:nodoc: # directive. Values should always be specified as strings. attr_internal :headers - # Holds the hash of variables that are passed on to the template class to be made available to the view. This hash - # is generated by taking a snapshot of all the instance variables in the current scope just before a template is rendered. - attr_accessor :assigns - # Returns the name of the action this controller is processing. attr_accessor :action_name - # Templates that are exempt from layouts - @@exempt_from_layout = Set.new([/\.rjs$/]) - class << self # Factory for the standard create, process loop where the controller is discarded after processing. def process(request, response) #:nodoc: @@ -520,13 +514,7 @@ module ActionController #:nodoc: protected :filter_parameters end - # Don't render layouts for templates with the given extensions. - def exempt_from_layout(*extensions) - regexps = extensions.collect do |extension| - extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ - end - @@exempt_from_layout.merge regexps - end + delegate :exempt_from_layout, :to => 'ActionView::Base' end public @@ -538,7 +526,6 @@ module ActionController #:nodoc: assign_shortcuts(request, response) initialize_current_url assign_names - forget_variables_added_to_assigns log_processing @@ -548,12 +535,16 @@ module ActionController #:nodoc: @@guard.synchronize { send(method, *arguments) } end - response.prepare! unless component_request? - response + send_response ensure process_cleanup end + def send_response + response.prepare! unless component_request? + response + end + # Returns a URL that has been rewritten according to the options hash and the defined Routes. # (For doing a complete redirect, use redirect_to). # @@ -859,7 +850,7 @@ module ActionController #:nodoc: raise DoubleRenderError, "Can only render or redirect once per action" if performed? if options.nil? - return render_for_file(default_template_name, nil, true) + return render(:file => default_template_name, :layout => true) elsif !extra_options.is_a?(Hash) raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}" else @@ -870,6 +861,9 @@ module ActionController #:nodoc: end end + response.layout = layout = pick_layout(options) + logger.info("Rendering template within #{layout}") if logger && layout + if content_type = options[:content_type] response.content_type = content_type.to_s end @@ -879,26 +873,21 @@ module ActionController #:nodoc: end if options.has_key?(:text) - render_for_text(options[:text], options[:status]) + text = layout ? @template.render(options.merge(:text => options[:text], :layout => layout)) : options[:text] + render_for_text(text, options[:status]) else if file = options[:file] - render_for_file(file, options[:status], nil, options[:locals] || {}) + render_for_file(file, options[:status], layout, options[:locals] || {}) elsif template = options[:template] - render_for_file(template, options[:status], true, options[:locals] || {}) + render_for_file(template, options[:status], layout, options[:locals] || {}) elsif inline = options[:inline] - add_variables_to_assigns - render_for_text(@template.render(options), options[:status]) + render_for_text(@template.render(options.merge(:layout => layout)), options[:status]) elsif action_name = options[:action] - template = default_template_name(action_name.to_s) - if options[:layout] && !template_exempt_from_layout?(template) - render_with_a_layout(:file => template, :status => options[:status], :layout => true) - else - render_with_no_layout(:file => template, :status => options[:status]) - end + render_for_file(default_template_name(action_name.to_s), options[:status], layout) elsif xml = options[:xml] response.content_type ||= Mime::XML @@ -912,12 +901,14 @@ module ActionController #:nodoc: elsif options[:partial] options[:partial] = default_template_name if options[:partial] == true - add_variables_to_assigns - render_for_text(@template.render(options), options[:status]) + if layout + render_for_text(@template.render(:text => @template.render(options), :layout => layout), options[:status]) + else + render_for_text(@template.render(options), options[:status]) + end elsif options[:update] - add_variables_to_assigns - @template.send! :evaluate_assigns + @template.send(:_evaluate_assigns_and_ivars) generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block) response.content_type = Mime::JS @@ -927,7 +918,7 @@ module ActionController #:nodoc: render_for_text(nil, options[:status]) else - render_for_file(default_template_name, options[:status], true) + render_for_file(default_template_name, options[:status], layout) end end end @@ -938,7 +929,6 @@ module ActionController #:nodoc: render(options, &block) ensure erase_render_results - forget_variables_added_to_assigns reset_variables_added_to_assigns end @@ -1123,10 +1113,9 @@ module ActionController #:nodoc: private - def render_for_file(template_path, status = nil, use_full_path = nil, locals = {}) #:nodoc: - add_variables_to_assigns + def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc: logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger - render_for_text(@template.render(:file => template_path, :locals => locals), status) + render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status end def render_for_text(text = nil, status = nil, append_response = false) #:nodoc: @@ -1161,7 +1150,6 @@ module ActionController #:nodoc: @_session = @_response.session @template = @_response.template - @assigns = @_response.template.assigns @_headers = @_response.headers end @@ -1225,27 +1213,10 @@ module ActionController #:nodoc: hidden_actions end - def add_variables_to_assigns - unless @variables_added - add_instance_variables_to_assigns - @variables_added = true - end - end - - def forget_variables_added_to_assigns - @variables_added = nil - end - def reset_variables_added_to_assigns @template.instance_variable_set("@assigns_added", nil) end - def add_instance_variables_to_assigns - (instance_variable_names - @@protected_view_variables).each do |var| - @assigns[var[1..-1]] = instance_variable_get(var) - end - end - def request_origin # this *needs* to be cached! # otherwise you'd get different results if calling it more than once @@ -1261,12 +1232,7 @@ module ActionController #:nodoc: end def template_exists?(template_name = default_template_name) - @template.file_exists?(template_name) - end - - def template_exempt_from_layout?(template_name = default_template_name) - template_name = @template.pick_template(template_name).to_s if @template - @@exempt_from_layout.any? { |ext| template_name =~ ext } + @template.send(:_pick_template, template_name) ? true : false rescue ActionView::MissingTemplate false end diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index b27ec486c0..7c803a9830 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -90,7 +90,7 @@ module ActionController #:nodoc: set_content_type!(controller, cache_path.extension) options = { :text => cache } options.merge!(:layout => true) if cache_layout? - controller.send!(:render, options) + controller.__send__(:render, options) false else controller.action_cache_path = cache_path @@ -121,7 +121,7 @@ module ActionController #:nodoc: end def content_for_layout(controller) - controller.response.layout && controller.response.template.instance_variable_get('@content_for_layout') + controller.response.layout && controller.response.template.instance_variable_get('@cached_content_for_layout') end end diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb index 61559e9ec7..c7992d7769 100644 --- a/actionpack/lib/action_controller/caching/sweeping.rb +++ b/actionpack/lib/action_controller/caching/sweeping.rb @@ -83,13 +83,13 @@ module ActionController #:nodoc: controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}" action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}" - send!(controller_callback_method_name) if respond_to?(controller_callback_method_name, true) - send!(action_callback_method_name) if respond_to?(action_callback_method_name, true) + __send__(controller_callback_method_name) if respond_to?(controller_callback_method_name, true) + __send__(action_callback_method_name) if respond_to?(action_callback_method_name, true) end def method_missing(method, *arguments) return if @controller.nil? - @controller.send!(method, *arguments) + @controller.__send__(method, *arguments) end end end diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index 0ca27b30db..d381af1b84 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -48,7 +48,7 @@ module ActionController #:nodoc: def initialize(cgi, session_options = {}) @cgi = cgi @session_options = session_options - @env = @cgi.send!(:env_table) + @env = @cgi.__send__(:env_table) super() end @@ -107,7 +107,7 @@ module ActionController #:nodoc: end def method_missing(method_id, *arguments) - @cgi.send!(method_id, *arguments) rescue super + @cgi.__send__(method_id, *arguments) rescue super end private @@ -164,7 +164,7 @@ end_msg begin output.write(@cgi.header(@headers)) - if @cgi.send!(:env_table)['REQUEST_METHOD'] == 'HEAD' + if @cgi.__send__(:env_table)['REQUEST_METHOD'] == 'HEAD' return elsif @body.respond_to?(:call) # Flush the output now in case the @body Proc uses diff --git a/actionpack/lib/action_controller/components.rb b/actionpack/lib/action_controller/components.rb index 8275bd380a..f446b91e7e 100644 --- a/actionpack/lib/action_controller/components.rb +++ b/actionpack/lib/action_controller/components.rb @@ -38,6 +38,7 @@ module ActionController #:nodoc: def self.included(base) #:nodoc: base.class_eval do include InstanceMethods + include ActiveSupport::Deprecation extend ClassMethods helper HelperMethods @@ -64,7 +65,7 @@ module ActionController #:nodoc: module HelperMethods def render_component(options) - @controller.send!(:render_component_as_string, options) + @controller.__send__(:render_component_as_string, options) end end @@ -82,6 +83,7 @@ module ActionController #:nodoc: render_for_text(component_response(options, true).body, response.headers["Status"]) end end + deprecate :render_component => "Please install render_component plugin from http://github.com/rails/render_component/tree/master" # Returns the component response as a string def render_component_as_string(options) #:doc: @@ -95,6 +97,7 @@ module ActionController #:nodoc: end end end + deprecate :render_component_as_string => "Please install render_component plugin from http://github.com/rails/render_component/tree/master" def flash_with_components(refresh = false) #:nodoc: if !defined?(@_flash) || refresh diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb index 1d7236f18a..9022b8b279 100644 --- a/actionpack/lib/action_controller/filters.rb +++ b/actionpack/lib/action_controller/filters.rb @@ -199,8 +199,8 @@ module ActionController #:nodoc: Proc.new do |controller, action| method.before(controller) - if controller.send!(:performed?) - controller.send!(:halt_filter_chain, method, :rendered_or_redirected) + if controller.__send__(:performed?) + controller.__send__(:halt_filter_chain, method, :rendered_or_redirected) else begin action.call @@ -223,8 +223,8 @@ module ActionController #:nodoc: def call(controller, &block) super - if controller.send!(:performed?) - controller.send!(:halt_filter_chain, method, :rendered_or_redirected) + if controller.__send__(:performed?) + controller.__send__(:halt_filter_chain, method, :rendered_or_redirected) end end end diff --git a/actionpack/lib/action_controller/helpers.rb b/actionpack/lib/action_controller/helpers.rb index ce5e8be54c..9cffa07b26 100644 --- a/actionpack/lib/action_controller/helpers.rb +++ b/actionpack/lib/action_controller/helpers.rb @@ -204,8 +204,8 @@ module ActionController #:nodoc: begin child.master_helper_module = Module.new - child.master_helper_module.send! :include, master_helper_module - child.send! :default_helper_module! + child.master_helper_module.__send__ :include, master_helper_module + child.__send__ :default_helper_module! rescue MissingSourceFile => e raise unless e.is_missing?("helpers/#{child.controller_path}_helper") end diff --git a/actionpack/lib/action_controller/http_authentication.rb b/actionpack/lib/action_controller/http_authentication.rb index 31db012ef2..2ed810db7d 100644 --- a/actionpack/lib/action_controller/http_authentication.rb +++ b/actionpack/lib/action_controller/http_authentication.rb @@ -117,7 +117,7 @@ module ActionController def authentication_request(controller, realm) controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.gsub(/"/, "")}") - controller.send! :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized + controller.__send__ :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized end end end diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index 198a22e8dc..a98c1af7f9 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -444,7 +444,7 @@ EOF reset! unless @integration_session # reset the html_document variable, but only for new get/post calls @html_document = nil unless %w(cookies assigns).include?(method) - returning @integration_session.send!(method, *args) do + returning @integration_session.__send__(method, *args) do copy_session_variables! end end @@ -469,12 +469,12 @@ EOF self.class.fixture_table_names.each do |table_name| name = table_name.tr(".", "_") next unless respond_to?(name) - extras.send!(:define_method, name) { |*args| delegate.send(name, *args) } + extras.__send__(:define_method, name) { |*args| delegate.send(name, *args) } end end # delegate add_assertion to the test case - extras.send!(:define_method, :add_assertion) { test_result.add_assertion } + extras.__send__(:define_method, :add_assertion) { test_result.add_assertion } session.extend(extras) session.delegate = self session.test_result = @_result @@ -488,7 +488,7 @@ EOF def copy_session_variables! #:nodoc: return unless @integration_session %w(controller response request).each do |var| - instance_variable_set("@#{var}", @integration_session.send!(var)) + instance_variable_set("@#{var}", @integration_session.__send__(var)) end end diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb index 8b6febe254..3631ce86af 100644 --- a/actionpack/lib/action_controller/layout.rb +++ b/actionpack/lib/action_controller/layout.rb @@ -3,11 +3,6 @@ module ActionController #:nodoc: def self.included(base) base.extend(ClassMethods) base.class_eval do - # NOTE: Can't use alias_method_chain here because +render_without_layout+ is already - # defined as a publicly exposed method - alias_method :render_with_no_layout, :render - alias_method :render, :render_with_a_layout - class << self alias_method_chain :inherited, :layout end @@ -169,17 +164,17 @@ module ActionController #:nodoc: # performance and have access to them as any normal template would. def layout(template_name, conditions = {}, auto = false) add_layout_conditions(conditions) - write_inheritable_attribute "layout", template_name - write_inheritable_attribute "auto_layout", auto + write_inheritable_attribute(:layout, template_name) + write_inheritable_attribute(:auto_layout, auto) end def layout_conditions #:nodoc: - @layout_conditions ||= read_inheritable_attribute("layout_conditions") + @layout_conditions ||= read_inheritable_attribute(:layout_conditions) end def default_layout(format) #:nodoc: - layout = read_inheritable_attribute("layout") - return layout unless read_inheritable_attribute("auto_layout") + layout = read_inheritable_attribute(:layout) + return layout unless read_inheritable_attribute(:auto_layout) @default_layout ||= {} @default_layout[format] ||= default_layout_with_format(format, layout) @default_layout[format] @@ -199,7 +194,7 @@ module ActionController #:nodoc: end def add_layout_conditions(conditions) - write_inheritable_hash "layout_conditions", normalize_conditions(conditions) + write_inheritable_hash(:layout_conditions, normalize_conditions(conditions)) end def normalize_conditions(conditions) @@ -221,10 +216,10 @@ module ActionController #:nodoc: # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard. def active_layout(passed_layout = nil) - layout = passed_layout || self.class.default_layout(response.template.template_format) + layout = passed_layout || self.class.default_layout(default_template_format) active_layout = case layout when String then layout - when Symbol then send!(layout) + when Symbol then __send__(layout) when Proc then layout.call(self) end @@ -240,51 +235,24 @@ module ActionController #:nodoc: end end - protected - def render_with_a_layout(options = nil, extra_options = {}, &block) #:nodoc: - template_with_options = options.is_a?(Hash) - - if (layout = pick_layout(template_with_options, options)) && apply_layout?(template_with_options, options) - options = options.merge :layout => false if template_with_options - logger.info("Rendering template within #{layout}") if logger - - content_for_layout = render_with_no_layout(options, extra_options, &block) - erase_render_results - add_variables_to_assigns - @template.instance_variable_set("@content_for_layout", content_for_layout) - response.layout = layout - status = template_with_options ? options[:status] : nil - render_for_text(@template.render(layout), status) - else - render_with_no_layout(options, extra_options, &block) - end - end - - private - def apply_layout?(template_with_options, options) - return false if options == :update - template_with_options ? candidate_for_layout?(options) : !template_exempt_from_layout? - end - def candidate_for_layout?(options) - (options.has_key?(:layout) && options[:layout] != false) || - options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing).compact.empty? && - !template_exempt_from_layout?(options[:template] || default_template_name(options[:action])) + options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty? && + !@template.__send__(:_exempt_from_layout?, options[:template] || default_template_name(options[:action])) end - def pick_layout(template_with_options, options) - if template_with_options - case layout = options[:layout] - when FalseClass - nil - when NilClass, TrueClass - active_layout if action_has_layout? - else - active_layout(layout) + def pick_layout(options) + if options.has_key?(:layout) + case layout = options.delete(:layout) + when FalseClass + nil + when NilClass, TrueClass + active_layout if action_has_layout? && !@template.__send__(:_exempt_from_layout?, default_template_name) + else + active_layout(layout) end else - active_layout if action_has_layout? + active_layout if action_has_layout? && candidate_for_layout?(options) end end @@ -304,7 +272,13 @@ module ActionController #:nodoc: end def layout_directory?(layout_name) - @template.file_exists?("#{File.join('layouts', layout_name)}.#{@template.template_format}") + @template.__send__(:_pick_template, "#{File.join('layouts', layout_name)}.#{@template.template_format}") ? true : false + rescue ActionView::MissingTemplate + false + end + + def default_template_format + response.template.template_format end end end diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index 30564c7bb3..cc228c4230 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -108,7 +108,7 @@ module ActionController args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options end - send!(named_route, *args) + __send__(named_route, *args) end # Returns the path component of a URL for the given record. It uses @@ -149,7 +149,7 @@ module ActionController if parent.is_a?(Symbol) || parent.is_a?(String) string << "#{parent}_" else - string << "#{RecordIdentifier.send!("singular_class_name", parent)}_" + string << "#{RecordIdentifier.__send__("singular_class_name", parent)}_" end end end @@ -157,7 +157,7 @@ module ActionController if record.is_a?(Symbol) || record.is_a?(String) route << "#{record}_" else - route << "#{RecordIdentifier.send!("#{inflection}_class_name", record)}_" + route << "#{RecordIdentifier.__send__("#{inflection}_class_name", record)}_" end action_prefix(options) + namespace + route + routing_type(options).to_s diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb index b12d50c773..83c4218af4 100644 --- a/actionpack/lib/action_controller/rescue.rb +++ b/actionpack/lib/action_controller/rescue.rb @@ -177,11 +177,8 @@ module ActionController #:nodoc: # Render detailed diagnostics for unhandled exceptions rescued from # a controller action. def rescue_action_locally(exception) - add_variables_to_assigns @template.instance_variable_set("@exception", exception) @template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub"))) - @template.send!(:assign_variables_from_controller) - @template.instance_variable_set("@contents", @template.render(:file => template_path_for_local_rescue(exception))) response.content_type = Mime::HTML diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index becf6b0b63..872b0dab3d 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -85,16 +85,24 @@ module ActionController @new_path ||= "#{path}/#{new_action}" end + def shallow_path_prefix + @shallow_path_prefix ||= "#{path_prefix unless @options[:shallow]}" + end + def member_path - @member_path ||= "#{path}/:id" + @member_path ||= "#{shallow_path_prefix}/#{path_segment}/:id" end def nesting_path_prefix - @nesting_path_prefix ||= "#{path}/:#{singular}_id" + @nesting_path_prefix ||= "#{shallow_path_prefix}/#{path_segment}/:#{singular}_id" + end + + def shallow_name_prefix + @shallow_name_prefix ||= "#{name_prefix unless @options[:shallow]}" end def nesting_name_prefix - "#{name_prefix}#{singular}_" + "#{shallow_name_prefix}#{singular}_" end def action_separator @@ -141,6 +149,8 @@ module ActionController super end + alias_method :shallow_path_prefix, :path_prefix + alias_method :shallow_name_prefix, :name_prefix alias_method :member_path, :path alias_method :nesting_path_prefix, :path end @@ -238,8 +248,9 @@ module ActionController # # The +resources+ method accepts the following options to customize the resulting routes: # * <tt>:collection</tt> - Add named routes for other actions that operate on the collection. - # Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt> - # or <tt>:any</tt> if the method does not matter. These routes map to a URL like /messages/rss, with a route of +rss_messages_url+. + # Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt>, + # an array of any of the previous, or <tt>:any</tt> if the method does not matter. + # These routes map to a URL like /messages/rss, with a route of +rss_messages_url+. # * <tt>:member</tt> - Same as <tt>:collection</tt>, but for actions that operate on a specific member. # * <tt>:new</tt> - Same as <tt>:collection</tt>, but for actions that operate on the new \resource action. # * <tt>:controller</tt> - Specify the controller name for the routes. @@ -317,7 +328,32 @@ module ActionController # comments_url(@article) # comment_url(@article, @comment) # - # If <tt>map.resources</tt> is called with multiple \resources, they all get the same options applied. + # * <tt>:shallow</tt> - If true, paths for nested resources which reference a specific member + # (ie. those with an :id parameter) will not use the parent path prefix or name prefix. + # + # The <tt>:shallow</tt> option is inherited by any nested resource(s). + # + # For example, 'users', 'posts' and 'comments' all use shallow paths with the following nested resources: + # + # map.resources :users, :shallow => true do |user| + # user.resources :posts do |post| + # post.resources :comments + # end + # end + # # --> GET /users/1/posts (maps to the PostsController#index action as usual) + # # also adds the usual named route called "user_posts" + # # --> GET /posts/2 (maps to the PostsController#show action as if it were not nested) + # # also adds the named route called "post" + # # --> GET /posts/2/comments (maps to the CommentsController#index action) + # # also adds the named route called "post_comments" + # # --> GET /comments/2 (maps to the CommentsController#show action as if it were not nested) + # # also adds the named route called "comment" + # + # You may also use <tt>:shallow</tt> in combination with the +has_one+ and +has_many+ shorthand notations like: + # + # map.resources :users, :has_many => { :posts => :comments }, :shallow => true + # + # If <tt>map.resources</tt> is called with multiple resources, they all get the same options applied. # # Examples: # @@ -442,7 +478,7 @@ module ActionController map_associations(resource, options) if block_given? - with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], &block) + with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block) end end end @@ -459,29 +495,45 @@ module ActionController map_associations(resource, options) if block_given? - with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], &block) + with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block) end end end def map_associations(resource, options) + map_has_many_associations(resource, options.delete(:has_many), options) if options[:has_many] + path_prefix = "#{options.delete(:path_prefix)}#{resource.nesting_path_prefix}" name_prefix = "#{options.delete(:name_prefix)}#{resource.nesting_name_prefix}" - Array(options[:has_many]).each do |association| - resources(association, :path_prefix => path_prefix, :name_prefix => name_prefix, :namespace => options[:namespace]) + Array(options[:has_one]).each do |association| + resource(association, :path_prefix => path_prefix, :name_prefix => name_prefix, :namespace => options[:namespace], :shallow => options[:shallow]) end + end - Array(options[:has_one]).each do |association| - resource(association, :path_prefix => path_prefix, :name_prefix => name_prefix, :namespace => options[:namespace]) + def map_has_many_associations(resource, associations, options) + case associations + when Hash + associations.each do |association,has_many| + map_has_many_associations(resource, association, options.merge(:has_many => has_many)) + end + when Array + associations.each do |association| + map_has_many_associations(resource, association, options) + end + when Symbol, String + resources(associations, :path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], :has_many => options[:has_many]) + else end end def map_collection_actions(map, resource) resource.collection_methods.each do |method, actions| actions.each do |action| - action_options = action_options_for(action, resource, method) - map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options) + [method].flatten.each do |m| + action_options = action_options_for(action, resource, m) + map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options) + end end end end @@ -521,17 +573,19 @@ module ActionController def map_member_actions(map, resource) resource.member_methods.each do |method, actions| actions.each do |action| - action_options = action_options_for(action, resource, method) + [method].flatten.each do |m| + action_options = action_options_for(action, resource, m) - action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash) - action_path ||= Base.resources_path_names[action] || action + action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash) + action_path ||= Base.resources_path_names[action] || action - map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options) + map_named_routes(map, "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options) + end end end show_action_options = action_options_for("show", resource) - map_named_routes(map, "#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options) + map_named_routes(map, "#{resource.shallow_name_prefix}#{resource.singular}", resource.member_path, show_action_options) update_action_options = action_options_for("update", resource) map_unnamed_routes(map, resource.member_path, update_action_options) @@ -574,4 +628,4 @@ end class ActionController::Routing::RouteSet::Mapper include ActionController::Resources -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_controller/response.rb index 5dac4128bb..54a99996ef 100644 --- a/actionpack/lib/action_controller/response.rb +++ b/actionpack/lib/action_controller/response.rb @@ -129,8 +129,8 @@ module ActionController # :nodoc: def prepare! assign_default_content_type_and_charset! - set_content_length! handle_conditional_get! + set_content_length! convert_content_type! end diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb index 03427e41de..5704d9d01a 100644 --- a/actionpack/lib/action_controller/routing/builder.rb +++ b/actionpack/lib/action_controller/routing/builder.rb @@ -187,12 +187,14 @@ module ActionController private def validate_route_conditions(conditions) if method = conditions[:method] - if method == :head - raise ArgumentError, "HTTP method HEAD is invalid in route conditions. Rails processes HEAD requests the same as GETs, returning just the response headers" - end + [method].flatten.each do |m| + if m == :head + raise ArgumentError, "HTTP method HEAD is invalid in route conditions. Rails processes HEAD requests the same as GETs, returning just the response headers" + end - unless HTTP_METHODS.include?(method.to_sym) - raise ArgumentError, "Invalid HTTP method specified in route conditions: #{conditions.inspect}" + unless HTTP_METHODS.include?(m.to_sym) + raise ArgumentError, "Invalid HTTP method specified in route conditions: #{conditions.inspect}" + end end end end diff --git a/actionpack/lib/action_controller/routing/optimisations.rb b/actionpack/lib/action_controller/routing/optimisations.rb index 0fe836606c..894d4109e4 100644 --- a/actionpack/lib/action_controller/routing/optimisations.rb +++ b/actionpack/lib/action_controller/routing/optimisations.rb @@ -103,9 +103,10 @@ module ActionController end # This case uses almost the same code as positional arguments, - # but add an args.last.to_query on the end + # but add a question mark and args.last.to_query on the end, + # unless the last arg is empty def generation_code - super.insert(-2, '?#{args.last.to_query}') + super.insert(-2, '#{\'?\' + args.last.to_query unless args.last.empty?}') end # To avoid generating "http://localhost/?host=foo.example.com" we diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb index 2106ac09e0..3b2cb28545 100644 --- a/actionpack/lib/action_controller/routing/route.rb +++ b/actionpack/lib/action_controller/routing/route.rb @@ -201,7 +201,7 @@ module ActionController # recognition, not generation. def recognition_conditions result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"] - result << "conditions[:method] === env[:method]" if conditions[:method] + result << "[conditions[:method]].flatten.include?(env[:method])" if conditions[:method] result end diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb index 8dfc22f94f..9d48f289db 100644 --- a/actionpack/lib/action_controller/routing/route_set.rb +++ b/actionpack/lib/action_controller/routing/route_set.rb @@ -115,7 +115,7 @@ module ActionController def install(destinations = [ActionController::Base, ActionView::Base], regenerate = false) reset! if regenerate Array(destinations).each do |dest| - dest.send! :include, @module + dest.__send__(:include, @module) end end @@ -353,7 +353,7 @@ module ActionController if generate_all # Used by caching to expire all paths for a resource return routes.collect do |route| - route.send!(method, options, merged, expire_on) + route.__send__(method, options, merged, expire_on) end.compact end @@ -361,7 +361,7 @@ module ActionController routes = routes_by_controller[controller][action][options.keys.sort_by { |x| x.object_id }] routes.each do |route| - results = route.send!(method, options, merged, expire_on) + results = route.__send__(method, options, merged, expire_on) return results if results && (!results.is_a?(Array) || results.first) end end diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index 9d4b740a44..e5f174ae2c 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -160,7 +160,7 @@ module ActionController s << "\n#{expiry_statement}" end - def interpolation_chunk(value_code = "#{local_name}") + def interpolation_chunk(value_code = local_name) "\#{URI.escape(#{value_code}.to_s, ActionController::Routing::Segment::UNSAFE_PCHAR)}" end @@ -231,7 +231,7 @@ module ActionController end # Don't URI.escape the controller name since it may contain slashes. - def interpolation_chunk(value_code = "#{local_name}") + def interpolation_chunk(value_code = local_name) "\#{#{value_code}.to_s}" end @@ -251,7 +251,7 @@ module ActionController end class PathSegment < DynamicSegment #:nodoc: - def interpolation_chunk(value_code = "#{local_name}") + def interpolation_chunk(value_code = local_name) "\#{#{value_code}}" end diff --git a/actionpack/lib/action_controller/session_management.rb b/actionpack/lib/action_controller/session_management.rb index 80a3ddd2c5..f5a1155a46 100644 --- a/actionpack/lib/action_controller/session_management.rb +++ b/actionpack/lib/action_controller/session_management.rb @@ -86,14 +86,14 @@ module ActionController #:nodoc: raise ArgumentError, "only one of either :only or :except are allowed" end - write_inheritable_array("session_options", [options]) + write_inheritable_array(:session_options, [options]) end # So we can declare session options in the Rails initializer. alias_method :session=, :session def cached_session_options #:nodoc: - @session_options ||= read_inheritable_attribute("session_options") || [] + @session_options ||= read_inheritable_attribute(:session_options) || [] end def session_options_for(request, action) #:nodoc: diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index a11fa7cd10..cde1f2052b 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -3,6 +3,8 @@ require 'action_controller/test_case' module ActionController #:nodoc: class Base + attr_reader :assigns + # Process a test request called with a TestRequest object. def self.process_test(request) new.process_test(request) @@ -14,7 +16,12 @@ module ActionController #:nodoc: def process_with_test(*args) returning process_without_test(*args) do - add_variables_to_assigns + @assigns = {} + (instance_variable_names - @@protected_instance_variables).each do |var| + value = instance_variable_get(var) + @assigns[var[1..-1]] = value + response.template.assigns[var[1..-1]] = value if response + end end end @@ -211,7 +218,7 @@ module ActionController #:nodoc: # Returns the template of the file which was used to # render this response (or nil) def rendered_template - template._first_render + template.send(:_first_render) end # A shortcut to the flash. Returns an empty hash if no session flash exists. @@ -350,7 +357,7 @@ module ActionController #:nodoc: alias local_path path def method_missing(method_name, *args, &block) #:nodoc: - @tempfile.send!(method_name, *args, &block) + @tempfile.__send__(method_name, *args, &block) end end @@ -396,7 +403,7 @@ module ActionController #:nodoc: def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' @request.env['HTTP_ACCEPT'] = 'text/javascript, text/html, application/xml, text/xml, */*' - returning send!(request_method, action, parameters, session, flash) do + returning __send__(request_method, action, parameters, session, flash) do @request.env.delete 'HTTP_X_REQUESTED_WITH' @request.env.delete 'HTTP_ACCEPT' end @@ -429,7 +436,7 @@ module ActionController #:nodoc: def build_request_uri(action, parameters) unless @request.env['REQUEST_URI'] - options = @controller.send!(:rewrite_options, parameters) + options = @controller.__send__(:rewrite_options, parameters) options.update(:only_path => true, :action => action) url = ActionController::UrlRewriter.new(@request, parameters) diff --git a/actionpack/lib/action_controller/verification.rb b/actionpack/lib/action_controller/verification.rb index 35b12a7f13..7bf09ba6ea 100644 --- a/actionpack/lib/action_controller/verification.rb +++ b/actionpack/lib/action_controller/verification.rb @@ -80,7 +80,7 @@ module ActionController #:nodoc: # array (may also be a single value). def verify(options={}) before_filter :only => options[:only], :except => options[:except] do |c| - c.send! :verify_action, options + c.__send__ :verify_action, options end end end @@ -116,7 +116,7 @@ module ActionController #:nodoc: end def apply_redirect_to(redirect_to_option) # :nodoc: - (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.send!(redirect_to_option) : redirect_to_option + (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option end def apply_remaining_actions(options) # :nodoc: diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index c65048bfa0..6c4da9067d 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -162,7 +162,6 @@ module ActionView #:nodoc: attr_accessor :base_path, :assigns, :template_extension attr_accessor :controller - attr_accessor :_first_render, :_last_render attr_writer :template_format @@ -185,6 +184,17 @@ module ActionView #:nodoc: "deprecated and has no effect. Please remove it from your config files.", caller) end + # Templates that are exempt from layouts + @@exempt_from_layout = Set.new([/\.rjs$/]) + + # Don't render layouts for templates with the given extensions. + def self.exempt_from_layout(*extensions) + regexps = extensions.collect do |extension| + extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ + end + @@exempt_from_layout.merge(regexps) + end + # Specify whether RJS responses should be wrapped in a try/catch block # that alert()s the caught exception (and then re-raises it). @@debug_rjs = false @@ -246,33 +256,20 @@ module ActionView #:nodoc: update_page(&block) elsif options.is_a?(Hash) options = options.reverse_merge(:locals => {}) - - if partial_layout = options.delete(:layout) - if block_given? - begin - @_proc_for_layout = block - concat(render(options.merge(:partial => partial_layout))) - ensure - @_proc_for_layout = nil - end - else - begin - original_content_for_layout, @content_for_layout = @content_for_layout, render(options) - render(options.merge(:partial => partial_layout)) - ensure - @content_for_layout = original_content_for_layout - end - end + if options[:layout] + _render_with_layout(options, local_assigns, &block) elsif options[:file] if options[:use_full_path] ActiveSupport::Deprecation.warn("use_full_path option has been deprecated and has no affect.", caller) end - pick_template(options[:file]).render_template(self, options[:locals]) + _pick_template(options[:file]).render_template(self, options[:locals]) elsif options[:partial] render_partial(options) elsif options[:inline] InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals]) + elsif options[:text] + options[:text] end end end @@ -290,74 +287,95 @@ module ActionView #:nodoc: end end - def file_exists?(template_path) - pick_template(template_path) ? true : false - rescue MissingTemplate - false - end + private + attr_accessor :_first_render, :_last_render - # Gets the extension for an existing template with the given template_path. - # Returns the format with the extension if that template exists. - # - # pick_template('users/show') - # # => 'users/show.html.erb' - # - # pick_template('users/legacy') - # # => 'users/legacy.rhtml' - # - def pick_template(template_path) - return template_path if template_path.respond_to?(:render) - - path = template_path.sub(/^\//, '') - if m = path.match(/(.*)\.(\w+)$/) - template_file_name, template_file_extension = m[1], m[2] - else - template_file_name = path - end + # Evaluate the local assigns and pushes them to the view. + def _evaluate_assigns_and_ivars #:nodoc: + unless @assigns_added + @assigns.each { |key, value| instance_variable_set("@#{key}", value) } - # OPTIMIZE: Checks to lookup template in view path - if template = self.view_paths["#{template_file_name}.#{template_format}"] - template - elsif template = self.view_paths[template_file_name] - template - elsif _first_render && template = self.view_paths["#{template_file_name}.#{_first_render.format_and_extension}"] - template - elsif template_format == :js && template = self.view_paths["#{template_file_name}.html"] - @template_format = :html - template - else - template = Template.new(template_path, view_paths) - - if self.class.warn_cache_misses && logger - logger.debug "[PERFORMANCE] Rendering a template that was " + - "not found in view path. Templates outside the view path are " + - "not cached and result in expensive disk operations. Move this " + - "file into #{view_paths.join(':')} or add the folder to your " + - "view path list" + if @controller + variables = @controller.instance_variables + variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables) + variables.each {|name| instance_variable_set(name, @controller.instance_variable_get(name)) } + end + + @assigns_added = true end + end - template + def _set_controller_content_type(content_type) #:nodoc: + if controller.respond_to?(:response) + controller.response.content_type ||= content_type + end end - end - memoize :pick_template - private - # Evaluate the local assigns and pushes them to the view. - def evaluate_assigns - unless @assigns_added - assign_variables_from_controller - @assigns_added = true + def _pick_template(template_path) + return template_path if template_path.respond_to?(:render) + + path = template_path.sub(/^\//, '') + if m = path.match(/(.*)\.(\w+)$/) + template_file_name, template_file_extension = m[1], m[2] + else + template_file_name = path + end + + # OPTIMIZE: Checks to lookup template in view path + if template = self.view_paths["#{template_file_name}.#{template_format}"] + template + elsif template = self.view_paths[template_file_name] + template + elsif _first_render && template = self.view_paths["#{template_file_name}.#{_first_render.format_and_extension}"] + template + elsif template_format == :js && template = self.view_paths["#{template_file_name}.html"] + @template_format = :html + template + else + template = Template.new(template_path, view_paths) + + if self.class.warn_cache_misses && logger + logger.debug "[PERFORMANCE] Rendering a template that was " + + "not found in view path. Templates outside the view path are " + + "not cached and result in expensive disk operations. Move this " + + "file into #{view_paths.join(':')} or add the folder to your " + + "view path list" + end + + template end end + memoize :_pick_template - # Assigns instance variables from the controller to the view. - def assign_variables_from_controller - @assigns.each { |key, value| instance_variable_set("@#{key}", value) } + def _exempt_from_layout?(template_path) #:nodoc: + template = _pick_template(template_path).to_s + @@exempt_from_layout.any? { |ext| template =~ ext } + rescue ActionView::MissingTemplate + return false end - def set_controller_content_type(content_type) - if controller.respond_to?(:response) - controller.response.content_type ||= content_type + def _render_with_layout(options, local_assigns, &block) #:nodoc: + partial_layout = options.delete(:layout) + + if block_given? + begin + @_proc_for_layout = block + concat(render(options.merge(:partial => partial_layout))) + ensure + @_proc_for_layout = nil + end + else + begin + original_content_for_layout, @content_for_layout = @content_for_layout, render(options) + if (options[:inline] || options[:file] || options[:text]) + @cached_content_for_layout = @content_for_layout + render(:file => partial_layout, :locals => local_assigns) + else + render(options.merge(:partial => partial_layout)) + end + ensure + @content_for_layout = original_content_for_layout + end end end end diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb index c339e10701..8b56d241ae 100644 --- a/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -246,7 +246,7 @@ module ActionView alias_method :tag_without_error_wrapping, :tag def tag(name, options) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(tag_without_error_wrapping(name, options), object.errors.on(@method_name)) else tag_without_error_wrapping(name, options) @@ -255,7 +255,7 @@ module ActionView alias_method :content_tag_without_error_wrapping, :content_tag def content_tag(name, value, options) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(content_tag_without_error_wrapping(name, value, options), object.errors.on(@method_name)) else content_tag_without_error_wrapping(name, value, options) @@ -264,7 +264,7 @@ module ActionView alias_method :to_date_select_tag_without_error_wrapping, :to_date_select_tag def to_date_select_tag(options = {}, html_options = {}) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(to_date_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else to_date_select_tag_without_error_wrapping(options, html_options) @@ -273,7 +273,7 @@ module ActionView alias_method :to_datetime_select_tag_without_error_wrapping, :to_datetime_select_tag def to_datetime_select_tag(options = {}, html_options = {}) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(to_datetime_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else to_datetime_select_tag_without_error_wrapping(options, html_options) @@ -282,7 +282,7 @@ module ActionView alias_method :to_time_select_tag_without_error_wrapping, :to_time_select_tag def to_time_select_tag(options = {}, html_options = {}) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(to_time_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else to_time_select_tag_without_error_wrapping(options, html_options) @@ -298,7 +298,7 @@ module ActionView end def column_type - object.send("column_for_attribute", @method_name).type + object.send(:column_for_attribute, @method_name).type end end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 623ed1e8df..ed33f082b9 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -104,7 +104,7 @@ module ActionView ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : "public" JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts" STYLESHEETS_DIR = "#{ASSETS_DIR}/stylesheets" - JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].map(&:to_s).freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES) + JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES) # Returns a link tag that browsers and news readers can use to auto-detect # an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index e452b04b31..ff41a6d417 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -255,6 +255,14 @@ module ActionView link_to_function(name, remote_function(options), html_options || options.delete(:html)) end + # Creates a button with an onclick event which calls a remote action + # via XMLHttpRequest + # The options for specifying the target with :url + # and defining callbacks is the same as link_to_remote. + def button_to_remote(name, options = {}, html_options = {}) + button_to_function(name, remote_function(options), html_options) + end + # Periodically calls the specified url (<tt>options[:url]</tt>) every # <tt>options[:frequency]</tt> seconds (default is 10). Usually used to # update a specified div (<tt>options[:update]</tt>) with the results @@ -1052,7 +1060,7 @@ module ActionView js_options['asynchronous'] = options[:type] != :synchronous js_options['method'] = method_option_to_s(options[:method]) if options[:method] - js_options['insertion'] = options[:position].to_s.downcase if options[:position] + js_options['insertion'] = "'#{options[:position].to_s.downcase}'" if options[:position] js_options['evalScripts'] = options[:script].nil? || options[:script] if options[:form] diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 9bb235175e..0cdb70e217 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -49,9 +49,9 @@ module ActionView # def content_tag_for(tag_name, record, *args, &block) prefix = args.first.is_a?(Hash) ? nil : args.shift - options = args.first.is_a?(Hash) ? args.shift : {} - concat content_tag(tag_name, capture(&block), - options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })) + options = args.extract_options! + options.merge!({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) }) + content_tag(tag_name, options, &block) end end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index ff6e588f62..ab1fdc80bc 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -298,7 +298,7 @@ module ActionView "" else textilized = RedCloth.new(text, [ :hard_breaks ]) - textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=") + textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=) textilized.to_html end end diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb index 443c49b870..373bb92dc4 100644 --- a/actionpack/lib/action_view/partials.rb +++ b/actionpack/lib/action_view/partials.rb @@ -196,7 +196,7 @@ module ActionView path = "_#{partial_path}" end - pick_template(path) + _pick_template(path) end memoize :_pick_partial_template end diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb index fa45edd436..d960335220 100644 --- a/actionpack/lib/action_view/renderable.rb +++ b/actionpack/lib/action_view/renderable.rb @@ -26,11 +26,11 @@ module ActionView def render(view, local_assigns = {}) compile(local_assigns) - view._first_render ||= self - view._last_render = self + view.send(:_first_render=, self) unless view.send(:_first_render) + view.send(:_last_render=, self) - view.send(:evaluate_assigns) - view.send(:set_controller_content_type, mime_type) if respond_to?(:mime_type) + view.send(:_evaluate_assigns_and_ivars) + view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type) view.send(method_name(local_assigns), local_assigns) do |*names| if proc = view.instance_variable_get("@_proc_for_layout") diff --git a/actionpack/lib/action_view/renderable_partial.rb b/actionpack/lib/action_view/renderable_partial.rb index 5203e57ead..123a9aebbc 100644 --- a/actionpack/lib/action_view/renderable_partial.rb +++ b/actionpack/lib/action_view/renderable_partial.rb @@ -27,8 +27,14 @@ module ActionView def render_partial(view, object = nil, local_assigns = {}, as = nil) object ||= local_assigns[:object] || - local_assigns[variable_name] || - view.controller.instance_variable_get("@#{variable_name}") if view.respond_to?(:controller) + local_assigns[variable_name] + + if view.respond_to?(:controller) + object ||= ActiveSupport::Deprecation::DeprecatedObjectProxy.new( + view.controller.instance_variable_get("@#{variable_name}"), + "@#{variable_name} will no longer be implicitly assigned to #{variable_name}" + ) + end # Ensure correct object is reassigned to other accessors local_assigns[:object] = local_assigns[variable_name] = object diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template_handlers/builder.rb index 7d24a5c423..788dc93326 100644 --- a/actionpack/lib/action_view/template_handlers/builder.rb +++ b/actionpack/lib/action_view/template_handlers/builder.rb @@ -6,7 +6,7 @@ module ActionView include Compilable def compile(template) - "set_controller_content_type(Mime::XML);" + + "_set_controller_content_type(Mime::XML);" + "xml = ::Builder::XmlMarkup.new(:indent => 2);" + "self.output_buffer = xml.target!;" + template.source + diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index adbb37fd09..c69f9455b2 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -54,7 +54,7 @@ module ActionView private def method_missing(selector, *args) controller = TestController.new - return controller.send!(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector) + return controller.__send__(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector) super end end diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index 1531e7c21a..08cbcbf302 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -433,6 +433,17 @@ class AssertSelectTest < Test::Unit::TestCase assert_select_rjs :remove, "test1" end + def test_assert_select_rjs_for_remove_offers_useful_error_when_assertion_fails + render_rjs do |page| + page.remove "test_with_typo" + end + + assert_select_rjs :remove, "test1" + + rescue Test::Unit::AssertionFailedError + assert_equal "No RJS statement that removes 'test1' was rendered.", $!.message + end + def test_assert_select_rjs_for_remove_ignores_block render_rjs do |page| page.remove "test1" @@ -454,6 +465,17 @@ class AssertSelectTest < Test::Unit::TestCase assert_select_rjs :show, "test1" end + def test_assert_select_rjs_for_show_offers_useful_error_when_assertion_fails + render_rjs do |page| + page.show "test_with_typo" + end + + assert_select_rjs :show, "test1" + + rescue Test::Unit::AssertionFailedError + assert_equal "No RJS statement that shows 'test1' was rendered.", $!.message + end + def test_assert_select_rjs_for_show_ignores_block render_rjs do |page| page.show "test1" @@ -475,6 +497,17 @@ class AssertSelectTest < Test::Unit::TestCase assert_select_rjs :hide, "test1" end + def test_assert_select_rjs_for_hide_offers_useful_error_when_assertion_fails + render_rjs do |page| + page.hide "test_with_typo" + end + + assert_select_rjs :hide, "test1" + + rescue Test::Unit::AssertionFailedError + assert_equal "No RJS statement that hides 'test1' was rendered.", $!.message + end + def test_assert_select_rjs_for_hide_ignores_block render_rjs do |page| page.hide "test1" @@ -496,6 +529,17 @@ class AssertSelectTest < Test::Unit::TestCase assert_select_rjs :toggle, "test1" end + def test_assert_select_rjs_for_toggle_offers_useful_error_when_assertion_fails + render_rjs do |page| + page.toggle "test_with_typo" + end + + assert_select_rjs :toggle, "test1" + + rescue Test::Unit::AssertionFailedError + assert_equal "No RJS statement that toggles 'test1' was rendered.", $!.message + end + def test_assert_select_rjs_for_toggle_ignores_block render_rjs do |page| page.toggle "test1" @@ -555,6 +599,11 @@ class AssertSelectTest < Test::Unit::TestCase end end + def test_assert_select_rjs_raise_errors + assert_raises(ArgumentError) { assert_select_rjs(:destroy) } + assert_raises(ArgumentError) { assert_select_rjs(:insert, :left) } + end + # Simple selection from a single result. def test_nested_assert_select_rjs_with_single_result render_rjs do |page| diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index d49cc2a9aa..738c016c6e 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -84,11 +84,11 @@ class ControllerInstanceTests < Test::Unit::TestCase def test_action_methods @empty_controllers.each do |c| hide_mocha_methods_from_controller(c) - assert_equal Set.new, c.send!(:action_methods), "#{c.controller_path} should be empty!" + assert_equal Set.new, c.__send__(:action_methods), "#{c.controller_path} should be empty!" end @non_empty_controllers.each do |c| hide_mocha_methods_from_controller(c) - assert_equal Set.new(%w(public_action)), c.send!(:action_methods), "#{c.controller_path} should not be empty!" + assert_equal Set.new(%w(public_action)), c.__send__(:action_methods), "#{c.controller_path} should not be empty!" end end @@ -100,7 +100,7 @@ class ControllerInstanceTests < Test::Unit::TestCase :expects, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify, :__metaclass__, :__is_a__, :to_matcher, ] - controller.class.send!(:hide_action, *mocha_methods) + controller.class.__send__(:hide_action, *mocha_methods) end end @@ -140,7 +140,7 @@ class PerformActionTest < Test::Unit::TestCase def test_method_missing_is_not_an_action_name use_controller MethodMissingController - assert ! @controller.send!(:action_methods).include?('method_missing') + assert ! @controller.__send__(:action_methods).include?('method_missing') get :method_missing assert_response :success diff --git a/actionpack/test/controller/components_test.rb b/actionpack/test/controller/components_test.rb index 71e8a18071..4d36fc411d 100644 --- a/actionpack/test/controller/components_test.rb +++ b/actionpack/test/controller/components_test.rb @@ -77,49 +77,64 @@ class ComponentsTest < Test::Unit::TestCase end def test_calling_from_controller - get :calling_from_controller - assert_equal "Lady of the House, speaking", @response.body + assert_deprecated do + get :calling_from_controller + assert_equal "Lady of the House, speaking", @response.body + end end def test_calling_from_controller_with_params - get :calling_from_controller_with_params - assert_equal "David of the House, speaking", @response.body + assert_deprecated do + get :calling_from_controller_with_params + assert_equal "David of the House, speaking", @response.body + end end def test_calling_from_controller_with_different_status_code - get :calling_from_controller_with_different_status_code - assert_equal 500, @response.response_code + assert_deprecated do + get :calling_from_controller_with_different_status_code + assert_equal 500, @response.response_code + end end def test_calling_from_template - get :calling_from_template - assert_equal "Ring, ring: Lady of the House, speaking", @response.body + assert_deprecated do + get :calling_from_template + assert_equal "Ring, ring: Lady of the House, speaking", @response.body + end end def test_etag_is_set_for_parent_template_when_calling_from_template - get :calling_from_template - expected_etag = etag_for("Ring, ring: Lady of the House, speaking") - assert_equal expected_etag, @response.headers['ETag'] + assert_deprecated do + get :calling_from_template + expected_etag = etag_for("Ring, ring: Lady of the House, speaking") + assert_equal expected_etag, @response.headers['ETag'] + end end def test_internal_calling - get :internal_caller - assert_equal "Are you there? Yes, ma'am", @response.body + assert_deprecated do + get :internal_caller + assert_equal "Are you there? Yes, ma'am", @response.body + end end def test_flash - get :set_flash - assert_equal 'My stoney baby', flash[:notice] - get :use_flash - assert_equal 'My stoney baby', @response.body - get :use_flash - assert_equal 'no flash', @response.body + assert_deprecated do + get :set_flash + assert_equal 'My stoney baby', flash[:notice] + get :use_flash + assert_equal 'My stoney baby', @response.body + get :use_flash + assert_equal 'no flash', @response.body + end end def test_component_redirect_redirects - get :calling_redirected - - assert_redirected_to :controller=>"callee", :action => "being_called" + assert_deprecated do + get :calling_redirected + assert_redirected_to :controller=>"callee", :action => "being_called" + end end def test_component_multiple_redirect_redirects @@ -128,9 +143,10 @@ class ComponentsTest < Test::Unit::TestCase end def test_component_as_string_redirect_renders_redirected_action - get :calling_redirected_as_string - - assert_equal "Lady of the House, speaking", @response.body + assert_deprecated do + get :calling_redirected_as_string + assert_equal "Lady of the House, speaking", @response.body + end end protected diff --git a/actionpack/test/controller/filter_params_test.rb b/actionpack/test/controller/filter_params_test.rb index c4de10181d..0b259a7980 100644 --- a/actionpack/test/controller/filter_params_test.rb +++ b/actionpack/test/controller/filter_params_test.rb @@ -27,7 +27,7 @@ class FilterParamTest < Test::Unit::TestCase test_hashes.each do |before_filter, after_filter, filter_words| FilterParamController.filter_parameter_logging(*filter_words) - assert_equal after_filter, @controller.send!(:filter_parameters, before_filter) + assert_equal after_filter, @controller.__send__(:filter_parameters, before_filter) filter_words.push('blah') FilterParamController.filter_parameter_logging(*filter_words) do |key, value| @@ -37,7 +37,7 @@ class FilterParamTest < Test::Unit::TestCase before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}} after_filter['barg'] = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}} - assert_equal after_filter, @controller.send!(:filter_parameters, before_filter) + assert_equal after_filter, @controller.__send__(:filter_parameters, before_filter) end end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 3652c482f1..dafa344473 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -111,15 +111,15 @@ class FilterTest < Test::Unit::TestCase end class OnlyConditionProcController < ConditionalFilterController - before_filter(:only => :show) {|c| c.assigns["ran_proc_filter"] = true } + before_filter(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_filter", true) } end class ExceptConditionProcController < ConditionalFilterController - before_filter(:except => :show_without_filter) {|c| c.assigns["ran_proc_filter"] = true } + before_filter(:except => :show_without_filter) {|c| c.instance_variable_set(:"@ran_proc_filter", true) } end class ConditionalClassFilter - def self.filter(controller) controller.assigns["ran_class_filter"] = true end + def self.filter(controller) controller.instance_variable_set(:"@ran_class_filter", true) end end class OnlyConditionClassController < ConditionalFilterController @@ -131,7 +131,7 @@ class FilterTest < Test::Unit::TestCase end class AnomolousYetValidConditionController < ConditionalFilterController - before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.assigns["ran_proc_filter1"] = true }, :except => :show_without_filter) { |c| c.assigns["ran_proc_filter2"] = true} + before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.instance_variable_set(:"@ran_proc_filter1", true)}, :except => :show_without_filter) { |c| c.instance_variable_set(:"@ran_proc_filter2", true)} end class ConditionalOptionsFilter < ConditionalFilterController @@ -225,16 +225,16 @@ class FilterTest < Test::Unit::TestCase end class ProcController < PrependingController - before_filter(proc { |c| c.assigns["ran_proc_filter"] = true }) + before_filter(proc { |c| c.instance_variable_set(:"@ran_proc_filter", true) }) end class ImplicitProcController < PrependingController - before_filter { |c| c.assigns["ran_proc_filter"] = true } + before_filter { |c| c.instance_variable_set(:"@ran_proc_filter", true) } end class AuditFilter def self.filter(controller) - controller.assigns["was_audited"] = true + controller.instance_variable_set(:"@was_audited", true) end end @@ -242,12 +242,12 @@ class FilterTest < Test::Unit::TestCase def before(controller) @execution_log = "before" controller.class.execution_log << " before aroundfilter " if controller.respond_to? :execution_log - controller.assigns["before_ran"] = true + controller.instance_variable_set(:"@before_ran", true) end def after(controller) - controller.assigns["execution_log"] = @execution_log + " and after" - controller.assigns["after_ran"] = true + controller.instance_variable_set(:"@execution_log", @execution_log + " and after") + controller.instance_variable_set(:"@after_ran", true) controller.class.execution_log << " after aroundfilter " if controller.respond_to? :execution_log end end @@ -364,7 +364,7 @@ class FilterTest < Test::Unit::TestCase begin yield rescue ErrorToRescue => ex - controller.send! :render, :text => "I rescued this: #{ex.inspect}" + controller.__send__ :render, :text => "I rescued this: #{ex.inspect}" end end end @@ -726,9 +726,9 @@ end class ControllerWithProcFilter < PostsController around_filter(:only => :no_raise) do |c,b| - c.assigns['before'] = true + c.instance_variable_set(:"@before", true) b.call - c.assigns['after'] = true + c.instance_variable_set(:"@after", true) end end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index c986941140..7e4c3e171a 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -243,7 +243,7 @@ class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest reset! stub_integration_session(@integration_session) %w( get post head put delete ).each do |verb| - assert_nothing_raised("'#{verb}' should use integration test methods") { send!(verb, '/') } + assert_nothing_raised("'#{verb}' should use integration test methods") { __send__(verb, '/') } end end end diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 71f110f241..1120fdbff5 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -79,53 +79,6 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase end end -class ExemptFromLayoutTest < Test::Unit::TestCase - def setup - @controller = LayoutTest.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_rjs_exempt_from_layout - assert @controller.send!(:template_exempt_from_layout?, 'test.rjs') - end - - def test_rhtml_and_rxml_not_exempt_from_layout - assert !@controller.send!(:template_exempt_from_layout?, 'test.rhtml') - assert !@controller.send!(:template_exempt_from_layout?, 'test.rxml') - end - - def test_other_extension_not_exempt_from_layout - assert !@controller.send!(:template_exempt_from_layout?, 'test.random') - end - - def test_add_extension_to_exempt_from_layout - ['rpdf', :rpdf].each do |ext| - assert_nothing_raised do - ActionController::Base.exempt_from_layout ext - end - assert @controller.send!(:template_exempt_from_layout?, "test.#{ext}") - end - end - - def test_add_regexp_to_exempt_from_layout - ActionController::Base.exempt_from_layout /\.rdoc/ - assert @controller.send!(:template_exempt_from_layout?, 'test.rdoc') - end - - def test_rhtml_exempt_from_layout_status_should_prevent_layout_render - ActionController::Base.exempt_from_layout :rhtml - - assert @controller.send!(:template_exempt_from_layout?, 'test.rhtml') - assert @controller.send!(:template_exempt_from_layout?, 'hello.rhtml') - - get :hello - assert_equal 'hello.rhtml', @response.body - ActionController::Base.exempt_from_layout.delete(/\.rhtml$/) - end -end - - class DefaultLayoutController < LayoutTest end @@ -179,8 +132,6 @@ class LayoutSetInResponseTest < Test::Unit::TestCase ActionController::Base.exempt_from_layout :rhtml @controller = RenderWithTemplateOptionController.new - assert @controller.send(:template_exempt_from_layout?, 'alt/hello.rhtml') - get :hello assert_equal "alt/hello.rhtml", @response.body.strip diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb deleted file mode 100644 index 82919b7777..0000000000 --- a/actionpack/test/controller/new_render_test.rb +++ /dev/null @@ -1,981 +0,0 @@ -require 'abstract_unit' -require 'controller/fake_models' - -class CustomersController < ActionController::Base -end - -module Fun - class GamesController < ActionController::Base - def hello_world - end - end -end - -module NewRenderTestHelper - def rjs_helper_method_from_module - page.visual_effect :highlight - end -end - -class LabellingFormBuilder < ActionView::Helpers::FormBuilder -end - -class NewRenderTestController < ActionController::Base - layout :determine_layout - - def self.controller_name; "test"; end - def self.controller_path; "test"; end - - def hello_world - end - - def render_hello_world - render :template => "test/hello_world" - end - - def render_hello_world_from_variable - @person = "david" - render :text => "hello #{@person}" - end - - def render_action_hello_world - render :action => "hello_world" - end - - def render_action_hello_world_as_symbol - render :action => :hello_world - end - - def render_text_hello_world - render :text => "hello world" - end - - def render_text_hello_world_with_layout - @variable_for_layout = ", I'm here!" - render :text => "hello world", :layout => true - end - - def hello_world_with_layout_false - render :layout => false - end - - def render_custom_code - render :text => "hello world", :status => "404 Moved" - end - - def render_file_with_instance_variables - @secret = 'in the sauce' - path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb') - render :file => path - end - - def render_file_from_template - @secret = 'in the sauce' - @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')) - end - - def render_file_with_locals - path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb') - render :file => path, :locals => {:secret => 'in the sauce'} - end - - def render_file_not_using_full_path - @secret = 'in the sauce' - render :file => 'test/render_file_with_ivar' - end - - def render_file_not_using_full_path_with_dot_in_path - @secret = 'in the sauce' - render :file => 'test/dot.directory/render_file_with_ivar' - end - - def render_xml_hello - @name = "David" - render :template => "test/hello" - end - - def greeting - # let's just rely on the template - end - - def layout_test - render :action => "hello_world" - end - - def layout_test_with_different_layout - render :action => "hello_world", :layout => "standard" - end - - def rendering_without_layout - render :action => "hello_world", :layout => false - end - - def layout_overriding_layout - render :action => "hello_world", :layout => "standard" - end - - def rendering_nothing_on_layout - render :nothing => true - end - - def builder_layout_test - render :action => "hello" - end - - def partials_list - @test_unchanged = 'hello' - @customers = [ Customer.new("david"), Customer.new("mary") ] - render :action => "list" - end - - def partial_only - render :partial => true - end - - def partial_only_with_layout - render :partial => "partial_only", :layout => true - end - - def partial_with_counter - render :partial => "counter", :locals => { :counter_counter => 5 } - end - - def partial_with_locals - render :partial => "customer", :locals => { :customer => Customer.new("david") } - end - - def partial_with_form_builder - render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, @template, {}, Proc.new {}) - end - - def partial_with_form_builder_subclass - render :partial => LabellingFormBuilder.new(:post, nil, @template, {}, Proc.new {}) - end - - def partial_collection - render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ] - end - - def partial_collection_with_as - render :partial => "customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer - end - - def partial_collection_with_spacer - render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ] - end - - def partial_collection_with_counter - render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ] - end - - def partial_collection_with_locals - render :partial => "customer_greeting", :collection => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } - end - - def partial_collection_shorthand_with_locals - render :partial => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } - end - - def partial_collection_shorthand_with_different_types_of_records - render :partial => [ - BadCustomer.new("mark"), - GoodCustomer.new("craig"), - BadCustomer.new("john"), - GoodCustomer.new("zach"), - GoodCustomer.new("brandon"), - BadCustomer.new("dan") ], - :locals => { :greeting => "Bonjour" } - end - - def partial_collection_shorthand_with_different_types_of_records_with_counter - partial_collection_shorthand_with_different_types_of_records - end - - def empty_partial_collection - render :partial => "customer", :collection => [] - end - - def partial_with_hash_object - render :partial => "hash_object", :object => {:first_name => "Sam"} - end - - def partial_hash_collection - render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ] - end - - def partial_hash_collection_with_locals - render :partial => "hash_greeting", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ], :locals => { :greeting => "Hola" } - end - - def partial_with_implicit_local_assignment - @customer = Customer.new("Marcel") - render :partial => "customer" - end - - def missing_partial - render :partial => 'thisFileIsntHere' - end - - def hello_in_a_string - @customers = [ Customer.new("david"), Customer.new("mary") ] - render :text => "How's there? " << render_to_string(:template => "test/list") - end - - def render_to_string_with_assigns - @before = "i'm before the render" - render_to_string :text => "foo" - @after = "i'm after the render" - render :action => "test/hello_world" - end - - def render_to_string_with_partial - @partial_only = render_to_string :partial => "partial_only" - @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") } - render :action => "test/hello_world" - end - - def render_to_string_with_exception - render_to_string :file => "exception that will not be caught - this will certainly not work" - end - - def render_to_string_with_caught_exception - @before = "i'm before the render" - begin - render_to_string :file => "exception that will be caught- hope my future instance vars still work!" - rescue - end - @after = "i'm after the render" - render :action => "test/hello_world" - end - - def accessing_params_in_template - render :inline => "Hello: <%= params[:name] %>" - end - - def accessing_request_in_template - render :inline => "Hello: <%= request.host %>" - end - - def accessing_logger_in_template - render :inline => "<%= logger.class %>" - end - - def accessing_action_name_in_template - render :inline => "<%= action_name %>" - end - - def accessing_controller_name_in_template - render :inline => "<%= controller_name %>" - end - - def accessing_params_in_template_with_layout - render :layout => nil, :inline => "Hello: <%= params[:name] %>" - end - - def render_with_explicit_template - render :template => "test/hello_world" - end - - def render_with_explicit_template_with_locals - render :template => "test/render_file_with_locals", :locals => { :secret => 'area51' } - end - - def double_render - render :text => "hello" - render :text => "world" - end - - def double_redirect - redirect_to :action => "double_render" - redirect_to :action => "double_render" - end - - def render_and_redirect - render :text => "hello" - redirect_to :action => "double_render" - end - - def render_to_string_and_render - @stuff = render_to_string :text => "here is some cached stuff" - render :text => "Hi web users! #{@stuff}" - end - - def rendering_with_conflicting_local_vars - @name = "David" - def @template.name() nil end - render :action => "potential_conflicts" - end - - def hello_world_from_rxml_using_action - render :action => "hello_world_from_rxml.builder" - end - - def hello_world_from_rxml_using_template - render :template => "test/hello_world_from_rxml.builder" - end - - def head_with_location_header - head :location => "/foo" - end - - def head_with_symbolic_status - head :status => params[:status].intern - end - - def head_with_integer_status - head :status => params[:status].to_i - end - - def head_with_string_status - head :status => params[:status] - end - - def head_with_custom_header - head :x_custom_header => "something" - end - - def head_with_status_code_first - head :forbidden, :x_custom_header => "something" - end - - def render_with_location - render :xml => "<hello/>", :location => "http://example.com", :status => 201 - end - - def render_with_object_location - customer = Customer.new("Some guy", 1) - render :xml => "<customer/>", :location => customer_url(customer), :status => :created - end - - def render_with_to_xml - to_xmlable = Class.new do - def to_xml - "<i-am-xml/>" - end - end.new - - render :xml => to_xmlable - end - - helper NewRenderTestHelper - helper do - def rjs_helper_method(value) - page.visual_effect :highlight, value - end - end - - def enum_rjs_test - render :update do |page| - page.select('.product').each do |value| - page.rjs_helper_method_from_module - page.rjs_helper_method(value) - page.sortable(value, :url => { :action => "order" }) - page.draggable(value) - end - end - end - - def delete_with_js - @project_id = 4 - end - - def render_js_with_explicit_template - @project_id = 4 - render :template => 'test/delete_with_js' - end - - def render_js_with_explicit_action_template - @project_id = 4 - render :action => 'delete_with_js' - end - - def update_page - render :update do |page| - page.replace_html 'balance', '$37,000,000.00' - page.visual_effect :highlight, 'balance' - end - end - - def update_page_with_instance_variables - @money = '$37,000,000.00' - @div_id = 'balance' - render :update do |page| - page.replace_html @div_id, @money - page.visual_effect :highlight, @div_id - end - end - - def action_talk_to_layout - # Action template sets variable that's picked up by layout - end - - def render_text_with_assigns - @hello = "world" - render :text => "foo" - end - - def yield_content_for - render :action => "content_for", :layout => "yield" - end - - def render_content_type_from_body - response.content_type = Mime::RSS - render :text => "hello world!" - end - - def render_call_to_partial_with_layout - render :action => "calling_partial_with_layout" - end - - def render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout - render :action => "calling_partial_with_layout" - end - - def render_using_layout_around_block - render :action => "using_layout_around_block" - end - - def render_using_layout_around_block_with_args - render :action => "using_layout_around_block_with_args" - end - - def render_using_layout_around_block_in_main_layout_and_within_content_for_layout - render :action => "using_layout_around_block" - end - - def rescue_action(e) raise end - - private - def determine_layout - case action_name - when "hello_world", "layout_test", "rendering_without_layout", - "rendering_nothing_on_layout", "render_text_hello_world", - "render_text_hello_world_with_layout", - "hello_world_with_layout_false", - "partial_only", "partial_only_with_layout", - "accessing_params_in_template", - "accessing_params_in_template_with_layout", - "render_with_explicit_template", - "render_js_with_explicit_template", - "render_js_with_explicit_action_template", - "delete_with_js", "update_page", "update_page_with_instance_variables" - - "layouts/standard" - when "builder_layout_test" - "layouts/builder" - when "action_talk_to_layout", "layout_overriding_layout" - "layouts/talk_from_action" - when "render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout" - "layouts/partial_with_layout" - when "render_using_layout_around_block_in_main_layout_and_within_content_for_layout" - "layouts/block_with_layout" - end - end -end - -class NewRenderTest < Test::Unit::TestCase - def setup - @controller = NewRenderTestController.new - - # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get - # a more accurate simulation of what happens in "real life". - @controller.logger = Logger.new(nil) - - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - - @request.host = "www.nextangle.com" - end - - def test_simple_show - get :hello_world - assert_response :success - assert_template "test/hello_world" - assert_equal "<html>Hello world!</html>", @response.body - end - - def test_renders_default_template_for_missing_action - get :'hyphen-ated' - assert_template 'test/hyphen-ated' - end - - def test_do_with_render - get :render_hello_world - assert_template "test/hello_world" - end - - def test_do_with_render_from_variable - get :render_hello_world_from_variable - assert_equal "hello david", @response.body - end - - def test_do_with_render_action - get :render_action_hello_world - assert_template "test/hello_world" - end - - def test_do_with_render_action_as_symbol - get :render_action_hello_world_as_symbol - assert_template "test/hello_world" - end - - def test_do_with_render_text - get :render_text_hello_world - assert_equal "hello world", @response.body - end - - def test_do_with_render_text_and_layout - get :render_text_hello_world_with_layout - assert_equal "<html>hello world, I'm here!</html>", @response.body - end - - def test_do_with_render_action_and_layout_false - get :hello_world_with_layout_false - assert_equal 'Hello world!', @response.body - end - - def test_do_with_render_custom_code - get :render_custom_code - assert_response :missing - end - - def test_render_file_with_instance_variables - get :render_file_with_instance_variables - assert_equal "The secret is in the sauce\n", @response.body - end - - def test_render_file_not_using_full_path - get :render_file_not_using_full_path - assert_equal "The secret is in the sauce\n", @response.body - end - - def test_render_file_not_using_full_path_with_dot_in_path - get :render_file_not_using_full_path_with_dot_in_path - assert_equal "The secret is in the sauce\n", @response.body - end - - def test_render_file_with_locals - get :render_file_with_locals - assert_equal "The secret is in the sauce\n", @response.body - end - - def test_render_file_from_template - get :render_file_from_template - assert_equal "The secret is in the sauce\n", @response.body - end - - def test_attempt_to_access_object_method - assert_raises(ActionController::UnknownAction, "No action responded to [clone]") { get :clone } - end - - def test_private_methods - assert_raises(ActionController::UnknownAction, "No action responded to [determine_layout]") { get :determine_layout } - end - - def test_access_to_request_in_view - get :accessing_request_in_template - assert_equal "Hello: www.nextangle.com", @response.body - end - - def test_access_to_logger_in_view - get :accessing_logger_in_template - assert_equal "Logger", @response.body - end - - def test_access_to_action_name_in_view - get :accessing_action_name_in_template - assert_equal "accessing_action_name_in_template", @response.body - end - - def test_access_to_controller_name_in_view - get :accessing_controller_name_in_template - assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller. - end - - def test_render_xml - get :render_xml_hello - assert_equal "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body - end - - def test_enum_rjs_test - get :enum_rjs_test - assert_equal <<-EOS.strip, @response.body -$$(".product").each(function(value, index) { -new Effect.Highlight(element,{}); -new Effect.Highlight(value,{}); -Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value)})}}); -new Draggable(value, {}); -}); -EOS - end - - def test_render_xml_with_default - get :greeting - assert_equal "<p>This is grand!</p>\n", @response.body - end - - def test_render_with_default_from_accept_header - xhr :get, :greeting - assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body - end - - def test_render_rjs_with_default - get :delete_with_js - assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body - end - - def test_render_rjs_template_explicitly - get :render_js_with_explicit_template - assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body - end - - def test_rendering_rjs_action_explicitly - get :render_js_with_explicit_action_template - assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body - end - - def test_layout_rendering - get :layout_test - assert_equal "<html>Hello world!</html>", @response.body - end - - def test_layout_test_with_different_layout - get :layout_test_with_different_layout - assert_equal "<html>Hello world!</html>", @response.body - end - - def test_rendering_without_layout - get :rendering_without_layout - assert_equal "Hello world!", @response.body - end - - def test_layout_overriding_layout - get :layout_overriding_layout - assert_no_match %r{<title>}, @response.body - end - - def test_rendering_nothing_on_layout - get :rendering_nothing_on_layout - assert_equal " ", @response.body - end - - def test_render_xml_with_layouts - get :builder_layout_test - assert_equal "<wrapper>\n<html>\n <p>Hello </p>\n<p>This is grand!</p>\n</html>\n</wrapper>\n", @response.body - end - - def test_partial_only - get :partial_only - assert_equal "only partial", @response.body - end - - def test_partial_only_with_layout - get :partial_only_with_layout - assert_equal "<html>only partial</html>", @response.body - end - - def test_render_to_string - assert_not_deprecated { get :hello_in_a_string } - assert_equal "How's there? goodbyeHello: davidHello: marygoodbye\n", @response.body - end - - def test_render_to_string_doesnt_break_assigns - get :render_to_string_with_assigns - assert_equal "i'm before the render", assigns(:before) - assert_equal "i'm after the render", assigns(:after) - end - - def test_render_to_string_partial - get :render_to_string_with_partial - assert_equal "only partial", assigns(:partial_only) - assert_equal "Hello: david", assigns(:partial_with_locals) - end - - def test_bad_render_to_string_still_throws_exception - assert_raises(ActionView::MissingTemplate) { get :render_to_string_with_exception } - end - - def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns - assert_nothing_raised { get :render_to_string_with_caught_exception } - assert_equal "i'm before the render", assigns(:before) - assert_equal "i'm after the render", assigns(:after) - end - - def test_nested_rendering - get :hello_world - assert_equal "Living in a nested world", Fun::GamesController.process(@request, @response).body - end - - def test_accessing_params_in_template - get :accessing_params_in_template, :name => "David" - assert_equal "Hello: David", @response.body - end - - def test_accessing_params_in_template_with_layout - get :accessing_params_in_template_with_layout, :name => "David" - assert_equal "<html>Hello: David</html>", @response.body - end - - def test_render_with_explicit_template - get :render_with_explicit_template - assert_response :success - end - - def test_double_render - assert_raises(ActionController::DoubleRenderError) { get :double_render } - end - - def test_double_redirect - assert_raises(ActionController::DoubleRenderError) { get :double_redirect } - end - - def test_render_and_redirect - assert_raises(ActionController::DoubleRenderError) { get :render_and_redirect } - end - - # specify the one exception to double render rule - render_to_string followed by render - def test_render_to_string_and_render - get :render_to_string_and_render - assert_equal("Hi web users! here is some cached stuff", @response.body) - end - - def test_rendering_with_conflicting_local_vars - get :rendering_with_conflicting_local_vars - assert_equal("First: David\nSecond: Stephan\nThird: David\nFourth: David\nFifth: ", @response.body) - end - - def test_action_talk_to_layout - get :action_talk_to_layout - assert_equal "<title>Talking to the layout</title>\nAction was here!", @response.body - end - - def test_partial_with_counter - get :partial_with_counter - assert_equal "5", @response.body - end - - def test_partials_list - get :partials_list - assert_equal "goodbyeHello: davidHello: marygoodbye\n", @response.body - end - - def test_partial_with_locals - get :partial_with_locals - assert_equal "Hello: david", @response.body - end - - def test_partial_with_form_builder - get :partial_with_form_builder - assert_match(/<label/, @response.body) - assert_template('test/_form') - end - - def test_partial_with_form_builder_subclass - get :partial_with_form_builder_subclass - assert_match(/<label/, @response.body) - assert_template('test/_labelling_form') - end - - def test_partial_collection - get :partial_collection - assert_equal "Hello: davidHello: mary", @response.body - end - - def test_partial_collection_with_as - get :partial_collection_with_as - assert_equal "david david davidmary mary mary", @response.body - end - - def test_partial_collection_with_counter - get :partial_collection_with_counter - assert_equal "david0mary1", @response.body - end - - def test_partial_collection_with_locals - get :partial_collection_with_locals - assert_equal "Bonjour: davidBonjour: mary", @response.body - end - - def test_partial_collection_with_spacer - get :partial_collection_with_spacer - assert_equal "Hello: davidonly partialHello: mary", @response.body - end - - def test_partial_collection_shorthand_with_locals - get :partial_collection_shorthand_with_locals - assert_equal "Bonjour: davidBonjour: mary", @response.body - end - - def test_partial_collection_shorthand_with_different_types_of_records - get :partial_collection_shorthand_with_different_types_of_records - assert_equal "Bonjour bad customer: mark0Bonjour good customer: craig1Bonjour bad customer: john2Bonjour good customer: zach3Bonjour good customer: brandon4Bonjour bad customer: dan5", @response.body - end - - def test_empty_partial_collection - get :empty_partial_collection - assert_equal " ", @response.body - end - - def test_partial_with_hash_object - get :partial_with_hash_object - assert_equal "Sam\nmaS\n", @response.body - end - - def test_hash_partial_collection - get :partial_hash_collection - assert_equal "Pratik\nkitarP\nAmy\nymA\n", @response.body - end - - def test_partial_hash_collection_with_locals - get :partial_hash_collection_with_locals - assert_equal "Hola: PratikHola: Amy", @response.body - end - - def test_partial_with_implicit_local_assignment - get :partial_with_implicit_local_assignment - assert_equal "Hello: Marcel", @response.body - end - - def test_render_missing_partial_template - assert_raises(ActionView::MissingTemplate) do - get :missing_partial - end - end - - def test_render_text_with_assigns - get :render_text_with_assigns - assert_equal "world", assigns["hello"] - end - - def test_template_with_locals - get :render_with_explicit_template_with_locals - assert_equal "The secret is area51\n", @response.body - end - - def test_update_page - get :update_page - assert_template nil - assert_equal 'text/javascript; charset=utf-8', @response.headers['type'] - assert_equal 2, @response.body.split($/).length - end - - def test_update_page_with_instance_variables - get :update_page_with_instance_variables - assert_template nil - assert_equal 'text/javascript; charset=utf-8', @response.headers['type'] - assert_match /balance/, @response.body - assert_match /\$37/, @response.body - end - - def test_yield_content_for - assert_not_deprecated { get :yield_content_for } - assert_equal "<title>Putting stuff in the title!</title>\n\nGreat stuff!\n", @response.body - end - - - def test_overwritting_rendering_relative_file_with_extension - get :hello_world_from_rxml_using_template - assert_equal "<html>\n <p>Hello</p>\n</html>\n", @response.body - - get :hello_world_from_rxml_using_action - assert_equal "<html>\n <p>Hello</p>\n</html>\n", @response.body - end - - - def test_head_with_location_header - get :head_with_location_header - assert @response.body.blank? - assert_equal "/foo", @response.headers["Location"] - assert_response :ok - end - - def test_head_with_custom_header - get :head_with_custom_header - assert @response.body.blank? - assert_equal "something", @response.headers["X-Custom-Header"] - assert_response :ok - end - - def test_head_with_symbolic_status - get :head_with_symbolic_status, :status => "ok" - assert_equal "200 OK", @response.headers["Status"] - assert_response :ok - - get :head_with_symbolic_status, :status => "not_found" - assert_equal "404 Not Found", @response.headers["Status"] - assert_response :not_found - - ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code| - get :head_with_symbolic_status, :status => status.to_s - assert_equal code, @response.response_code - assert_response status - end - end - - def test_head_with_integer_status - ActionController::StatusCodes::STATUS_CODES.each do |code, message| - get :head_with_integer_status, :status => code.to_s - assert_equal message, @response.message - end - end - - def test_head_with_string_status - get :head_with_string_status, :status => "404 Eat Dirt" - assert_equal 404, @response.response_code - assert_equal "Eat Dirt", @response.message - assert_response :not_found - end - - def test_head_with_status_code_first - get :head_with_status_code_first - assert_equal 403, @response.response_code - assert_equal "Forbidden", @response.message - assert_equal "something", @response.headers["X-Custom-Header"] - assert_response :forbidden - end - - def test_rendering_with_location_should_set_header - get :render_with_location - assert_equal "http://example.com", @response.headers["Location"] - end - - def test_rendering_xml_should_call_to_xml_if_possible - get :render_with_to_xml - assert_equal "<i-am-xml/>", @response.body - end - - def test_rendering_with_object_location_should_set_header_with_url_for - ActionController::Routing::Routes.draw do |map| - map.resources :customers - map.connect ':controller/:action/:id' - end - - get :render_with_object_location - assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] - end - - def test_render_call_to_partial_with_layout - get :render_call_to_partial_with_layout - assert_equal "Before (David)\nInside from partial (David)\nAfter", @response.body - end - - def test_render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout - get :render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout - assert_equal "Before (Anthony)\nInside from partial (Anthony)\nAfter\nBefore (David)\nInside from partial (David)\nAfter\nBefore (Ramm)\nInside from partial (Ramm)\nAfter", @response.body - end - - def test_using_layout_around_block - get :render_using_layout_around_block - assert_equal "Before (David)\nInside from block\nAfter", @response.body - end - - def test_using_layout_around_block_in_main_layout_and_within_content_for_layout - get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout - assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body - end - - def test_using_layout_around_block_with_args - get :render_using_layout_around_block_with_args - assert_equal "Before\narg1arg2\nAfter", @response.body - end -end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 3008f5ca03..af7b5dde62 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -8,7 +8,22 @@ module Fun end end +class MockLogger + attr_reader :logged + + def initialize + @logged = [] + end + + def method_missing(method, *args) + @logged << args.first + end +end + class TestController < ActionController::Base + class LabellingFormBuilder < ActionView::Helpers::FormBuilder + end + layout :determine_layout def hello_world @@ -58,6 +73,57 @@ class TestController < ActionController::Base render :text => "hello world" end + def render_text_hello_world_with_layout + @variable_for_layout = ", I'm here!" + render :text => "hello world", :layout => true + end + + def hello_world_with_layout_false + render :layout => false + end + + def render_file_with_instance_variables + @secret = 'in the sauce' + path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb') + render :file => path + end + + def render_file_not_using_full_path + @secret = 'in the sauce' + render :file => 'test/render_file_with_ivar' + end + + def render_file_not_using_full_path_with_dot_in_path + @secret = 'in the sauce' + render :file => 'test/dot.directory/render_file_with_ivar' + end + + def render_file_from_template + @secret = 'in the sauce' + @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')) + end + + def render_file_with_locals + path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb') + render :file => path, :locals => {:secret => 'in the sauce'} + end + + def accessing_request_in_template + render :inline => "Hello: <%= request.host %>" + end + + def accessing_logger_in_template + render :inline => "<%= logger.class %>" + end + + def accessing_action_name_in_template + render :inline => "<%= action_name %>" + end + + def accessing_controller_name_in_template + render :inline => "<%= controller_name %>" + end + def render_json_hello_world render :json => {:hello => 'world'}.to_json end @@ -126,7 +192,7 @@ class TestController < ActionController::Base end def builder_layout_test - render :action => "hello" + render :action => "hello", :layout => "layouts/builder" end def builder_partial_test @@ -168,8 +234,232 @@ class TestController < ActionController::Base @foo = render_to_string :inline => "this is a test" end - def partial - render :partial => 'partial' + def default_render + if @alternate_default_render + @alternate_default_render.call + else + render + end + end + + def render_action_hello_world_as_symbol + render :action => :hello_world + end + + def layout_test_with_different_layout + render :action => "hello_world", :layout => "standard" + end + + def rendering_without_layout + render :action => "hello_world", :layout => false + end + + def layout_overriding_layout + render :action => "hello_world", :layout => "standard" + end + + def rendering_nothing_on_layout + render :nothing => true + end + + def render_to_string_with_assigns + @before = "i'm before the render" + render_to_string :text => "foo" + @after = "i'm after the render" + render :action => "test/hello_world" + end + + def render_to_string_with_exception + render_to_string :file => "exception that will not be caught - this will certainly not work" + end + + def render_to_string_with_caught_exception + @before = "i'm before the render" + begin + render_to_string :file => "exception that will be caught- hope my future instance vars still work!" + rescue + end + @after = "i'm after the render" + render :action => "test/hello_world" + end + + def accessing_params_in_template_with_layout + render :layout => nil, :inline => "Hello: <%= params[:name] %>" + end + + def render_with_explicit_template + render :template => "test/hello_world" + end + + def render_with_explicit_template_with_locals + render :template => "test/render_file_with_locals", :locals => { :secret => 'area51' } + end + + def double_render + render :text => "hello" + render :text => "world" + end + + def double_redirect + redirect_to :action => "double_render" + redirect_to :action => "double_render" + end + + def render_and_redirect + render :text => "hello" + redirect_to :action => "double_render" + end + + def render_to_string_and_render + @stuff = render_to_string :text => "here is some cached stuff" + render :text => "Hi web users! #{@stuff}" + end + + def rendering_with_conflicting_local_vars + @name = "David" + def @template.name() nil end + render :action => "potential_conflicts" + end + + def hello_world_from_rxml_using_action + render :action => "hello_world_from_rxml.builder" + end + + def hello_world_from_rxml_using_template + render :template => "test/hello_world_from_rxml.builder" + end + + module RenderTestHelper + def rjs_helper_method_from_module + page.visual_effect :highlight + end + end + + helper RenderTestHelper + helper do + def rjs_helper_method(value) + page.visual_effect :highlight, value + end + end + + def enum_rjs_test + render :update do |page| + page.select('.product').each do |value| + page.rjs_helper_method_from_module + page.rjs_helper_method(value) + page.sortable(value, :url => { :action => "order" }) + page.draggable(value) + end + end + end + + def delete_with_js + @project_id = 4 + end + + def render_js_with_explicit_template + @project_id = 4 + render :template => 'test/delete_with_js' + end + + def render_js_with_explicit_action_template + @project_id = 4 + render :action => 'delete_with_js' + end + + def update_page + render :update do |page| + page.replace_html 'balance', '$37,000,000.00' + page.visual_effect :highlight, 'balance' + end + end + + def update_page_with_instance_variables + @money = '$37,000,000.00' + @div_id = 'balance' + render :update do |page| + page.replace_html @div_id, @money + page.visual_effect :highlight, @div_id + end + end + + def update_page_with_view_method + render :update do |page| + page.replace_html 'person', pluralize(2, 'person') + end + end + + def action_talk_to_layout + # Action template sets variable that's picked up by layout + end + + def render_text_with_assigns + @hello = "world" + render :text => "foo" + end + + def yield_content_for + render :action => "content_for", :layout => "yield" + end + + def render_content_type_from_body + response.content_type = Mime::RSS + render :text => "hello world!" + end + + def head_with_location_header + head :location => "/foo" + end + + def head_with_symbolic_status + head :status => params[:status].intern + end + + def head_with_integer_status + head :status => params[:status].to_i + end + + def head_with_string_status + head :status => params[:status] + end + + def head_with_custom_header + head :x_custom_header => "something" + end + + def head_with_status_code_first + head :forbidden, :x_custom_header => "something" + end + + def render_with_location + render :xml => "<hello/>", :location => "http://example.com", :status => 201 + end + + def render_with_object_location + customer = Customer.new("Some guy", 1) + render :xml => "<customer/>", :location => customer_url(customer), :status => :created + end + + def render_with_to_xml + to_xmlable = Class.new do + def to_xml + "<i-am-xml/>" + end + end.new + + render :xml => to_xmlable + end + + def render_using_layout_around_block + render :action => "using_layout_around_block" + end + + def render_using_layout_around_block_with_args + render :action => "using_layout_around_block_with_args" + end + + def render_using_layout_around_block_in_main_layout_and_within_content_for_layout + render :action => "using_layout_around_block", :layout => "layouts/block_with_layout" end def partial_dot_html @@ -192,12 +482,8 @@ class TestController < ActionController::Base end end - def default_render - if @alternate_default_render - @alternate_default_render.call - else - render - end + def partial + render :partial => 'partial' end def render_alternate_default @@ -209,14 +495,126 @@ class TestController < ActionController::Base end end - def rescue_action(e) raise end + def partial_only_with_layout + render :partial => "partial_only", :layout => true + end + + def render_to_string_with_partial + @partial_only = render_to_string :partial => "partial_only" + @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") } + render :action => "test/hello_world" + end + + def partial_with_counter + render :partial => "counter", :locals => { :counter_counter => 5 } + end + + def partial_with_locals + render :partial => "customer", :locals => { :customer => Customer.new("david") } + end + + def partial_with_form_builder + render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, @template, {}, Proc.new {}) + end + + def partial_with_form_builder_subclass + render :partial => LabellingFormBuilder.new(:post, nil, @template, {}, Proc.new {}) + end + + def partial_collection + render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ] + end + + def partial_collection_with_as + render :partial => "customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer + end + + def partial_collection_with_counter + render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ] + end + + def partial_collection_with_locals + render :partial => "customer_greeting", :collection => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } + end + + def partial_collection_with_spacer + render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ] + end + + def partial_collection_shorthand_with_locals + render :partial => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } + end + + def partial_collection_shorthand_with_different_types_of_records + render :partial => [ + BadCustomer.new("mark"), + GoodCustomer.new("craig"), + BadCustomer.new("john"), + GoodCustomer.new("zach"), + GoodCustomer.new("brandon"), + BadCustomer.new("dan") ], + :locals => { :greeting => "Bonjour" } + end + + def empty_partial_collection + render :partial => "customer", :collection => [] + end + + def partial_collection_shorthand_with_different_types_of_records_with_counter + partial_collection_shorthand_with_different_types_of_records + end + + def missing_partial + render :partial => 'thisFileIsntHere' + end + + def partial_with_hash_object + render :partial => "hash_object", :object => {:first_name => "Sam"} + end + + def partial_hash_collection + render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ] + end + + def partial_hash_collection_with_locals + render :partial => "hash_greeting", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ], :locals => { :greeting => "Hola" } + end + + def partial_with_implicit_local_assignment + @customer = Customer.new("Marcel") + render :partial => "customer" + end + + def render_call_to_partial_with_layout + render :action => "calling_partial_with_layout" + end + + def render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout + render :action => "calling_partial_with_layout", :layout => "layouts/partial_with_layout" + end + + def rescue_action(e) + raise + end private def determine_layout case action_name - when "layout_test"; "layouts/standard" - when "builder_layout_test"; "layouts/builder" - when "render_symbol_json"; "layouts/standard" # to make sure layouts don't interfere + when "hello_world", "layout_test", "rendering_without_layout", + "rendering_nothing_on_layout", "render_text_hello_world", + "render_text_hello_world_with_layout", + "hello_world_with_layout_false", + "partial_only", "partial_only_with_layout", + "accessing_params_in_template", + "accessing_params_in_template_with_layout", + "render_with_explicit_template", + "render_js_with_explicit_template", + "render_js_with_explicit_action_template", + "delete_with_js", "update_page", "update_page_with_instance_variables" + + "layouts/standard" + when "action_talk_to_layout", "layout_overriding_layout" + "layouts/talk_from_action" end end end @@ -227,13 +625,24 @@ class RenderTest < Test::Unit::TestCase @response = ActionController::TestResponse.new @controller = TestController.new + # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get + # a more accurate simulation of what happens in "real life". + @controller.logger = Logger.new(nil) + @request.host = "www.nextangle.com" end def test_simple_show get :hello_world assert_response 200 + assert_response :success assert_template "test/hello_world" + assert_equal "<html>Hello world!</html>", @response.body + end + + def test_renders_default_template_for_missing_action + get :'hyphen-ated' + assert_template 'test/hyphen-ated' end def test_render @@ -290,6 +699,41 @@ class RenderTest < Test::Unit::TestCase assert_equal "hello world", @response.body end + def test_do_with_render_text_and_layout + get :render_text_hello_world_with_layout + assert_equal "<html>hello world, I'm here!</html>", @response.body + end + + def test_do_with_render_action_and_layout_false + get :hello_world_with_layout_false + assert_equal 'Hello world!', @response.body + end + + def test_render_file_with_instance_variables + get :render_file_with_instance_variables + assert_equal "The secret is in the sauce\n", @response.body + end + + def test_render_file_not_using_full_path + get :render_file_not_using_full_path + assert_equal "The secret is in the sauce\n", @response.body + end + + def test_render_file_not_using_full_path_with_dot_in_path + get :render_file_not_using_full_path_with_dot_in_path + assert_equal "The secret is in the sauce\n", @response.body + end + + def test_render_file_with_locals + get :render_file_with_locals + assert_equal "The secret is in the sauce\n", @response.body + end + + def test_render_file_from_template + get :render_file_from_template + assert_equal "The secret is in the sauce\n", @response.body + end + def test_render_json get :render_json_hello_world assert_equal '{"hello": "world"}', @response.body @@ -317,6 +761,7 @@ class RenderTest < Test::Unit::TestCase def test_render_custom_code get :render_custom_code assert_response 404 + assert_response :missing assert_equal 'hello world', @response.body end @@ -355,6 +800,26 @@ class RenderTest < Test::Unit::TestCase assert_raises(ActionController::UnknownAction, "No action responded to [determine_layout]") { get :determine_layout } end + def test_access_to_request_in_view + get :accessing_request_in_template + assert_equal "Hello: www.nextangle.com", @response.body + end + + def test_access_to_logger_in_view + get :accessing_logger_in_template + assert_equal "Logger", @response.body + end + + def test_access_to_action_name_in_view + get :accessing_action_name_in_template + assert_equal "accessing_action_name_in_template", @response.body + end + + def test_access_to_controller_name_in_view + get :accessing_controller_name_in_template + assert_equal "test", @response.body # name is explicitly set to 'test' inside the controller. + end + def test_render_xml get :render_xml_hello assert_equal "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body @@ -371,6 +836,19 @@ class RenderTest < Test::Unit::TestCase assert_equal "<test>\n <hello/>\n</test>\n", @response.body end + def test_enum_rjs_test + get :enum_rjs_test + body = %{ + $$(".product").each(function(value, index) { + new Effect.Highlight(element,{}); + new Effect.Highlight(value,{}); + Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value)})}}); + new Draggable(value, {}); + }); + }.gsub(/^ /, '').strip + assert_equal body, @response.body + end + def test_layout_rendering get :layout_test assert_equal "<html>Hello world!</html>", @response.body @@ -381,14 +859,9 @@ class RenderTest < Test::Unit::TestCase assert_equal "<wrapper>\n<html>\n <p>Hello </p>\n<p>This is grand!</p>\n</html>\n</wrapper>\n", @response.body end - # def test_partials_list - # get :partials_list - # assert_equal "goodbyeHello: davidHello: marygoodbye\n", process_request.body - # end - - def test_partial_only - get :partial_only - assert_equal "only partial", @response.body + def test_partials_list + get :partials_list + assert_equal "goodbyeHello: davidHello: marygoodbye\n", @response.body end def test_render_to_string @@ -438,6 +911,252 @@ class RenderTest < Test::Unit::TestCase assert_equal '<test>passed formatted html erb</test>', @response.body end + def test_should_render_xml_but_keep_custom_content_type + get :render_xml_with_custom_content_type + assert_equal "application/atomsvc+xml", @response.content_type + end + + def test_render_with_default_from_accept_header + xhr :get, :greeting + assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body + end + + def test_render_rjs_with_default + get :delete_with_js + assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body + end + + def test_render_rjs_template_explicitly + get :render_js_with_explicit_template + assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body + end + + def test_rendering_rjs_action_explicitly + get :render_js_with_explicit_action_template + assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body + end + + def test_layout_test_with_different_layout + get :layout_test_with_different_layout + assert_equal "<html>Hello world!</html>", @response.body + end + + def test_rendering_without_layout + get :rendering_without_layout + assert_equal "Hello world!", @response.body + end + + def test_layout_overriding_layout + get :layout_overriding_layout + assert_no_match %r{<title>}, @response.body + end + + def test_rendering_nothing_on_layout + get :rendering_nothing_on_layout + assert_equal " ", @response.body + end + + def test_render_to_string + assert_not_deprecated { get :hello_in_a_string } + assert_equal "How's there? goodbyeHello: davidHello: marygoodbye\n", @response.body + end + + def test_render_to_string_doesnt_break_assigns + get :render_to_string_with_assigns + assert_equal "i'm before the render", assigns(:before) + assert_equal "i'm after the render", assigns(:after) + end + + def test_bad_render_to_string_still_throws_exception + assert_raises(ActionView::MissingTemplate) { get :render_to_string_with_exception } + end + + def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns + assert_nothing_raised { get :render_to_string_with_caught_exception } + assert_equal "i'm before the render", assigns(:before) + assert_equal "i'm after the render", assigns(:after) + end + + def test_accessing_params_in_template_with_layout + get :accessing_params_in_template_with_layout, :name => "David" + assert_equal "<html>Hello: David</html>", @response.body + end + + def test_render_with_explicit_template + get :render_with_explicit_template + assert_response :success + end + + def test_double_render + assert_raises(ActionController::DoubleRenderError) { get :double_render } + end + + def test_double_redirect + assert_raises(ActionController::DoubleRenderError) { get :double_redirect } + end + + def test_render_and_redirect + assert_raises(ActionController::DoubleRenderError) { get :render_and_redirect } + end + + # specify the one exception to double render rule - render_to_string followed by render + def test_render_to_string_and_render + get :render_to_string_and_render + assert_equal("Hi web users! here is some cached stuff", @response.body) + end + + def test_rendering_with_conflicting_local_vars + get :rendering_with_conflicting_local_vars + assert_equal("First: David\nSecond: Stephan\nThird: David\nFourth: David\nFifth: ", @response.body) + end + + def test_action_talk_to_layout + get :action_talk_to_layout + assert_equal "<title>Talking to the layout</title>\nAction was here!", @response.body + end + + def test_render_text_with_assigns + get :render_text_with_assigns + assert_equal "world", assigns["hello"] + end + + def test_template_with_locals + get :render_with_explicit_template_with_locals + assert_equal "The secret is area51\n", @response.body + end + + def test_update_page + get :update_page + assert_template nil + assert_equal 'text/javascript; charset=utf-8', @response.headers['type'] + assert_equal 2, @response.body.split($/).length + end + + def test_update_page_with_instance_variables + get :update_page_with_instance_variables + assert_template nil + assert_equal 'text/javascript; charset=utf-8', @response.headers['type'] + assert_match /balance/, @response.body + assert_match /\$37/, @response.body + end + + def test_update_page_with_view_method + get :update_page_with_view_method + assert_template nil + assert_equal 'text/javascript; charset=utf-8', @response.headers['type'] + assert_match /2 people/, @response.body + end + + def test_yield_content_for + assert_not_deprecated { get :yield_content_for } + assert_equal "<title>Putting stuff in the title!</title>\n\nGreat stuff!\n", @response.body + end + + def test_overwritting_rendering_relative_file_with_extension + get :hello_world_from_rxml_using_template + assert_equal "<html>\n <p>Hello</p>\n</html>\n", @response.body + + get :hello_world_from_rxml_using_action + assert_equal "<html>\n <p>Hello</p>\n</html>\n", @response.body + end + + def test_head_with_location_header + get :head_with_location_header + assert @response.body.blank? + assert_equal "/foo", @response.headers["Location"] + assert_response :ok + end + + def test_head_with_custom_header + get :head_with_custom_header + assert @response.body.blank? + assert_equal "something", @response.headers["X-Custom-Header"] + assert_response :ok + end + + def test_head_with_symbolic_status + get :head_with_symbolic_status, :status => "ok" + assert_equal "200 OK", @response.headers["Status"] + assert_response :ok + + get :head_with_symbolic_status, :status => "not_found" + assert_equal "404 Not Found", @response.headers["Status"] + assert_response :not_found + + ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code| + get :head_with_symbolic_status, :status => status.to_s + assert_equal code, @response.response_code + assert_response status + end + end + + def test_head_with_integer_status + ActionController::StatusCodes::STATUS_CODES.each do |code, message| + get :head_with_integer_status, :status => code.to_s + assert_equal message, @response.message + end + end + + def test_head_with_string_status + get :head_with_string_status, :status => "404 Eat Dirt" + assert_equal 404, @response.response_code + assert_equal "Eat Dirt", @response.message + assert_response :not_found + end + + def test_head_with_status_code_first + get :head_with_status_code_first + assert_equal 403, @response.response_code + assert_equal "Forbidden", @response.message + assert_equal "something", @response.headers["X-Custom-Header"] + assert_response :forbidden + end + + def test_rendering_with_location_should_set_header + get :render_with_location + assert_equal "http://example.com", @response.headers["Location"] + end + + def test_rendering_xml_should_call_to_xml_if_possible + get :render_with_to_xml + assert_equal "<i-am-xml/>", @response.body + end + + def test_rendering_with_object_location_should_set_header_with_url_for + ActionController::Routing::Routes.draw do |map| + map.resources :customers + map.connect ':controller/:action/:id' + end + + get :render_with_object_location + assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] + end + + def test_should_use_implicit_content_type + get :implicit_content_type, :format => 'atom' + assert_equal Mime::ATOM, @response.content_type + end + + def test_using_layout_around_block + get :render_using_layout_around_block + assert_equal "Before (David)\nInside from block\nAfter", @response.body + end + + def test_using_layout_around_block_in_main_layout_and_within_content_for_layout + get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout + assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body + end + + def test_using_layout_around_block_with_args + get :render_using_layout_around_block_with_args + assert_equal "Before\narg1arg2\nAfter", @response.body + end + + def test_partial_only + get :partial_only + assert_equal "only partial", @response.body + end + def test_should_render_html_formatted_partial get :partial assert_equal 'partial html', @response.body @@ -468,14 +1187,115 @@ class RenderTest < Test::Unit::TestCase assert_equal %(Element.replace("foo", "partial html");), @response.body end - def test_should_render_xml_but_keep_custom_content_type - get :render_xml_with_custom_content_type - assert_equal "application/atomsvc+xml", @response.content_type + def test_partial_only_with_layout + get :partial_only_with_layout + assert_equal "<html>only partial</html>", @response.body end - def test_should_use_implicit_content_type - get :implicit_content_type, :format => 'atom' - assert_equal Mime::ATOM, @response.content_type + def test_render_to_string_partial + get :render_to_string_with_partial + assert_equal "only partial", assigns(:partial_only) + assert_equal "Hello: david", assigns(:partial_with_locals) + end + + def test_partial_with_counter + get :partial_with_counter + assert_equal "5", @response.body + end + + def test_partial_with_locals + get :partial_with_locals + assert_equal "Hello: david", @response.body + end + + def test_partial_with_form_builder + get :partial_with_form_builder + assert_match(/<label/, @response.body) + assert_template('test/_form') + end + + def test_partial_with_form_builder_subclass + get :partial_with_form_builder_subclass + assert_match(/<label/, @response.body) + assert_template('test/_labelling_form') + end + + def test_partial_collection + get :partial_collection + assert_equal "Hello: davidHello: mary", @response.body + end + + def test_partial_collection_with_as + get :partial_collection_with_as + assert_equal "david david davidmary mary mary", @response.body + end + + def test_partial_collection_with_counter + get :partial_collection_with_counter + assert_equal "david0mary1", @response.body + end + + def test_partial_collection_with_locals + get :partial_collection_with_locals + assert_equal "Bonjour: davidBonjour: mary", @response.body + end + + def test_partial_collection_with_spacer + get :partial_collection_with_spacer + assert_equal "Hello: davidonly partialHello: mary", @response.body + end + + def test_partial_collection_shorthand_with_locals + get :partial_collection_shorthand_with_locals + assert_equal "Bonjour: davidBonjour: mary", @response.body + end + + def test_partial_collection_shorthand_with_different_types_of_records + get :partial_collection_shorthand_with_different_types_of_records + assert_equal "Bonjour bad customer: mark0Bonjour good customer: craig1Bonjour bad customer: john2Bonjour good customer: zach3Bonjour good customer: brandon4Bonjour bad customer: dan5", @response.body + end + + def test_empty_partial_collection + get :empty_partial_collection + assert_equal " ", @response.body + end + + def test_partial_with_hash_object + get :partial_with_hash_object + assert_equal "Sam\nmaS\n", @response.body + end + + def test_hash_partial_collection + get :partial_hash_collection + assert_equal "Pratik\nkitarP\nAmy\nymA\n", @response.body + end + + def test_partial_hash_collection_with_locals + get :partial_hash_collection_with_locals + assert_equal "Hola: PratikHola: Amy", @response.body + end + + def test_partial_with_implicit_local_assignment + assert_deprecated do + get :partial_with_implicit_local_assignment + assert_equal "Hello: Marcel", @response.body + end + end + + def test_render_missing_partial_template + assert_raises(ActionView::MissingTemplate) do + get :missing_partial + end + end + + def test_render_call_to_partial_with_layout + get :render_call_to_partial_with_layout + assert_equal "Before (David)\nInside from partial (David)\nAfter", @response.body + end + + def test_render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout + get :render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout + assert_equal "Before (Anthony)\nInside from partial (Anthony)\nAfter\nBefore (David)\nInside from partial (David)\nAfter\nBefore (Ramm)\nInside from partial (Ramm)\nAfter", @response.body end end @@ -501,6 +1321,12 @@ class EtagRenderTest < Test::Unit::TestCase assert @response.body.empty? end + def test_render_against_etag_request_should_have_no_content_length_when_match + @request.if_none_match = etag_for("hello david") + get :render_hello_world_from_variable + assert !@response.headers.has_key?("Content-Length") + end + def test_render_against_etag_request_should_200_when_no_match @request.if_none_match = etag_for("hello somewhere else") get :render_hello_world_from_variable @@ -577,3 +1403,21 @@ class LastModifiedRenderTest < Test::Unit::TestCase assert_equal @last_modified, @response.headers['Last-Modified'] end end + +class RenderingLoggingTest < Test::Unit::TestCase + def setup + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @controller = TestController.new + + @request.host = "www.nextangle.com" + end + + def test_logger_prints_layout_and_template_rendering_info + @controller.logger = MockLogger.new + get :layout_test + logged = @controller.logger.logged.find_all {|l| l =~ /render/i } + assert_equal "Rendering template within layouts/standard", logged[0] + assert_equal "Rendering test/hello_world", logged[1] + end +end diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index e153b0cc98..1fea82e564 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -264,6 +264,19 @@ class ResourcesTest < Test::Unit::TestCase end end + def test_array_as_collection_or_member_method_value + with_restful_routing :messages, :collection => { :search => [:get, :post] }, :member => { :toggle => [:get, :post] } do + assert_restful_routes_for :messages do |options| + [:get, :post].each do |method| + assert_recognizes(options.merge(:action => 'search'), :path => "/messages/search", :method => method) + end + [:get, :post].each do |method| + assert_recognizes(options.merge(:action => 'toggle', :id => '1'), :path => '/messages/1/toggle', :method => method) + end + end + end + end + def test_with_new_action with_restful_routing :messages, :new => { :preview => :post } do preview_options = {:action => 'preview'} @@ -366,6 +379,31 @@ class ResourcesTest < Test::Unit::TestCase end end + def test_shallow_nested_restful_routes + with_routing do |set| + set.draw do |map| + map.resources :threads, :shallow => true do |map| + map.resources :messages do |map| + map.resources :comments + end + end + end + + assert_simply_restful_for :threads, + :shallow => true + assert_simply_restful_for :messages, + :name_prefix => 'thread_', + :path_prefix => 'threads/1/', + :shallow => true, + :options => { :thread_id => '1' } + assert_simply_restful_for :comments, + :name_prefix => 'message_', + :path_prefix => 'messages/2/', + :shallow => true, + :options => { :message_id => '2' } + end + end + def test_restful_routes_dont_generate_duplicates with_restful_routing :messages do routes = ActionController::Routing::Routes.routes @@ -416,6 +454,32 @@ class ResourcesTest < Test::Unit::TestCase end end + def test_resources_has_many_hash_should_become_nested_resources + with_routing do |set| + set.draw do |map| + map.resources :threads, :has_many => { :messages => [ :comments, { :authors => :threads } ] } + end + + assert_simply_restful_for :threads + assert_simply_restful_for :messages, :name_prefix => "thread_", :path_prefix => 'threads/1/', :options => { :thread_id => '1' } + assert_simply_restful_for :comments, :name_prefix => "thread_message_", :path_prefix => 'threads/1/messages/1/', :options => { :thread_id => '1', :message_id => '1' } + assert_simply_restful_for :authors, :name_prefix => "thread_message_", :path_prefix => 'threads/1/messages/1/', :options => { :thread_id => '1', :message_id => '1' } + assert_simply_restful_for :threads, :name_prefix => "thread_message_author_", :path_prefix => 'threads/1/messages/1/authors/1/', :options => { :thread_id => '1', :message_id => '1', :author_id => '1' } + end + end + + def test_shallow_resource_has_many_should_become_shallow_nested_resources + with_routing do |set| + set.draw do |map| + map.resources :messages, :has_many => [ :comments, :authors ], :shallow => true + end + + assert_simply_restful_for :messages, :shallow => true + assert_simply_restful_for :comments, :name_prefix => "message_", :path_prefix => 'messages/1/', :shallow => true, :options => { :message_id => '1' } + assert_simply_restful_for :authors, :name_prefix => "message_", :path_prefix => 'messages/1/', :shallow => true, :options => { :message_id => '1' } + end + end + def test_resource_has_one_should_become_nested_resources with_routing do |set| set.draw do |map| @@ -427,6 +491,17 @@ class ResourcesTest < Test::Unit::TestCase end end + def test_shallow_resource_has_one_should_become_shallow_nested_resources + with_routing do |set| + set.draw do |map| + map.resources :messages, :has_one => :logo, :shallow => true + end + + assert_simply_restful_for :messages, :shallow => true + assert_singleton_restful_for :logo, :name_prefix => 'message_', :path_prefix => 'messages/1/', :shallow => true, :options => { :message_id => '1' } + end + end + def test_singleton_resource_with_member_action [:put, :post].each do |method| with_singleton_resources :account, :member => { :reset => method } do @@ -731,6 +806,13 @@ class ResourcesTest < Test::Unit::TestCase options[:options] ||= {} options[:options][:controller] = options[:controller] || controller_name.to_s + if options[:shallow] + options[:shallow_options] ||= {} + options[:shallow_options][:controller] = options[:options][:controller] + else + options[:shallow_options] = options[:options] + end + new_action = ActionController::Base.resources_path_names[:new] || "new" edit_action = ActionController::Base.resources_path_names[:edit] || "edit" if options[:path_names] @@ -738,8 +820,10 @@ class ResourcesTest < Test::Unit::TestCase edit_action = options[:path_names][:edit] if options[:path_names][:edit] end - collection_path = "/#{options[:path_prefix]}#{options[:as] || controller_name}" - member_path = "#{collection_path}/1" + path = "#{options[:as] || controller_name}" + collection_path = "/#{options[:path_prefix]}#{path}" + shallow_path = "/#{options[:path_prefix] unless options[:shallow]}#{path}" + member_path = "#{shallow_path}/1" new_path = "#{collection_path}/#{new_action}" edit_member_path = "#{member_path}/#{edit_action}" formatted_edit_member_path = "#{member_path}/#{edit_action}.xml" @@ -747,10 +831,13 @@ class ResourcesTest < Test::Unit::TestCase with_options(options[:options]) do |controller| controller.assert_routing collection_path, :action => 'index' controller.assert_routing new_path, :action => 'new' - controller.assert_routing member_path, :action => 'show', :id => '1' - controller.assert_routing edit_member_path, :action => 'edit', :id => '1' controller.assert_routing "#{collection_path}.xml", :action => 'index', :format => 'xml' controller.assert_routing "#{new_path}.xml", :action => 'new', :format => 'xml' + end + + with_options(options[:shallow_options]) do |controller| + controller.assert_routing member_path, :action => 'show', :id => '1' + controller.assert_routing edit_member_path, :action => 'edit', :id => '1' controller.assert_routing "#{member_path}.xml", :action => 'show', :id => '1', :format => 'xml' controller.assert_routing formatted_edit_member_path, :action => 'edit', :id => '1', :format => 'xml' end @@ -758,18 +845,18 @@ class ResourcesTest < Test::Unit::TestCase assert_recognizes(options[:options].merge(:action => 'index'), :path => collection_path, :method => :get) assert_recognizes(options[:options].merge(:action => 'new'), :path => new_path, :method => :get) assert_recognizes(options[:options].merge(:action => 'create'), :path => collection_path, :method => :post) - assert_recognizes(options[:options].merge(:action => 'show', :id => '1'), :path => member_path, :method => :get) - assert_recognizes(options[:options].merge(:action => 'edit', :id => '1'), :path => edit_member_path, :method => :get) - assert_recognizes(options[:options].merge(:action => 'update', :id => '1'), :path => member_path, :method => :put) - assert_recognizes(options[:options].merge(:action => 'destroy', :id => '1'), :path => member_path, :method => :delete) - - assert_recognizes(options[:options].merge(:action => 'index', :format => 'xml'), :path => "#{collection_path}.xml", :method => :get) - assert_recognizes(options[:options].merge(:action => 'new', :format => 'xml'), :path => "#{new_path}.xml", :method => :get) - assert_recognizes(options[:options].merge(:action => 'create', :format => 'xml'), :path => "#{collection_path}.xml", :method => :post) - assert_recognizes(options[:options].merge(:action => 'show', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :get) - assert_recognizes(options[:options].merge(:action => 'edit', :id => '1', :format => 'xml'), :path => formatted_edit_member_path, :method => :get) - assert_recognizes(options[:options].merge(:action => 'update', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :put) - assert_recognizes(options[:options].merge(:action => 'destroy', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :delete) + assert_recognizes(options[:shallow_options].merge(:action => 'show', :id => '1'), :path => member_path, :method => :get) + assert_recognizes(options[:shallow_options].merge(:action => 'edit', :id => '1'), :path => edit_member_path, :method => :get) + assert_recognizes(options[:shallow_options].merge(:action => 'update', :id => '1'), :path => member_path, :method => :put) + assert_recognizes(options[:shallow_options].merge(:action => 'destroy', :id => '1'), :path => member_path, :method => :delete) + + assert_recognizes(options[:options].merge(:action => 'index', :format => 'xml'), :path => "#{collection_path}.xml", :method => :get) + assert_recognizes(options[:options].merge(:action => 'new', :format => 'xml'), :path => "#{new_path}.xml", :method => :get) + assert_recognizes(options[:options].merge(:action => 'create', :format => 'xml'), :path => "#{collection_path}.xml", :method => :post) + assert_recognizes(options[:shallow_options].merge(:action => 'show', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :get) + assert_recognizes(options[:shallow_options].merge(:action => 'edit', :id => '1', :format => 'xml'), :path => formatted_edit_member_path, :method => :get) + assert_recognizes(options[:shallow_options].merge(:action => 'update', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :put) + assert_recognizes(options[:shallow_options].merge(:action => 'destroy', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :delete) yield options[:options] if block_given? end @@ -785,14 +872,24 @@ class ResourcesTest < Test::Unit::TestCase options[:options] ||= {} options[:options][:controller] = options[:controller] || controller_name.to_s + if options[:shallow] + options[:shallow_options] ||= {} + options[:shallow_options][:controller] = options[:options][:controller] + else + options[:shallow_options] = options[:options] + end + @controller = "#{options[:options][:controller].camelize}Controller".constantize.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new get :index, options[:options] options[:options].delete :action - full_prefix = "/#{options[:path_prefix]}#{options[:as] || controller_name}" + path = "#{options[:as] || controller_name}" + shallow_path = "/#{options[:path_prefix] unless options[:shallow]}#{path}" + full_path = "/#{options[:path_prefix]}#{path}" name_prefix = options[:name_prefix] + shallow_prefix = "#{options[:name_prefix] unless options[:shallow]}" new_action = "new" edit_action = "edit" @@ -801,15 +898,15 @@ class ResourcesTest < Test::Unit::TestCase edit_action = options[:path_names][:edit] || "edit" end - assert_named_route "#{full_prefix}", "#{name_prefix}#{controller_name}_path", options[:options] - assert_named_route "#{full_prefix}.xml", "formatted_#{name_prefix}#{controller_name}_path", options[:options].merge( :format => 'xml') - assert_named_route "#{full_prefix}/1", "#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1') - assert_named_route "#{full_prefix}/1.xml", "formatted_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') + assert_named_route "#{full_path}", "#{name_prefix}#{controller_name}_path", options[:options] + assert_named_route "#{full_path}.xml", "formatted_#{name_prefix}#{controller_name}_path", options[:options].merge(:format => 'xml') + assert_named_route "#{shallow_path}/1", "#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1') + assert_named_route "#{shallow_path}/1.xml", "formatted_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml') - assert_named_route "#{full_prefix}/#{new_action}", "new_#{name_prefix}#{singular_name}_path", options[:options] - assert_named_route "#{full_prefix}/#{new_action}.xml", "formatted_new_#{name_prefix}#{singular_name}_path", options[:options].merge( :format => 'xml') - assert_named_route "#{full_prefix}/1/#{edit_action}", "edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1') - assert_named_route "#{full_prefix}/1/#{edit_action}.xml", "formatted_edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') + assert_named_route "#{full_path}/#{new_action}", "new_#{name_prefix}#{singular_name}_path", options[:options] + assert_named_route "#{full_path}/#{new_action}.xml", "formatted_new_#{name_prefix}#{singular_name}_path", options[:options].merge(:format => 'xml') + assert_named_route "#{shallow_path}/1/#{edit_action}", "edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1') + assert_named_route "#{shallow_path}/1/#{edit_action}.xml", "formatted_edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml') yield options[:options] if block_given? end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 6cf134c26f..8bb1c49cbd 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1297,6 +1297,29 @@ uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do 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' + end + + @request = ActionController::TestRequest.new + @request.env["REQUEST_METHOD"] = 'POST' + @request.request_uri = "/match" + assert_nothing_raised { rs.recognize(@request) } + assert_equal 'get_or_post', @request.path_parameters[:action] + + # have to recreate or else the RouteSet uses a cached version: + @request = ActionController::TestRequest.new + @request.env["REQUEST_METHOD"] = 'PUT' + @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)) @@ -1671,6 +1694,12 @@ uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do controller.send(:multi_url, 7, "hello", 5, :baz => "bar") end + def test_named_route_url_method_with_ordered_parameters_and_empty_hash + controller = setup_named_route_test + assert_equal "http://named.route.test/people/go/7/hello/joe/5", + controller.send(:multi_url, 7, "hello", 5, {}) + end + def test_named_route_url_method_with_no_positional_arguments controller = setup_named_route_test assert_equal "http://named.route.test/people?baz=bar", diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index abc9f930dd..a1f541fd7b 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -79,6 +79,8 @@ class PrototypeHelperTest < PrototypeHelperBaseTest link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:false, evalScripts:true}); return false;\">Remote outauthor</a>), link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous) + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, insertion:'bottom'}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) end def test_link_to_remote_html_options @@ -91,6 +93,19 @@ class PrototypeHelperTest < PrototypeHelperBaseTest link_to_remote("Remote", { :url => { :action => "whatnot's" } }) end + def test_button_to_remote + assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true});\" />), + button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) + end + def test_periodically_call_remote assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>), periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb index 34a200b933..67aa047745 100644 --- a/actionpack/test/template/record_tag_helper_test.rb +++ b/actionpack/test/template/record_tag_helper_test.rb @@ -34,6 +34,14 @@ class RecordTagHelperTest < ActionView::TestCase assert_dom_equal expected, actual end + def test_block_not_in_erb_multiple_calls + expected = %(<div class="post bar" id="post_45">#{@post.body}</div>) + actual = div_for(@post, :class => "bar") { @post.body } + assert_dom_equal expected, actual + actual = div_for(@post, :class => "bar") { @post.body } + assert_dom_equal expected, actual + end + def test_block_works_with_content_tag_for_in_erb __in_erb_template = '' expected = %(<tr class="post" id="post_45">#{@post.body}</tr>) |