diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2010-03-15 19:46:03 +0000 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2010-03-15 19:46:03 +0000 |
commit | 03a62f4afedbef8bda72c8fdf9a0092273c0f2b0 (patch) | |
tree | 2155b65750757d26e3c8c8e0655ad32cc89d6c2e | |
parent | f53fddf3665e6582768f4ab0c82b286b39e7fb19 (diff) | |
parent | a594a22267bfd3346e00923742c4aa7edad0cef7 (diff) | |
download | rails-03a62f4afedbef8bda72c8fdf9a0092273c0f2b0.tar.gz rails-03a62f4afedbef8bda72c8fdf9a0092273c0f2b0.tar.bz2 rails-03a62f4afedbef8bda72c8fdf9a0092273c0f2b0.zip |
Merge remote branch 'mainstream/master'
53 files changed, 339 insertions, 288 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index ef3820ad67..f94e23fe05 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -605,7 +605,7 @@ module ActionMailer #:nodoc: each_template(templates_path, templates_name) do |template| responses << { - :body => render(:_template => template), + :body => render(:template => template), :content_type => template.mime_type.to_s } end diff --git a/actionmailer/lib/action_mailer/old_api.rb b/actionmailer/lib/action_mailer/old_api.rb index aeb653c5db..fb4b6701dd 100644 --- a/actionmailer/lib/action_mailer/old_api.rb +++ b/actionmailer/lib/action_mailer/old_api.rb @@ -207,7 +207,7 @@ module ActionMailer @parts.unshift create_inline_part(@body) elsif @parts.empty? || @parts.all? { |p| p.content_disposition =~ /^attachment/ } lookup_context.find_all(@template, @mailer_name).each do |template| - @parts << create_inline_part(render(:_template => template), template.mime_type) + @parts << create_inline_part(render(:template => template), template.mime_type) end if @parts.size > 1 diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index c1cf1f0157..f5fd12a6b0 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -2,6 +2,8 @@ require 'abstract_unit' class BaseTest < ActiveSupport::TestCase + # TODO Add some tests for implicity layout render and url helpers + # so we can get rid of old base tests altogether with old base. class BaseMailer < ActionMailer::Base self.mailer_name = "base_mailer" diff --git a/actionmailer/test/old_base/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb index 70dafaf33c..6d0b2c53a3 100644 --- a/actionmailer/test/old_base/mail_service_test.rb +++ b/actionmailer/test/old_base/mail_service_test.rb @@ -444,9 +444,6 @@ class ActionMailerTest < Test::Unit::TestCase expected.from = "system@loudthinking.com" expected.date = Time.local(2004, 12, 12) - # Stub the render method so no alternative renderers need be present. - ActionView::Base.any_instance.stubs(:render).returns("Hello there, \n\nMr. #{@recipient}") - # Now that the template is registered, there should be one part. The text/plain part. created = nil assert_nothing_raised { created = TestMailer.custom_templating_extension(@recipient) } diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 2da4dc052c..de95f935c2 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -12,6 +12,7 @@ require 'active_support/i18n' module AbstractController extend ActiveSupport::Autoload + autoload :Assigns autoload :Base autoload :Callbacks autoload :Collector diff --git a/actionpack/lib/abstract_controller/assigns.rb b/actionpack/lib/abstract_controller/assigns.rb new file mode 100644 index 0000000000..21459c6d51 --- /dev/null +++ b/actionpack/lib/abstract_controller/assigns.rb @@ -0,0 +1,21 @@ +module AbstractController + module Assigns + # This method should return a hash with assigns. + # You can overwrite this configuration per controller. + # :api: public + def view_assigns + hash = {} + variables = instance_variable_names + variables -= protected_instance_variables if respond_to?(:protected_instance_variables) + variables.each { |name| hash[name] = instance_variable_get(name) } + hash + end + + # This method assigns the hash specified in _assigns_hash to the given object. + # :api: private + # TODO Ideally, this should be done on AV::Base.new initialization. + def _evaluate_assigns(object) + view_assigns.each { |k,v| object.instance_variable_set(k, v) } + end + end +end
\ No newline at end of file diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 2f9616124a..95a6101109 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -284,6 +284,12 @@ module AbstractController layout = options.key?(:layout) ? options.delete(:layout) : :default value = _layout_for_option(layout) options[:layout] = (value =~ /\blayouts/ ? value : "layouts/#{value}") if value + + # TODO Layout for partials should be handled here, because inside the + # partial renderer it looks for the layout as a partial. + if options.key?(:partial) && options[:layout] + options[:layout] = view_context.find_layout(options[:layout]) + end end end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 42f4939108..16664098e5 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -31,6 +31,8 @@ module AbstractController module Rendering extend ActiveSupport::Concern + + include AbstractController::Assigns include AbstractController::ViewPaths # Overwrite process to setup I18n proxy. @@ -54,8 +56,8 @@ module AbstractController @_view_context ||= ActionView::Base.for_controller(self) end - # Mostly abstracts the fact that calling render twice is a DoubleRenderError. - # Delegates render_to_body and sticks the result in self.response_body. + # Normalize arguments, options and then delegates render_to_body and + # sticks the result in self.response_body. def render(*args, &block) options = _normalize_args(*args, &block) _normalize_options(options) @@ -78,8 +80,10 @@ module AbstractController end # Find and renders a template based on the options given. - def _render_template(options) - view_context.render_template(options) { |template| _with_template_hook(template) } + # :api: private + def _render_template(options) #:nodoc: + _evaluate_assigns(view_context) + view_context.render(options) end # The prefix used in render "foo" shortcuts. @@ -134,9 +138,5 @@ module AbstractController def _process_options(options) end - - def _with_template_hook(template) - self.formats = template.formats - end end end diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index c2a9f6336d..b331eb51b6 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -7,7 +7,7 @@ module AbstractController self._view_paths = ActionView::PathSet.new end - delegate :template_exists?, :view_paths, :formats, :formats=, + delegate :find_template, :template_exists?, :view_paths, :formats, :formats=, :locale, :locale=, :to => :lookup_context # LookupContext is the object responsible to hold all information required to lookup @@ -29,10 +29,6 @@ module AbstractController lookup_context.view_paths.unshift(*path) end - def template_exists?(*args) - lookup_context.exists?(*args) - end - module ClassMethods # Append a path to the list of view paths for this controller. # diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index fcd3cb9bd3..ad2b68af21 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -2,7 +2,6 @@ module ActionController class Base < Metal abstract! - include AbstractController::Callbacks include AbstractController::Layouts include AbstractController::Translation @@ -23,6 +22,7 @@ module ActionController # Rails 2.x compatibility include ActionController::Compatibility + include ActionController::ImplicitRender include ActionController::Cookies include ActionController::Flash @@ -36,8 +36,12 @@ module ActionController # Add instrumentations hooks at the bottom, to ensure they instrument # all the methods properly. include ActionController::Instrumentation - include ImplicitRender + # Before callbacks should also be executed the earliest as possible, so + # also include them at the bottom. + include AbstractController::Callbacks + + # The same with rescue, append it at the end to wrap as much as possible. include ActionController::Rescue def self.inherited(klass) diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index bb5ff95a67..89787727bd 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -41,9 +41,7 @@ module ActionController #:nodoc: else pos = buffer.length block.call - content = buffer[pos..-1] - content = content.as_str if content.respond_to?(:as_str) - write_fragment(name, content, options) + write_fragment(name, buffer[pos..-1], options) end else block.call @@ -53,9 +51,10 @@ module ActionController #:nodoc: # Writes <tt>content</tt> to the location signified by <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats) def write_fragment(key, content, options = nil) return content unless cache_configured? - key = fragment_cache_key(key) + key = fragment_cache_key(key) instrument_fragment_cache :write_fragment, key do + content = content.html_safe.to_str if content.respond_to?(:html_safe) cache_store.write(key, content, options) end content @@ -64,10 +63,11 @@ module ActionController #:nodoc: # Reads a cached fragment from the location signified by <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats) def read_fragment(key, options = nil) return unless cache_configured? - key = fragment_cache_key(key) + key = fragment_cache_key(key) instrument_fragment_cache :read_fragment, key do - cache_store.read(key, options) + result = cache_store.read(key, options) + result.respond_to?(:html_safe) ? result.html_safe : result end end diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index e70a20b2be..2ac199265d 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -261,6 +261,7 @@ module ActionController #:nodoc: block.call(collector) if block_given? if format = request.negotiate_mime(collector.order) + self.content_type ||= format.to_s self.formats = [format.to_sym] collector.response_for(format) else diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 49d3d6b466..08325b468c 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -87,8 +87,9 @@ module ActionController end add :update do |proc, options| + _evaluate_assigns(view_context) generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc) - self.content_type = Mime::JS + self.content_type = Mime::JS self.response_body = generator.to_s end end diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index f892bd9b91..86bb810947 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -5,26 +5,31 @@ module ActionController include ActionController::RackDelegation include AbstractController::Rendering - def process(*) + # Before processing, set the request formats in current controller formats. + def process_action(*) #:nodoc: self.formats = request.formats.map { |x| x.to_sym } super end - def render(*args) + # Check for double render errors and set the content_type after rendering. + def render(*args) #:nodoc: raise ::AbstractController::DoubleRenderError if response_body super + self.content_type ||= Mime[formats.first].to_s response_body end private - def _normalize_args(action=nil, options={}, &blk) + # Normalize arguments by catching blocks and setting them on :update. + def _normalize_args(action=nil, options={}, &blk) #:nodoc: options = super options[:update] = blk if block_given? options end - def _normalize_options(options) + # Normalize both text and status options. + def _normalize_options(options) #:nodoc: if options.key?(:text) && options[:text].respond_to?(:to_text) options[:text] = options[:text].to_text end @@ -36,7 +41,8 @@ module ActionController super end - def _process_options(options) + # Process controller specific options, as status, content-type and location. + def _process_options(options) #:nodoc: status, content_type, location = options.values_at(:status, :content_type, :location) self.status = status if status @@ -46,10 +52,5 @@ module ActionController super end - def _with_template_hook(template) - super - self.content_type ||= template.mime_type.to_s - end - end end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0b7b09ee7a..f9b27a5a03 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -362,11 +362,11 @@ module ActionDispatch attr_reader :plural, :singular, :options def initialize(entities, options = {}) - entities = entities.to_s + @name = entities.to_s @options = options - @plural = entities.pluralize - @singular = entities.singularize + @plural = @name.pluralize + @singular = @name.singularize end def default_actions @@ -393,7 +393,7 @@ module ActionDispatch end def name - options[:as] || plural + options[:as] || @name end def controller @@ -438,8 +438,8 @@ module ActionDispatch end end - def name - options[:as] || singular + def member_name + name end end @@ -468,8 +468,8 @@ module ActionDispatch post :create if resource.actions.include?(:create) put :update if resource.actions.include?(:update) delete :destroy if resource.actions.include?(:destroy) - get :new, :as => resource.singular if resource.actions.include?(:new) - get :edit, :as => resource.singular if resource.actions.include?(:edit) + get :new, :as => resource.name if resource.actions.include?(:new) + get :edit, :as => resource.name if resource.actions.include?(:edit) end end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index ffe3060404..feaf45c333 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -194,7 +194,7 @@ module ActionView #:nodoc: attr_accessor :base_path, :assigns, :template_extension, :lookup_context attr_internal :captures, :request, :layout, :controller, :template, :config - delegate :find, :exists?, :formats, :formats=, :locale, :locale=, + delegate :find_template, :template_exists?, :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, :with_fallbacks, :update_details, :to => :lookup_context delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, @@ -264,14 +264,5 @@ module ActionView #:nodoc: response.body_parts << part nil end - - # Evaluates the local assigns and controller ivars, pushes them to the view. - def _evaluate_assigns_and_ivars #:nodoc: - if controller - variables = controller.instance_variable_names - 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 - end end end diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index 4e12cdab54..e3db2923f7 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -129,7 +129,7 @@ module ActionView if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) && (errors = obj.errors[method]) content_tag("div", - (options[:prepend_text].html_safe << errors.first).safe_concat(options[:append_text]), + "#{options[:prepend_text]}#{ERB::Util.h(errors.first)}#{options[:append_text]}".html_safe, :class => options[:css_class] ) else diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 0c488b6793..03ae8ce0d8 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -242,12 +242,12 @@ module ActionView # == Caching multiple javascripts into one # # You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be - # compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching + # compressed by gzip (leading to faster transfers). Caching will only happen if config.perform_caching # is set to <tt>true</tt> (which is the case by default for the Rails production environment, but not for the development # environment). # # ==== Examples - # javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is false => + # javascript_include_tag :all, :cache => true # when config.perform_caching is false => # <script type="text/javascript" src="/javascripts/prototype.js"></script> # <script type="text/javascript" src="/javascripts/effects.js"></script> # ... @@ -255,15 +255,15 @@ module ActionView # <script type="text/javascript" src="/javascripts/shop.js"></script> # <script type="text/javascript" src="/javascripts/checkout.js"></script> # - # javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is true => + # javascript_include_tag :all, :cache => true # when config.perform_caching is true => # <script type="text/javascript" src="/javascripts/all.js"></script> # - # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is false => + # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is false => # <script type="text/javascript" src="/javascripts/prototype.js"></script> # <script type="text/javascript" src="/javascripts/cart.js"></script> # <script type="text/javascript" src="/javascripts/checkout.js"></script> # - # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is true => + # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is true => # <script type="text/javascript" src="/javascripts/shop.js"></script> # # The <tt>:recursive</tt> option is also available for caching: @@ -275,11 +275,11 @@ module ActionView cache = concat || options.delete("cache") recursive = options.delete("recursive") - if concat || (ActionController::Base.perform_caching && cache) + if concat || (config.perform_caching && cache) joined_javascript_name = (cache == true ? "all" : cache) + ".js" joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.javascripts_dir, joined_javascript_name) - unless ActionController::Base.perform_caching && File.exists?(joined_javascript_path) + unless config.perform_caching && File.exists?(joined_javascript_path) write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) end javascript_src_tag(joined_javascript_name, options) @@ -390,25 +390,25 @@ module ActionView # == Caching multiple stylesheets into one # # You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be - # compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching + # compressed by gzip (leading to faster transfers). Caching will only happen if config.perform_caching # is set to true (which is the case by default for the Rails production environment, but not for the development # environment). Examples: # # ==== Examples - # stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is false => + # stylesheet_link_tag :all, :cache => true # when config.perform_caching is false => # <link href="/stylesheets/style1.css" media="screen" rel="stylesheet" type="text/css" /> # <link href="/stylesheets/styleB.css" media="screen" rel="stylesheet" type="text/css" /> # <link href="/stylesheets/styleX2.css" media="screen" rel="stylesheet" type="text/css" /> # - # stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is true => + # stylesheet_link_tag :all, :cache => true # when config.perform_caching is true => # <link href="/stylesheets/all.css" media="screen" rel="stylesheet" type="text/css" /> # - # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when ActionController::Base.perform_caching is false => + # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is false => # <link href="/stylesheets/shop.css" media="screen" rel="stylesheet" type="text/css" /> # <link href="/stylesheets/cart.css" media="screen" rel="stylesheet" type="text/css" /> # <link href="/stylesheets/checkout.css" media="screen" rel="stylesheet" type="text/css" /> # - # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when ActionController::Base.perform_caching is true => + # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is true => # <link href="/stylesheets/payment.css" media="screen" rel="stylesheet" type="text/css" /> # # The <tt>:recursive</tt> option is also available for caching: @@ -426,11 +426,11 @@ module ActionView cache = concat || options.delete("cache") recursive = options.delete("recursive") - if concat || (ActionController::Base.perform_caching && cache) + if concat || (config.perform_caching && cache) joined_stylesheet_name = (cache == true ? "all" : cache) + ".css" joined_stylesheet_path = File.join(joined_stylesheet_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.stylesheets_dir, joined_stylesheet_name) - unless ActionController::Base.perform_caching && File.exists?(joined_stylesheet_path) + unless config.perform_caching && File.exists?(joined_stylesheet_path) write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) end stylesheet_tag(joined_stylesheet_name, options) diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 75fc2fddeb..03c7ba5a87 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -140,7 +140,7 @@ module ActionView def with_output_buffer(buf = nil) #:nodoc: unless buf buf = ActionView::OutputBuffer.new - buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding) + buf.force_encoding(output_buffer.encoding) if output_buffer && buf.respond_to?(:force_encoding) end self.output_buffer, old_buffer = buf, output_buffer yield diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 4d6ea7dfb2..dc3c6d88f5 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -180,7 +180,6 @@ module ActionView # #include_helpers_from_context has nothing to overwrite. class JavaScriptGenerator #:nodoc: def initialize(context, &block) #:nodoc: - context._evaluate_assigns_and_ivars @context, @lines = context, [] @context.update_details(:formats => [:js, :html]) do include_helpers_from_context diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 8ae2e5f28f..9b4cacd4d7 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -109,7 +109,7 @@ module ActionView def content_tag_string(name, content, options, escape = true) tag_options = tag_options(options, escape) if options - ("<#{name}#{tag_options}>".html_safe << content.to_s).safe_concat("</#{name}>") + "<#{name}#{tag_options}>#{ERB::Util.h(content)}</#{name}>".html_safe end def tag_options(options, escape = true) diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index ae1385f3b7..131e950b18 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -224,7 +224,7 @@ module ActionView end href_attr = "href=\"#{url}\"" unless href - ("<a #{href_attr}#{tag_options}>".html_safe << (name || url)).safe_concat("</a>") + "<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe end end diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 27ee8b23c9..8eb17bf8f1 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -38,17 +38,18 @@ module ActionView register_detail(:locale) { [I18n.locale] } class DetailsKey #:nodoc: - attr_reader :details alias :eql? :equal? + alias :object_hash :hash + attr_reader :hash @details_keys = Hash.new def self.get(details) - @details_keys[details] ||= new(details) + @details_keys[details] ||= new end - def initialize(details) - @details, @hash = details, details.hash + def initialize + @hash = object_hash end end @@ -70,6 +71,7 @@ module ActionView def find(name, prefix = nil, partial = false) @view_paths.find(name, prefix, partial, details, details_key) end + alias :find_template :find def find_all(name, prefix = nil, partial = false) @view_paths.find_all(name, prefix, partial, details, details_key) @@ -78,6 +80,7 @@ module ActionView def exists?(name, prefix = nil, partial = false) @view_paths.exists?(name, prefix, partial, details, details_key) end + alias :template_exists? :exists? # Add fallbacks to the view paths. Useful in cases you are rendering a :file. def with_fallbacks diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb index e9252dba9e..11ff05ce5b 100644 --- a/actionpack/lib/action_view/render/layouts.rb +++ b/actionpack/lib/action_view/render/layouts.rb @@ -1,8 +1,5 @@ -require 'active_support/core_ext/object/try' - module ActionView module Layouts - # You can think of a layout as a method that is called with a block. _layout_for # returns the contents that are yielded to the layout. If the user calls yield # :some_name, the block, by default, returns content_for(:some_name). If the user @@ -46,13 +43,13 @@ module ActionView # This is the method which actually finds the layout using details in the lookup # context object. If no layout is found, it checkes if at least a layout with # the given name exists across all details before raising the error. - def _find_layout(layout) #:nodoc: + def find_layout(layout) #:nodoc: begin layout =~ /^\// ? - with_fallbacks { find(layout) } : find(layout) + with_fallbacks { find_template(layout) } : find_template(layout) rescue ActionView::MissingTemplate => e update_details(:formats => nil) do - raise unless exists?(layout) + raise unless template_exists?(layout) end end end diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index d34ab0354c..17d16556b9 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -294,7 +294,7 @@ module ActionView def find_template(path=@path) return path unless path.is_a?(String) prefix = @view.controller_path unless path.include?(?/) - @view.find(path, prefix, true) + @view.find_template(path, prefix, true) end def partial_path(object = @object) diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 47ea70f5ad..310efe40e2 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -12,14 +12,18 @@ module ActionView # # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter # as the locals hash. - def render(options = {}, locals = {}, &block) #:nodoc: + def render(options = {}, locals = {}, &block) case options when Hash if block_given? content = _render_partial(options.merge(:partial => options[:layout]), &block) safe_concat(content) + elsif options.key?(:partial) + _render_partial(options) else - _render(options) + template = _determine_template(options) + self.formats = template.formats + _render_template(template, options[:layout], options) end when :update update_page(&block) @@ -28,44 +32,18 @@ module ActionView end end - # This is the API to render a ViewContext's template from a controller. - def render_template(options, &block) - _evaluate_assigns_and_ivars - - # TODO Layout for partials should be handled here, because inside the - # partial renderer it looks for the layout as a partial. - if options.key?(:partial) && options[:layout] - options[:layout] = _find_layout(options[:layout]) - end - - _render(options, &block) - end - - # This method holds the common render logic for both controllers and - # views rendering stacks. - def _render(options) #:nodoc: - if options.key?(:partial) - _render_partial(options) - else - template = _determine_template(options) - yield template if block_given? - _render_template(template, options[:layout], options) - end - end - # Determine the template to be rendered using the given options. def _determine_template(options) #:nodoc: if options.key?(:inline) handler = Template.handler_class_for_extension(options[:type] || "erb") Template.new(options[:inline], "inline template", handler, {}) elsif options.key?(:text) - Template::Text.new(options[:text], self.formats.try(:first)) - elsif options.key?(:_template) - options[:_template] + Template::Text.new(options[:text], formats.try(:first)) elsif options.key?(:file) - with_fallbacks { find(options[:file], options[:prefix]) } + with_fallbacks { find_template(options[:file], options[:prefix]) } elsif options.key?(:template) - find(options[:template], options[:prefix]) + options[:template].respond_to?(:render) ? + options[:template] : find_template(options[:template], options[:prefix]) end end @@ -73,7 +51,7 @@ module ActionView # supplied as well. def _render_template(template, layout = nil, options = {}) #:nodoc: locals = options[:locals] || {} - layout = _find_layout(layout) if layout + layout = find_layout(layout) if layout ActiveSupport::Notifications.instrument("action_view.render_template", :identifier => template.identifier, :layout => layout.try(:identifier)) do @@ -89,6 +67,5 @@ module ActionView content end end - end end diff --git a/actionpack/lib/action_view/template/handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb index 63e7dc0902..128be5077c 100644 --- a/actionpack/lib/action_view/template/handlers/rjs.rb +++ b/actionpack/lib/action_view/template/handlers/rjs.rb @@ -6,8 +6,7 @@ module ActionView self.default_format = Mime::JS def compile(template) - "controller.response.content_type ||= Mime::JS;" + - "update_page do |page|;#{template.source}\nend" + "update_page do |page|;#{template.source}\nend" end def default_format diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index df394b0fb0..269340514c 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -1,10 +1,12 @@ module ActionView #:nodoc: class Template class Text < String #:nodoc: - def initialize(string, content_type = nil) + attr_accessor :mime_type + + def initialize(string, mime_type = nil) super(string.to_s) - @content_type = Mime[content_type] || content_type if content_type - @content_type ||= Mime::TEXT + @mime_type = Mime[mime_type] || mime_type if mime_type + @mime_type ||= Mime::TEXT end def identifier @@ -19,12 +21,8 @@ module ActionView #:nodoc: to_s end - def mime_type - @content_type - end - def formats - [@content_type.to_sym] + [@mime_type.to_sym] end def partial? diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index 65a50807fd..f580ad40f7 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -8,210 +8,158 @@ module AbstractControllerTests include AbstractController::Rendering include AbstractController::Layouts - def _prefix - "template" - end - self.view_paths = [ActionView::FixtureResolver.new( - "abstract_controller_tests/layouts/with_string_implied_child.erb" => - "With Implied <%= yield %>", "layouts/hello.erb" => "With String <%= yield %>", "layouts/hello_override.erb" => "With Override <%= yield %>", "layouts/overwrite.erb" => "Overwrite <%= yield %>", - "layouts/with_false_layout.erb" => "False Layout <%= yield %>" + "layouts/with_false_layout.erb" => "False Layout <%= yield %>", + "abstract_controller_tests/layouts/with_string_implied_child.erb" => + "With Implied <%= yield %>" )] end - + class Blank < Base - self.view_paths = ActionView::FixtureResolver.new("template/index.erb" => "Hello blank!") + self.view_paths = [] def index - render + render :template => ActionView::Template::Text.new("Hello blank!") end end - + class WithString < Base layout "hello" - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello string!", - "template/overwrite_default.erb" => "Hello string!", - "template/overwrite_false.erb" => "Hello string!", - "template/overwrite_string.erb" => "Hello string!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello string!") end def overwrite_default - render :layout => :default + render :template => ActionView::Template::Text.new("Hello string!"), :layout => :default end def overwrite_false - render :layout => false + render :template => ActionView::Template::Text.new("Hello string!"), :layout => false end def overwrite_string - render :layout => "overwrite" + render :template => ActionView::Template::Text.new("Hello string!"), :layout => "overwrite" end def overwrite_skip render :text => "Hello text!" end end - + class WithStringChild < WithString end - + class WithStringOverriddenChild < WithString layout "hello_override" end - + class WithNilChild < WithString layout nil - end - + end + class WithStringImpliedChild < WithString end - + class WithChildOfImplied < WithStringImpliedChild end class WithProc < Base layout proc { |c| "overwrite" } - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello proc!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello proc!") end end class WithSymbol < Base layout :hello - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello symbol!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello symbol!") end - private - def hello "overwrite" end end - + class WithSymbolReturningString < Base layout :no_hello - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello missing symbol!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello missing symbol!") end - private - def no_hello nil end end - + class WithSymbolReturningNil < Base layout :nilz - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello nilz!" - ) - def index - render - end - - def nilz + render :template => ActionView::Template::Text.new("Hello nilz!") end + + def nilz() end end - + class WithSymbolReturningObj < Base layout :objekt - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello object!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello nilz!") end - + def objekt Object.new end - end - + end + class WithSymbolAndNoMethod < Base layout :no_method - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello boom!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello boom!") end end - + class WithMissingLayout < Base layout "missing" - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello missing!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello missing!") end end - + class WithFalseLayout < Base layout false - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello false!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello false!") end end - + class WithNilLayout < Base layout nil - append_view_path ActionView::FixtureResolver.new( - "template/index.erb" => "Hello nil!" - ) - def index - render + render :template => ActionView::Template::Text.new("Hello nil!") end end - + class TestBase < ActiveSupport::TestCase test "when no layout is specified, and no default is available, render without a layout" do controller = Blank.new controller.process(:index) assert_equal "Hello blank!", controller.response_body end - + test "when layout is specified as a string, render with that layout" do controller = WithString.new controller.process(:index) @@ -245,13 +193,13 @@ module AbstractControllerTests test "when layout is specified as a string, but the layout is missing, raise an exception" do assert_raises(ActionView::MissingTemplate) { WithMissingLayout.new.process(:index) } end - + test "when layout is specified as false, do not use a layout" do controller = WithFalseLayout.new controller.process(:index) assert_equal "Hello false!", controller.response_body end - + test "when layout is specified as nil, do not use a layout" do controller = WithNilLayout.new controller.process(:index) @@ -263,58 +211,58 @@ module AbstractControllerTests controller.process(:index) assert_equal "Overwrite Hello proc!", controller.response_body end - + test "when layout is specified as a symbol, call the requested method and use the layout returned" do controller = WithSymbol.new controller.process(:index) assert_equal "Overwrite Hello symbol!", controller.response_body end - + test "when layout is specified as a symbol and the method returns nil, don't use a layout" do controller = WithSymbolReturningNil.new controller.process(:index) assert_equal "Hello nilz!", controller.response_body end - + test "when the layout is specified as a symbol and the method doesn't exist, raise an exception" do assert_raises(NoMethodError) { WithSymbolAndNoMethod.new.process(:index) } end - + test "when the layout is specified as a symbol and the method returns something besides a string/false/nil, raise an exception" do assert_raises(ArgumentError) { WithSymbolReturningObj.new.process(:index) } end - + test "when a child controller does not have a layout, use the parent controller layout" do controller = WithStringChild.new controller.process(:index) assert_equal "With String Hello string!", controller.response_body end - + test "when a child controller has specified a layout, use that layout and not the parent controller layout" do controller = WithStringOverriddenChild.new controller.process(:index) assert_equal "With Override Hello string!", controller.response_body end - + test "when a child controller has an implied layout, use that layout and not the parent controller layout" do controller = WithStringImpliedChild.new controller.process(:index) assert_equal "With Implied Hello string!", controller.response_body end - + test "when a child controller specifies layout nil, do not use the parent layout" do controller = WithNilChild.new controller.process(:index) assert_equal "Hello string!", controller.response_body end - + test "when a grandchild has no layout specified, the child has an implied layout, and the " \ "parent has specified a layout, use the child controller layout" do controller = WithChildOfImplied.new controller.process(:index) assert_equal "With Implied Hello string!", controller.response_body end - + test "raises an exception when specifying layout true" do assert_raises ArgumentError do Object.class_eval do @@ -326,4 +274,4 @@ module AbstractControllerTests end end end -end +end
\ No newline at end of file diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index a3c8fdbb6e..a792752ef4 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -634,6 +634,19 @@ class FragmentCachingTest < ActionController::TestCase assert_equal 'generated till now -> fragment content', buffer end + def test_html_safety + assert_nil @store.read('views/name') + content = 'value'.html_safe + assert_equal content, @controller.write_fragment('name', content) + + cached = @store.read('views/name') + assert_equal content, cached + assert_equal String, cached.class + + html_safe = @controller.read_fragment('name') + assert_equal content, html_safe + assert html_safe.html_safe? + end end class FunctionalCachingController < CachingController diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index e3c4869391..20fcb87da6 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -617,6 +617,15 @@ class TestController < ActionController::Base raise end + before_filter :only => :render_with_filters do + request.format = :xml + end + + # Ensure that the before filter is executed *before* self.formats is set. + def render_with_filters + render :action => :formatted_xml_erb + end + private def determine_layout @@ -1034,6 +1043,11 @@ class RenderTest < ActionController::TestCase assert_equal "<html>Hello world!</html>", @response.body end + def test_render_with_filters + get :render_with_filters + assert_equal "<test>passed formatted xml erb</test>", @response.body + end + # :ported: def test_double_render assert_raise(ActionController::DoubleRenderError) { get :double_render } diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index f60045bba6..17c645c04c 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -16,6 +16,7 @@ class AccountsController < ResourcesController; end class AdminController < ResourcesController; end class ProductsController < ResourcesController; end class ImagesController < ResourcesController; end +class PreferencesController < ResourcesController; end module Backoffice class ProductsController < ResourcesController; end @@ -1125,6 +1126,12 @@ class ResourcesTest < ActionController::TestCase end end + def test_singleton_resource_name_is_not_singularized + with_singleton_resources(:preferences) do + assert_singleton_restful_for :preferences + end + end + protected def with_restful_routing(*args) with_routing do |set| diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index d9a89959da..c471df861d 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -50,7 +50,7 @@ class AssetTagHelperTest < ActionView::TestCase end def teardown - ActionController::Base.perform_caching = false + config.perform_caching = false ENV.delete('RAILS_ASSET_ID') end @@ -141,7 +141,6 @@ class AssetTagHelperTest < ActionView::TestCase ImageLinkToTag = { %(image_tag("xml.png")) => %(<img alt="Xml" src="/images/xml.png" />), - %(image_tag("..jpg")) => %(<img alt="..jpg" src="/images/..jpg" />), %(image_tag("rss.gif", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/images/rss.gif" />), %(image_tag("gold.png", :size => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />), %(image_tag("gold.png", "size" => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />), @@ -422,7 +421,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_when_caching_on ENV["RAILS_ASSET_ID"] = "" @controller.config.asset_host = 'http://a0.example.com' - ActionController::Base.perform_caching = true + config.perform_caching = true assert_dom_equal( %(<script src="http://a0.example.com/javascripts/all.js" type="text/javascript"></script>), @@ -454,7 +453,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_when_caching_on_with_proc_asset_host ENV['RAILS_ASSET_ID'] = '' @controller.config.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" } - ActionController::Base.perform_caching = true + config.perform_caching = true assert_equal '/javascripts/scripts.js'.length, 23 assert_dom_equal( @@ -477,7 +476,7 @@ class AssetTagHelperTest < ActionView::TestCase "#{request.protocol}assets#{source.length}.example.com" end } - ActionController::Base.perform_caching = true + config.perform_caching = true assert_equal '/javascripts/vanilla.js'.length, 23 assert_dom_equal( @@ -517,7 +516,7 @@ class AssetTagHelperTest < ActionView::TestCase end end.new - ActionController::Base.perform_caching = true + config.perform_caching = true assert_equal '/javascripts/vanilla.js'.length, 23 assert_dom_equal( @@ -548,7 +547,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_when_caching_on_and_using_subdirectory ENV["RAILS_ASSET_ID"] = "" @controller.config.asset_host = 'http://a%d.example.com' - ActionController::Base.perform_caching = true + config.perform_caching = true hash = '/javascripts/cache/money.js'.hash % 4 assert_dom_equal( @@ -564,7 +563,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_with_all_and_recursive_puts_defaults_at_the_start_of_the_file ENV["RAILS_ASSET_ID"] = "" @controller.config.asset_host = 'http://a0.example.com' - ActionController::Base.perform_caching = true + config.perform_caching = true assert_dom_equal( %(<script src="http://a0.example.com/javascripts/combined.js" type="text/javascript"></script>), @@ -585,7 +584,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_with_all_puts_defaults_at_the_start_of_the_file ENV["RAILS_ASSET_ID"] = "" @controller.config.asset_host = 'http://a0.example.com' - ActionController::Base.perform_caching = true + config.perform_caching = true assert_dom_equal( %(<script src="http://a0.example.com/javascripts/combined.js" type="text/javascript"></script>), @@ -606,7 +605,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_with_relative_url_root ENV["RAILS_ASSET_ID"] = "" @controller.config.relative_url_root = "/collaboration/hieraki" - ActionController::Base.perform_caching = true + config.perform_caching = true assert_dom_equal( %(<script src="/collaboration/hieraki/javascripts/all.js" type="text/javascript"></script>), @@ -629,7 +628,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_when_caching_off ENV["RAILS_ASSET_ID"] = "" - ActionController::Base.perform_caching = false + config.perform_caching = false assert_dom_equal( %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>\n<script src="/javascripts/bank.js" type="text/javascript"></script>\n<script src="/javascripts/robber.js" type="text/javascript"></script>\n<script src="/javascripts/version.1.0.js" type="text/javascript"></script>), @@ -658,7 +657,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_when_caching_on_and_missing_javascript_file ENV["RAILS_ASSET_ID"] = "" - ActionController::Base.perform_caching = true + config.perform_caching = true assert_raise(Errno::ENOENT) { javascript_include_tag('bank', 'robber', 'missing_security_guard', :cache => true) @@ -675,7 +674,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_javascript_include_tag_when_caching_off_and_missing_javascript_file ENV["RAILS_ASSET_ID"] = "" - ActionController::Base.perform_caching = false + config.perform_caching = false assert_raise(Errno::ENOENT) { javascript_include_tag('bank', 'robber', 'missing_security_guard', :cache => true) @@ -693,7 +692,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_link_tag_when_caching_on ENV["RAILS_ASSET_ID"] = "" @controller.config.asset_host = 'http://a0.example.com' - ActionController::Base.perform_caching = true + config.perform_caching = true assert_dom_equal( %(<link href="http://a0.example.com/stylesheets/all.css" media="screen" rel="stylesheet" type="text/css" />), @@ -760,7 +759,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_link_tag_when_caching_on_and_missing_css_file ENV["RAILS_ASSET_ID"] = "" - ActionController::Base.perform_caching = true + config.perform_caching = true assert_raise(Errno::ENOENT) { stylesheet_link_tag('bank', 'robber', 'missing_security_guard', :cache => true) @@ -781,7 +780,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_link_tag_when_caching_off_and_missing_css_file ENV["RAILS_ASSET_ID"] = "" - ActionController::Base.perform_caching = false + config.perform_caching = false assert_raise(Errno::ENOENT) { stylesheet_link_tag('bank', 'robber', 'missing_security_guard', :cache => true) @@ -803,7 +802,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_link_tag_when_caching_on_with_proc_asset_host ENV["RAILS_ASSET_ID"] = "" @controller.config.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" } - ActionController::Base.perform_caching = true + config.perform_caching = true assert_equal '/stylesheets/styles.css'.length, 23 assert_dom_equal( @@ -820,7 +819,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_link_tag_with_relative_url_root ENV["RAILS_ASSET_ID"] = "" @controller.config.relative_url_root = "/collaboration/hieraki" - ActionController::Base.perform_caching = true + config.perform_caching = true assert_dom_equal( %(<link href="/collaboration/hieraki/stylesheets/all.css" media="screen" rel="stylesheet" type="text/css" />), @@ -845,7 +844,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_include_tag_when_caching_off ENV["RAILS_ASSET_ID"] = "" - ActionController::Base.perform_caching = false + config.perform_caching = false assert_dom_equal( %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" type="text/css" />), diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb index 2017a18806..f887c9ab5b 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionpack/test/template/capture_helper_test.rb @@ -12,4 +12,10 @@ class CaptureHelperTest < ActionView::TestCase assert content_for?(:title) assert ! content_for?(:something_else) end + + def test_with_output_buffer_does_not_assume_there_is_an_output_buffer + av = ActionView::Base.new + assert_nil av.output_buffer + assert_equal "", av.with_output_buffer {} + end end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index b69577f8dd..a5179033f2 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -111,8 +111,11 @@ module ActiveRecord private # Gets the specified association instance if it responds to :loaded?, nil otherwise. def association_instance_get(name) - association = instance_variable_get("@#{name}") - association if association.respond_to?(:loaded?) + ivar = "@#{name}" + if instance_variable_defined?(ivar) + association = instance_variable_get(ivar) + association if association.respond_to?(:loaded?) + end end # Set the specified association instance. diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 9487d16123..6eda70d0ce 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -101,6 +101,7 @@ module ActiveRecord Array(@target) end end + alias_method :to_a, :to_ary def reset reset_target! diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 022dd2ae9b..0ff89df1e3 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -49,7 +49,7 @@ module ActiveRecord alias_method :proxy_respond_to?, :respond_to? alias_method :proxy_extend, :extend delegate :to_param, :to => :proxy_target - instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ } + instance_methods.each { |m| undef_method m unless m =~ /^(?:nil\?|send|object_id|to_a)$|^__|proxy_/ } def initialize(owner, reflection) @owner, @reflection = owner, reflection diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 52587ef251..1488d9f967 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1041,6 +1041,10 @@ module ActiveRecord #:nodoc: object.instance_variable_set(:'@attributes', record) object.instance_variable_set(:'@attributes_cache', {}) + object.instance_variable_set(:@new_record, false) + object.instance_variable_set(:@readonly, false) + object.instance_variable_set(:@destroyed, false) + object.instance_variable_set(:@marked_for_destruction, false) object.send(:_run_find_callbacks) object.send(:_run_initialize_callbacks) @@ -1506,6 +1510,10 @@ module ActiveRecord #:nodoc: @attributes = attributes_from_column_definition @attributes_cache = {} @new_record = true + @readonly = false + @destroyed = false + @marked_for_destruction = false + ensure_proper_type if scope = self.class.send(:current_scoped_methods) @@ -1570,7 +1578,7 @@ module ActiveRecord #:nodoc: # user_path(user) # => "/users/Phusion" def to_param # We can't use alias_method here, because method 'id' optimizes itself on the fly. - (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes + id && id.to_s # Be sure to stringify the id for routes end # Returns a cache key that can be used to identify this record. @@ -1597,12 +1605,12 @@ module ActiveRecord #:nodoc: # Returns true if this object hasn't been saved yet -- that is, a record for the object doesn't exist yet; otherwise, returns false. def new_record? - @new_record || false + @new_record end # Returns true if this object has been destroyed, otherwise returns false. def destroyed? - @destroyed || false + @destroyed end # Returns if the record is persisted, i.e. it's not a new record and it was not destroyed. @@ -1695,7 +1703,7 @@ module ActiveRecord #:nodoc: # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method # in Base is replaced with this when the validations module is mixed in, which it is by default. def update_attribute(name, value) - send(name.to_s + '=', value) + send("#{name}=", value) save(:validate => false) end @@ -1912,14 +1920,14 @@ module ActiveRecord #:nodoc: # Returns duplicated record with unfreezed attributes. def dup obj = super - obj.instance_variable_set('@attributes', instance_variable_get('@attributes').dup) + obj.instance_variable_set('@attributes', @attributes.dup) obj end # Returns +true+ if the record is read only. Records loaded through joins with piggy-back # attributes will be marked as read only since they cannot be saved. def readonly? - defined?(@readonly) && @readonly == true + @readonly end # Marks this record as read only. @@ -1939,10 +1947,10 @@ module ActiveRecord #:nodoc: protected def clone_attributes(reader_method = :read_attribute, attributes = {}) - self.attribute_names.inject(attributes) do |attrs, name| - attrs[name] = clone_attribute_value(reader_method, name) - attrs + attribute_names.each do |name| + attributes[name] = clone_attribute_value(reader_method, name) end + attributes end def clone_attribute_value(reader_method, attribute_name) @@ -2245,4 +2253,4 @@ end # TODO: Remove this and make it work with LAZY flag require 'active_record/connection_adapters/abstract_adapter' -ActiveRecord.run_base_hooks(ActiveRecord::Base)
\ No newline at end of file +ActiveRecord.run_base_hooks(ActiveRecord::Base) diff --git a/activerecord/lib/active_record/dynamic_finder_match.rb b/activerecord/lib/active_record/dynamic_finder_match.rb index 8f9f05ce36..fa7a19487c 100644 --- a/activerecord/lib/active_record/dynamic_finder_match.rb +++ b/activerecord/lib/active_record/dynamic_finder_match.rb @@ -7,6 +7,9 @@ module ActiveRecord def initialize(method) @finder = :first + @bang = false + @instantiator = nil + case method.to_s when /^find_(all_by|last_by|by)_([_a-zA-Z]\w*)$/ @finder = :last if $1 == 'last_by' diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index fd5ffc6d77..5825482db7 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -315,7 +315,9 @@ module ActiveRecord end def announce(message) - text = "#{@version} #{name}: #{message}" + version = defined?(@version) ? @version : nil + + text = "#{version} #{name}: #{message}" length = [0, 75 - text.length].max write "== %s %s" % [text, "=" * length] end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 32b9a2aa87..5e8fc104cb 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -154,6 +154,11 @@ module ActiveRecord @klass ||= active_record.send(:compute_type, class_name) end + def initialize(macro, name, options, active_record) + super + @collection = [:has_many, :has_and_belongs_to_many].include?(macro) + end + # Returns a new, unsaved instance of the associated class. +options+ will # be passed to the class's constructor. def build_association(*options) @@ -256,9 +261,6 @@ module ActiveRecord # association. Returns +true+ if the +macro+ is one of +has_many+ or # +has_and_belongs_to_many+, +false+ otherwise. def collection? - if @collection.nil? - @collection = [:has_many, :has_and_belongs_to_many].include?(macro) - end @collection end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index aca4629dd8..1a84f70a8e 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -14,6 +14,14 @@ module ActiveRecord def initialize(klass, table) @klass, @table = klass, table + + @readonly_value = nil + @create_with_value = nil + @implicit_readonly = nil + @limit_value = nil + @offset_value = nil + @loaded = nil + (ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v| instance_variable_set(:"@#{v}_values", [])} end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 608d5a3608..d47c8bba7d 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -18,10 +18,14 @@ require 'models/developer' class HasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :posts, :readers, :people, :comments, :authors, :owners, :pets, :toys, :jobs, :references, :companies - def test_associate_existing - assert_queries(2) { posts(:thinking);people(:david) } + # Dummies to force column loads so query counts are clean. + def setup + Person.create :first_name => 'gummy' + Reader.create :person_id => 0, :post_id => 0 + end - posts(:thinking).people + def test_associate_existing + assert_queries(2) { posts(:thinking); people(:david) } assert_queries(1) do posts(:thinking).people << people(:david) diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 9bc34bd750..d99fb44f01 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -180,6 +180,14 @@ class AssociationProxyTest < ActiveRecord::TestCase end end + if RUBY_VERSION < '1.9' + def test_splat_does_not_invoke_to_a_on_singular_targets + author = posts(:welcome).author + author.reload.target.expects(:to_a).never + [*author] + end + end + def setup_dangling_association josh = Author.create(:name => "Josh") p = Post.create(:title => "New on Edge", :body => "More cool stuff!", :author => josh) diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index e831ebf36c..1fb59d3589 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -7,6 +7,7 @@ require 'config' require 'test/unit' require 'stringio' +require 'mocha' require 'active_record' require 'active_support/dependencies' diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index af46ae10d6..9a7c520e75 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -89,12 +89,8 @@ module ActiveSupport #:nodoc: self end - def as_str - ''.replace(self) - end - def to_yaml(*args) - as_str.to_yaml(*args) + to_str.to_yaml(*args) end end end diff --git a/ci/ci_build.rb b/ci/ci_build.rb index 2a7bbc376e..02351729f2 100755 --- a/ci/ci_build.rb +++ b/ci/ci_build.rb @@ -27,7 +27,7 @@ cd root_dir do puts puts "[CruiseControl] Bundling RubyGems" puts - build_results[:bundle] = system 'rm -rf ~/.bundle; env CI=1 bundle install' + build_results[:bundle] = system 'sudo rm -rf ~/.bundle; env CI=1 bundle install' end cd "#{root_dir}/activesupport" do diff --git a/railties/lib/generators/rails/app/app_generator.rb b/railties/lib/generators/rails/app/app_generator.rb index 92e0d37436..1e1acc1141 100644 --- a/railties/lib/generators/rails/app/app_generator.rb +++ b/railties/lib/generators/rails/app/app_generator.rb @@ -178,7 +178,8 @@ module Rails::Generators end def bundle_if_dev_or_edge - run "bundle install" if dev_or_edge? + bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') + run "#{bundle_command} install" if dev_or_edge? end protected @@ -220,6 +221,8 @@ module Rails::Generators raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers." elsif RESERVED_NAMES.include?(app_name) raise Error, "Invalid application name #{app_name}. Please give a name which does not match one of the reserved rails words." + elsif Object.const_defined?(app_const_base) + raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name." end end diff --git a/railties/lib/generators/rails/app/templates/script/rails b/railties/lib/generators/rails/app/templates/script/rails index 199fe1a6d3..b01d1ee183 100644 --- a/railties/lib/generators/rails/app/templates/script/rails +++ b/railties/lib/generators/rails/app/templates/script/rails @@ -1,5 +1,8 @@ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. -ENV_PATH = File.expand_path('../../config/environment', __FILE__) -require File.expand_path('../../config/boot', __FILE__) +ENV_PATH = File.expand_path('../../config/environment', __FILE__) +BOOT_PATH = File.expand_path('../../config/boot', __FILE__) +APP_PATH = File.expand_path('../../config/application', __FILE__) + +require BOOT_PATH require 'rails/commands' diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index d4558be00f..12748da18b 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -34,13 +34,15 @@ when 'c', 'console' Rails::Console.start(Rails::Application) when 's', 'server' require 'rails/commands/server' + # Initialize the server first, so environment options are set server = Rails::Server.new - require ENV_PATH + require APP_PATH + Dir.chdir(Rails::Application.root) server.start when 'db', 'dbconsole' require 'rails/commands/dbconsole' - require ENV_PATH + require APP_PATH Rails::DBConsole.start(Rails::Application) when 'application' @@ -55,7 +57,7 @@ when 'profiler' require ENV_PATH require 'rails/commands/performance/profiler' when 'plugin' - require ENV_PATH + require APP_PATH require 'rails/commands/plugin' when 'runner' require 'rails/commands/runner' diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 3c902ce0d4..9a51171cf5 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -202,6 +202,10 @@ module Rails rails.delete("app") print_list("rails", rails) + groups.delete("active_record") if options[:rails][:orm] == :active_record + groups.delete("test_unit") if options[:rails][:test_framework] == :test_unit + groups.delete("erb") if options[:rails][:template_engine] == :erb + groups.sort.each { |b, n| print_list(b, n) } end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 412034029e..4fc26563ff 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -9,6 +9,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def setup super Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) + @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') end def teardown @@ -65,6 +66,13 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_equal "Invalid application name 43-things. Please give a name which does not start with numbers.\n", content end + def test_application_name_raises_an_error_if_name_already_used_constant + %w{ String Hash Class Module Set Symbol }.each do |ruby_class| + content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] } + assert_equal "Invalid application name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another application name.\n", content + end + end + def test_invalid_application_name_is_fixed run_generator [File.join(destination_root, "things-43")] assert_file "things-43/config/environment.rb", /Things43::Application\.initialize!/ @@ -161,14 +169,14 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_dev_option - generator([destination_root], :dev => true).expects(:run).with("bundle install") + generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install") silence(:stdout){ generator.invoke } rails_path = File.expand_path('../../..', Rails.root) assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/ end def test_edge_option - generator([destination_root], :edge => true).expects(:run).with("bundle install") + generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install") silence(:stdout){ generator.invoke } assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$/ end diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index dd17f8f756..2975e3e3ef 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -104,11 +104,25 @@ class GeneratorsTest < Rails::Generators::TestCase def test_rails_generators_with_others_information output = capture(:stdout){ Rails::Generators.help } - assert_match /ActiveRecord:/, output assert_match /Fixjour:/, output + assert_match /^ fixjour$/, output + end + + def test_rails_generators_does_not_show_activerecord_info_if_its_the_default + output = capture(:stdout){ Rails::Generators.help } + assert_no_match /ActiveRecord:/, output + assert_no_match /^ active_record:model$/, output + assert_no_match /^ active_record:fixjour$/, output + end + + def test_rails_generators_shows_activerecord_info_if_its_not_the_default + Rails::Generators.options[:rails][:orm] = :data_mapper + output = capture(:stdout){ Rails::Generators.help } + assert_match /ActiveRecord:/, output assert_match /^ active_record:model$/, output assert_match /^ active_record:fixjour$/, output - assert_match /^ fixjour$/, output + ensure + Rails::Generators.options[:rails][:orm] = :active_record end def test_no_color_sets_proper_shell |