Browse files

Database connections are now pooled, one pool per #establish_connecti…

…on call.

Pools start out empty and grow as necessary to a maximum size (default is 5,
configure size with key 'pool' in your database configuration). If no
connections are available, a thread will wait up to a 'wait_timeout' time
(default is 5 seconds).

Connections are verified and reset when checked out from the pool (usually
upon first access to ActiveRecord::Base.connection), and returned back to the
pool after each request.

If you would like to use connection pools outside of ActionPack, there is an
ActiveRecord::Base.connection_pool method that gives you access to the pool,
and you can manually checkout/checkin connections, or supply a block to
ActiveRecord::Base.connection_pool.with_connection which takes care of the
checkout/checkin for you.

[#936 state:resolved]
  • Loading branch information...
2 parents 3007545 + ebfa43c commit 6f932b4790371e548c0df9033da96b2cf8f51dcc @jeremy jeremy committed Sep 2, 2008
Showing with 1,175 additions and 708 deletions.
  1. +0 −24 README.rdoc
  2. +5 −0 actionmailer/CHANGELOG
  3. +38 −7 actionmailer/lib/action_mailer/base.rb
  4. +2 −2 actionmailer/lib/action_mailer/helpers.rb
  5. +1 −0 actionmailer/test/fixtures/auto_layout_mailer/hello.html.erb
  6. +1 −0 actionmailer/test/fixtures/explicit_layout_mailer/logout.html.erb
  7. +1 −0 actionmailer/test/fixtures/explicit_layout_mailer/signup.html.erb
  8. +1 −0 actionmailer/test/fixtures/layouts/auto_layout_mailer.html.erb
  9. +1 −0 actionmailer/test/fixtures/layouts/spam.html.erb
  10. +78 −0 actionmailer/test/mail_layout_test.rb
  11. +52 −0 actionmailer/test/mail_service_test.rb
  12. +16 −0 actionpack/CHANGELOG
  13. +26 −52 actionpack/lib/action_controller/assertions/selector_assertions.rb
  14. +25 −63 actionpack/lib/action_controller/base.rb
  15. +2 −2 actionpack/lib/action_controller/caching/actions.rb
  16. +3 −3 actionpack/lib/action_controller/caching/sweeping.rb
  17. +3 −3 actionpack/lib/action_controller/cgi_process.rb
  18. +1 −1 actionpack/lib/action_controller/components.rb
  19. +4 −4 actionpack/lib/action_controller/filters.rb
  20. +2 −2 actionpack/lib/action_controller/helpers.rb
  21. +1 −1 actionpack/lib/action_controller/http_authentication.rb
  22. +4 −4 actionpack/lib/action_controller/integration.rb
  23. +21 −47 actionpack/lib/action_controller/layout.rb
  24. +3 −3 actionpack/lib/action_controller/polymorphic_routes.rb
  25. +0 −3 actionpack/lib/action_controller/rescue.rb
  26. +61 −12 actionpack/lib/action_controller/resources.rb
  27. +3 −2 actionpack/lib/action_controller/routing/optimisations.rb
  28. +3 −3 actionpack/lib/action_controller/routing/route_set.rb
  29. +12 −5 actionpack/lib/action_controller/test_process.rb
  30. +2 −2 actionpack/lib/action_controller/verification.rb
  31. +94 −76 actionpack/lib/action_view/base.rb
  32. +9 −1 actionpack/lib/action_view/helpers/prototype_helper.rb
  33. +1 −1 actionpack/lib/action_view/partials.rb
  34. +4 −4 actionpack/lib/action_view/renderable.rb
  35. +1 −1 actionpack/lib/action_view/template_handlers/builder.rb
  36. +1 −1 actionpack/lib/action_view/test_case.rb
  37. +5 −0 actionpack/test/controller/assert_select_test.rb
  38. +4 −4 actionpack/test/controller/base_test.rb
  39. +2 −2 actionpack/test/controller/filter_params_test.rb
  40. +13 −13 actionpack/test/controller/filters_test.rb
  41. +1 −1 actionpack/test/controller/integration_test.rb
  42. +0 −49 actionpack/test/controller/layout_test.rb
  43. +43 −0 actionpack/test/controller/render_test.rb
  44. +109 −25 actionpack/test/controller/resources_test.rb
  45. +6 −0 actionpack/test/controller/routing_test.rb
  46. +15 −0 actionpack/test/template/prototype_helper_test.rb
  47. +1 −1 activemodel/lib/active_model/validations.rb
  48. +2 −0 activerecord/CHANGELOG
  49. +5 −1 activerecord/lib/active_record/associations.rb
  50. +6 −2 activerecord/lib/active_record/named_scope.rb
  51. +2 −1 activerecord/lib/active_record/validations.rb
  52. +25 −9 activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
  53. +23 −7 activerecord/test/cases/associations/has_many_associations_test.rb
  54. +20 −0 activerecord/test/cases/associations/has_many_through_associations_test.rb
  55. +15 −0 activerecord/test/cases/named_scope_test.rb
  56. +33 −0 activerecord/test/cases/validations_i18n_test.rb
  57. +10 −5 activeresource/lib/active_resource/base.rb
  58. +18 −7 activeresource/lib/active_resource/connection.rb
  59. +12 −11 activeresource/lib/active_resource/custom_methods.rb
  60. +6 −6 activeresource/lib/active_resource/formats/json_format.rb
  61. +9 −9 activeresource/lib/active_resource/formats/xml_format.rb
  62. +1 −1 activeresource/lib/active_resource/http_mock.rb
  63. +8 −8 activeresource/test/authorization_test.rb
  64. +1 −2 activeresource/test/base/custom_methods_test.rb
  65. +2 −2 activeresource/test/base/load_test.rb
  66. +5 −5 activeresource/test/base_test.rb
  67. +1 −1 activeresource/test/connection_test.rb
  68. +23 −11 activeresource/test/format_test.rb
  69. +10 −1 activesupport/lib/active_support/core_ext/module.rb
  70. +71 −67 activesupport/lib/active_support/core_ext/module/aliasing.rb
  71. +79 −75 activesupport/lib/active_support/core_ext/module/introspection.rb
  72. +5 −5 activesupport/lib/active_support/core_ext/module/model_naming.rb
  73. +0 −5 activesupport/lib/active_support/core_ext/object/misc.rb
  74. +35 −0 activesupport/lib/active_support/core_ext/rexml.rb
  75. +1 −1 activesupport/lib/active_support/core_ext/time/zones.rb
  76. +1 −1 activesupport/lib/active_support/option_merger.rb
  77. +5 −1 activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb
  78. +1 −1 activesupport/lib/active_support/time_with_zone.rb
  79. +20 −17 activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb
  80. +2 −1 activesupport/test/buffered_logger_test.rb
  81. +25 −4 activesupport/test/core_ext/hash_ext_test.rb
  82. +0 −5 activesupport/test/core_ext/object_and_class_ext_test.rb
  83. +9 −9 activesupport/test/dependencies_test.rb
  84. +1 −1 railties/lib/initializer.rb
  85. +2 −2 railties/lib/tasks/documentation.rake
View
24 README.rdoc
@@ -1,24 +0,0 @@
-== About
-
-This is Nick's connection pool branch, wherein he attempts to rewrite Rails' connection handling code to
-be more thread-safe, and to add connection pooling features.
-
-== Goals
-
-- Preserve Rails' lazy connection acquisition and caching strategy behavior as it exists prior to this work.
-- Add ability to configure a connection pool to limit the number of connections made to a database in multiple-thread scenarios.
-- Threads will block for a configurable timeout if the pool is exhausted until a connection is available.
-- If none is available during the timeout period, an exception will be raised.
-- Add a checkout/checkin API to reserve and release a connection to/from the pool.
-- Add several different connection handling/pooling classes to serve different needs:
- - proper fixed-size connection pool
- - connection-per-thread with no maximum on the number of connections
- - single thread cached connection
- - pass-through to external connection pool (JRuby/JNDI data source connection pool)
-
-== TODO
-
-Remaining tasks:
-
-- Review and put the thing to real work.
-- Look at whether existing clear_* or verify_* methods can be deprecated or removed.
View
5 actionmailer/CHANGELOG
@@ -1,3 +1,8 @@
+* Add layout functionality to mailers [Pratik]
+
+ Mailer layouts behaves just like controller layouts, except layout names need to
+ have '_mailer' postfix for them to be automatically picked up.
+
*2.1.0 (May 31st, 2008)*
* Fixed that a return-path header would be ignored #7572 [joost]
View
45 actionmailer/lib/action_mailer/base.rb
@@ -246,7 +246,10 @@ module ActionMailer #:nodoc:
# +implicit_parts_order+.
class Base
include AdvAttrAccessor, PartContainer
- include ActionController::UrlWriter if Object.const_defined?(:ActionController)
+ if Object.const_defined?(:ActionController)
+ include ActionController::UrlWriter
+ include ActionController::Layout
+ end
private_class_method :new #:nodoc:
@@ -362,6 +365,7 @@ def mailer_name=(value)
# The mail object instance referenced by this mailer.
attr_reader :mail
+ attr_reader :template_name, :default_template_name, :action_name
class << self
attr_writer :mailer_name
@@ -374,11 +378,16 @@ def mailer_name
alias_method :controller_name, :mailer_name
alias_method :controller_path, :mailer_name
- def method_missing(method_symbol, *parameters)#:nodoc:
- case method_symbol.id2name
- when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
- when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
- when "new" then nil
+ def respond_to?(method_symbol, include_private = false) #:nodoc:
+ matches_dynamic_method?(method_symbol) || super
+ end
+
+ def method_missing(method_symbol, *parameters) #:nodoc:
+ match = matches_dynamic_method?(method_symbol)
+ case match[1]
+ when 'create' then new(match[2], *parameters).mail
+ when 'deliver' then new(match[2], *parameters).deliver!
+ when 'new' then nil
else super
end
end
@@ -424,6 +433,12 @@ def template_root
def template_root=(root)
self.view_paths = ActionView::Base.process_view_paths(root)
end
+
+ private
+ def matches_dynamic_method?(method_name) #:nodoc:
+ method_name = method_name.to_s
+ /(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
+ end
end
# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
@@ -519,6 +534,7 @@ def initialize_defaults(method_name)
@content_type ||= @@default_content_type.dup
@implicit_parts_order ||= @@default_implicit_parts_order.dup
@template ||= method_name
+ @default_template_name = @action_name = @template
@mailer_name ||= self.class.name.underscore
@parts ||= []
@headers ||= {}
@@ -535,7 +551,22 @@ def render(opts)
if opts[:file] && (opts[:file] !~ /\// && !opts[:file].respond_to?(:render))
opts[:file] = "#{mailer_name}/#{opts[:file]}"
end
- initialize_template_class(body).render(opts)
+
+ begin
+ old_template, @template = @template, initialize_template_class(body)
+ layout = respond_to?(:pick_layout, true) ? pick_layout(opts) : false
+ @template.render(opts.merge(:layout => layout))
+ ensure
+ @template = old_template
+ end
+ end
+
+ def default_template_format
+ :html
+ end
+
+ def candidate_for_layout?(options)
+ !@template.send(:_exempt_from_layout?, default_template_name)
end
def template_root
View
4 actionmailer/lib/action_mailer/helpers.rb
@@ -72,7 +72,7 @@ def helper_method(*methods)
methods.flatten.each do |method|
master_helper_module.module_eval <<-end_eval
def #{method}(*args, &block)
- controller.send!(%(#{method}), *args, &block)
+ controller.__send__(%(#{method}), *args, &block)
end
end_eval
end
@@ -92,7 +92,7 @@ def inherited_with_helper(child)
inherited_without_helper(child)
begin
child.master_helper_module = Module.new
- child.master_helper_module.send! :include, master_helper_module
+ child.master_helper_module.__send__(:include, master_helper_module)
child.helper child.name.to_s.underscore
rescue MissingSourceFile => e
raise unless e.is_missing?("helpers/#{child.name.to_s.underscore}_helper")
View
1 actionmailer/test/fixtures/auto_layout_mailer/hello.html.erb
@@ -0,0 +1 @@
+Inside
View
1 actionmailer/test/fixtures/explicit_layout_mailer/logout.html.erb
@@ -0,0 +1 @@
+You logged out
View
1 actionmailer/test/fixtures/explicit_layout_mailer/signup.html.erb
@@ -0,0 +1 @@
+We do not spam
View
1 actionmailer/test/fixtures/layouts/auto_layout_mailer.html.erb
@@ -0,0 +1 @@
+Hello from layout <%= yield %>
View
1 actionmailer/test/fixtures/layouts/spam.html.erb
@@ -0,0 +1 @@
+Spammer layout <%= yield %>
View
78 actionmailer/test/mail_layout_test.rb
@@ -0,0 +1,78 @@
+require 'abstract_unit'
+
+class AutoLayoutMailer < ActionMailer::Base
+ def hello(recipient)
+ recipients recipient
+ subject "You have a mail"
+ from "tester@example.com"
+ end
+
+ def spam(recipient)
+ recipients recipient
+ subject "You have a mail"
+ from "tester@example.com"
+ body render(:inline => "Hello, <%= @world %>", :layout => 'spam', :body => { :world => "Earth" })
+ end
+
+ def nolayout(recipient)
+ recipients recipient
+ subject "You have a mail"
+ from "tester@example.com"
+ body render(:inline => "Hello, <%= @world %>", :layout => false, :body => { :world => "Earth" })
+ end
+end
+
+class ExplicitLayoutMailer < ActionMailer::Base
+ layout 'spam', :except => [:logout]
+
+ def signup(recipient)
+ recipients recipient
+ subject "You have a mail"
+ from "tester@example.com"
+ end
+
+ def logout(recipient)
+ recipients recipient
+ subject "You have a mail"
+ from "tester@example.com"
+ end
+end
+
+class LayoutMailerTest < Test::Unit::TestCase
+ def setup
+ set_delivery_method :test
+ ActionMailer::Base.perform_deliveries = true
+ ActionMailer::Base.deliveries = []
+
+ @recipient = 'test@localhost'
+ end
+
+ def teardown
+ restore_delivery_method
+ end
+
+ def test_should_pickup_default_layout
+ mail = AutoLayoutMailer.create_hello(@recipient)
+ assert_equal "Hello from layout Inside", mail.body.strip
+ end
+
+ def test_should_pickup_layout_given_to_render
+ mail = AutoLayoutMailer.create_spam(@recipient)
+ assert_equal "Spammer layout Hello, Earth", mail.body.strip
+ end
+
+ def test_should_respect_layout_false
+ mail = AutoLayoutMailer.create_nolayout(@recipient)
+ assert_equal "Hello, Earth", mail.body.strip
+ end
+
+ def test_explicit_class_layout
+ mail = ExplicitLayoutMailer.create_signup(@recipient)
+ assert_equal "Spammer layout We do not spam", mail.body.strip
+ end
+
+ def test_explicit_layout_exceptions
+ mail = ExplicitLayoutMailer.create_logout(@recipient)
+ assert_equal "You logged out", mail.body.strip
+ end
+end
View
52 actionmailer/test/mail_service_test.rb
@@ -968,3 +968,55 @@ def test_send_method
end
end
end
+
+class RespondToTest < Test::Unit::TestCase
+ class RespondToMailer < ActionMailer::Base; end
+
+ def setup
+ set_delivery_method :test
+ end
+
+ def teardown
+ restore_delivery_method
+ end
+
+ def test_should_respond_to_new
+ assert RespondToMailer.respond_to?(:new)
+ end
+
+ def test_should_respond_to_create_with_template_suffix
+ assert RespondToMailer.respond_to?(:create_any_old_template)
+ end
+
+ def test_should_respond_to_deliver_with_template_suffix
+ assert RespondToMailer.respond_to?(:deliver_any_old_template)
+ end
+
+ def test_should_not_respond_to_new_with_template_suffix
+ assert !RespondToMailer.respond_to?(:new_any_old_template)
+ end
+
+ def test_should_not_respond_to_create_with_template_suffix_unless_it_is_separated_by_an_underscore
+ assert !RespondToMailer.respond_to?(:createany_old_template)
+ end
+
+ def test_should_not_respond_to_deliver_with_template_suffix_unless_it_is_separated_by_an_underscore
+ assert !RespondToMailer.respond_to?(:deliverany_old_template)
+ end
+
+ def test_should_not_respond_to_create_with_template_suffix_if_it_begins_with_a_uppercase_letter
+ assert !RespondToMailer.respond_to?(:create_Any_old_template)
+ end
+
+ def test_should_not_respond_to_deliver_with_template_suffix_if_it_begins_with_a_uppercase_letter
+ assert !RespondToMailer.respond_to?(:deliver_Any_old_template)
+ end
+
+ def test_should_not_respond_to_create_with_template_suffix_if_it_begins_with_a_digit
+ assert !RespondToMailer.respond_to?(:create_1_template)
+ end
+
+ def test_should_not_respond_to_deliver_with_template_suffix_if_it_begins_with_a_digit
+ assert !RespondToMailer.respond_to?(:deliver_1_template)
+ end
+end
View
16 actionpack/CHANGELOG
@@ -1,5 +1,21 @@
*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]
View
78 actionpack/lib/action_controller/assertions/selector_assertions.rb
@@ -396,54 +396,31 @@ def count_description(min, max) #:nodoc:
# # 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
@@ -588,26 +565,23 @@ def assert_select_email(&block)
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
@@ -621,8 +595,8 @@ def response_from_page_or_rjs()
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
""
View
88 actionpack/lib/action_controller/base.rb
@@ -260,10 +260,11 @@ class Base
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 @@ def self.relative_url_root
# 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 @@ def filter_parameter_logging(*filter_words, &block)
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 @@ def process(request, response, method = :perform_action, *arguments) #:nodoc:
assign_shortcuts(request, response)
initialize_current_url
assign_names
- forget_variables_added_to_assigns
log_processing
@@ -863,7 +850,7 @@ def render(options = nil, extra_options = {}, &block) #:doc:
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
@@ -874,6 +861,9 @@ def render(options = nil, extra_options = {}, &block) #:doc:
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
@@ -883,26 +873,21 @@ def render(options = nil, extra_options = {}, &block) #:doc:
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
@@ -916,12 +901,14 @@ def render(options = nil, extra_options = {}, &block) #:doc:
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
@@ -931,7 +918,7 @@ def render(options = nil, extra_options = {}, &block) #:doc:
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
@@ -942,7 +929,6 @@ def render_to_string(options = nil, &block) #:doc:
render(options, &block)
ensure
erase_render_results
- forget_variables_added_to_assigns
reset_variables_added_to_assigns
end
@@ -1127,10 +1113,9 @@ def reset_session #:doc:
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:
@@ -1165,7 +1150,6 @@ def assign_shortcuts(request, response)
@_session = @_response.session
@template = @_response.template
- @assigns = @_response.template.assigns
@_headers = @_response.headers
end
@@ -1229,27 +1213,10 @@ def self.action_methods
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
@@ -1265,12 +1232,7 @@ def close_session
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
View
4 actionpack/lib/action_controller/caching/actions.rb
@@ -90,7 +90,7 @@ def before(controller)
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 @@ def cache_layout?
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
View
6 actionpack/lib/action_controller/caching/sweeping.rb
@@ -83,13 +83,13 @@ def callback(timing)
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
View
6 actionpack/lib/action_controller/cgi_process.rb
@@ -48,7 +48,7 @@ class SessionFixationAttempt < StandardError #: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 @@ def reset_session
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 @@ def out(output = $stdout)
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
View
2 actionpack/lib/action_controller/components.rb
@@ -65,7 +65,7 @@ def process_with_components(request, response, parent_controller = nil) #:nodoc:
module HelperMethods
def render_component(options)
- @controller.send!(:render_component_as_string, options)
+ @controller.__send__(:render_component_as_string, options)
end
end
View
8 actionpack/lib/action_controller/filters.rb
@@ -199,8 +199,8 @@ def around_proc
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 @@ def before?
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
View
4 actionpack/lib/action_controller/helpers.rb
@@ -204,8 +204,8 @@ def inherited_with_helper(child)
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
View
2 actionpack/lib/action_controller/http_authentication.rb
@@ -117,7 +117,7 @@ def encode_credentials(user_name, password)
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
View
8 actionpack/lib/action_controller/integration.rb
@@ -444,7 +444,7 @@ def reset!
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 @@ def open_session
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 @@ def open_session
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
View
68 actionpack/lib/action_controller/layout.rb
@@ -3,11 +3,6 @@ module Layout #: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
@@ -221,10 +216,10 @@ def default_layout_with_format(format, layout)
# 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 @@ def active_layout(passed_layout = nil)
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 @@ def action_has_layout?
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
View
6 actionpack/lib/action_controller/polymorphic_routes.rb
@@ -108,7 +108,7 @@ def polymorphic_url(record_or_hash_or_array, options = {})
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,15 +149,15 @@ def build_named_route_call(records, namespace, inflection, options = {})
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
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
View
3 actionpack/lib/action_controller/rescue.rb
@@ -177,11 +177,8 @@ def local_request? #:doc:
# 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
View
73 actionpack/lib/action_controller/resources.rb
@@ -85,16 +85,24 @@ def new_path
@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 @@ def initialize(entity, options)
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
@@ -318,6 +328,31 @@ def initialize(entity, options)
# comments_url(@article)
# comment_url(@article, @comment)
#
+ # * <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:
@@ -443,7 +478,7 @@ def map_resource(entities, options = {}, &block)
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
@@ -460,21 +495,35 @@ def map_singleton_resource(entities, options = {}, &block)
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
@@ -530,13 +579,13 @@ def map_member_actions(map, resource)
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)
@@ -579,4 +628,4 @@ def action_options_for(action, resource, method = nil)
class ActionController::Routing::RouteSet::Mapper
include ActionController::Resources
-end
+end
View
5 actionpack/lib/action_controller/routing/optimisations.rb
@@ -103,9 +103,10 @@ def guard_condition
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
View
6 actionpack/lib/action_controller/routing/route_set.rb
@@ -115,7 +115,7 @@ def reset!
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,15 +353,15 @@ def generate(options, recall = {}, method=:generate)
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
# don't use the recalled keys when determining which routes to check
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
View
17 actionpack/lib/action_controller/test_process.rb
@@ -3,6 +3,8 @@
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 @@ def process_test(request) #: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 @@ def redirect_url_match?( pattern )
# 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 @@ def path #: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 @@ def process(action, parameters = nil, session = nil, flash = nil)
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 @@ def redirect_to_url
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)
View
4 actionpack/lib/action_controller/verification.rb
@@ -80,7 +80,7 @@ module ClassMethods
# 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 @@ def verify_request_xhr_status(options) # :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:
View
170 actionpack/lib/action_view/base.rb
@@ -162,7 +162,6 @@ class Base
attr_accessor :base_path, :assigns, :template_extension
attr_accessor :controller
- attr_accessor :_first_render, :_last_render
attr_writer :template_format
@@ -185,6 +184,17 @@ def self.cache_template_extensions=(*args)
"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 @@ def render(options = {}, local_assigns = {}, &block) #: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 @@ def template_format
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
View
10 actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -255,6 +255,14 @@ def link_to_remote(name, options = {}, html_options = nil)
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 @@ def options_for_ajax(options)
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]
View
2 actionpack/lib/action_view/partials.rb
@@ -196,7 +196,7 @@ def _pick_partial_template(partial_path) #:nodoc:
path = "_#{partial_path}"
end
- pick_template(path)
+ _pick_template(path)
end
memoize :_pick_partial_template
end
View
8 actionpack/lib/action_view/renderable.rb
@@ -26,11 +26,11 @@ def compiled_source
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")
View
2 actionpack/lib/action_view/template_handlers/builder.rb
@@ -6,7 +6,7 @@ class Builder < TemplateHandler
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 +
View
2 actionpack/lib/action_view/test_case.rb
@@ -54,7 +54,7 @@ def initialize
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
View
5 actionpack/test/controller/assert_select_test.rb
@@ -599,6 +599,11 @@ def test_assert_select_rjs_for_positioned_insert
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|
View
8 actionpack/test/controller/base_test.rb
@@ -84,11 +84,11 @@ def setup
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 @@ def hide_mocha_methods_from_controller(controller)
: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 @@ def test_get_on_priv_should_show_selector
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
View
4 actionpack/test/controller/filter_params_test.rb
@@ -27,7 +27,7 @@ def test_filter_parameters
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 @@ def test_filter_parameters
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
View
26 actionpack/test/controller/filters_test.rb
@@ -111,15 +111,15 @@ class BeforeAndAfterConditionController < ConditionalFilterController
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 ExceptConditionClassController < ConditionalFilterController
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,29 +225,29 @@ class AnotherChildOfConditionalParentController < ConditionalParentOfConditional
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
class AroundFilter
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 @@ def filter(controller)
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 @@ def filter(controller)
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
View
2 actionpack/test/controller/integration_test.rb
@@ -243,7 +243,7 @@ def test_integration_methods_called
reset!
stub_integration_session(@integration_session)
%w( get post head put delete ).each do |verb|
- assert_nothing_raised("'#{verb}' should use integration test methods