aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
authorEmilio Tagua <miloops@gmail.com>2009-08-10 18:07:33 -0300
committerEmilio Tagua <miloops@gmail.com>2009-08-10 18:07:33 -0300
commit0e2fbd80e2420329738b891240d44a056cea1de4 (patch)
tree5b16755670be58e168b5e86e2cdcb43ee5aa3918 /actionpack/lib
parenteb3ae44ccaff1dc63eb31bf86d8db07c88ddc413 (diff)
parent600a89f2082beadf4af9fe140a1a2ae56386cd49 (diff)
downloadrails-0e2fbd80e2420329738b891240d44a056cea1de4.tar.gz
rails-0e2fbd80e2420329738b891240d44a056cea1de4.tar.bz2
rails-0e2fbd80e2420329738b891240d44a056cea1de4.zip
Merge commit 'rails/master'
Conflicts: activerecord/lib/active_record/calculations.rb activerecord/lib/active_record/connection_adapters/mysql_adapter.rb activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb10
-rw-r--r--actionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/metal/compatibility.rb2
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb5
-rw-r--r--actionpack/lib/action_controller/routing/resources.rb14
-rw-r--r--actionpack/lib/action_controller/routing/route_set.rb33
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb4
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb13
-rw-r--r--actionpack/lib/action_view/base.rb40
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb67
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb32
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionpack/lib/action_view/render/partials.rb114
-rw-r--r--actionpack/lib/action_view/template/template.rb12
-rw-r--r--actionpack/lib/action_view/template/text.rb4
17 files changed, 250 insertions, 111 deletions
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 04eaa02441..f3072fad74 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -4,8 +4,16 @@ module AbstractController
include RenderingController
+ def self.next_serial
+ @helper_serial ||= 0
+ @helper_serial += 1
+ end
+
included do
extlib_inheritable_accessor(:_helpers) { Module.new }
+ extlib_inheritable_accessor(:_helper_serial) do
+ AbstractController::Helpers.next_serial
+ end
end
module ClassMethods
@@ -58,6 +66,8 @@ module AbstractController
# of the helper module. Any methods defined in the block
# will be helpers.
def helper(*args, &block)
+ self._helper_serial = AbstractController::Helpers.next_serial + 1
+
args.flatten.each do |arg|
case arg
when Module
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 61f1c715c8..698189bd46 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -41,7 +41,7 @@ module ActionController
module ImplicitRender
def send_action(*)
ret = super
- default_render unless performed?
+ default_render unless response_body
ret
end
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb
index 23e7b1b3af..f94d1c669c 100644
--- a/actionpack/lib/action_controller/metal/compatibility.rb
+++ b/actionpack/lib/action_controller/metal/compatibility.rb
@@ -64,6 +64,8 @@ module ActionController
cattr_accessor :ip_spoofing_check
self.ip_spoofing_check = true
+
+ cattr_accessor :trusted_proxies
end
# For old tests
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 525787bf92..2b62a1be85 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -141,7 +141,7 @@ module ActionController
end
def decode_credentials(request)
- ActiveSupport::Base64.decode64(authorization(request).split.last || '')
+ ActiveSupport::Base64.decode64(authorization(request).split(' ', 2).last || '')
end
def encode_credentials(user_name, password)
@@ -197,9 +197,10 @@ module ActionController
return false unless password
method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
+ uri = credentials[:uri][0,1] == '/' ? request.request_uri : request.url
[true, false].any? do |password_is_ha1|
- expected = expected_response(method, request.env['REQUEST_URI'], credentials, password, password_is_ha1)
+ expected = expected_response(method, uri, credentials, password, password_is_ha1)
expected == credentials[:response]
end
end
diff --git a/actionpack/lib/action_controller/routing/resources.rb b/actionpack/lib/action_controller/routing/resources.rb
index 2dee0a3d87..4862cf7115 100644
--- a/actionpack/lib/action_controller/routing/resources.rb
+++ b/actionpack/lib/action_controller/routing/resources.rb
@@ -320,9 +320,10 @@ module ActionController
# notes.resources :attachments
# end
#
- # * <tt>:path_names</tt> - Specify different names for the 'new' and 'edit' actions. For example:
+ # * <tt>:path_names</tt> - Specify different path names for the actions. For example:
# # new_products_path == '/productos/nuevo'
- # map.resources :products, :as => 'productos', :path_names => { :new => 'nuevo', :edit => 'editar' }
+ # # bids_product_path(1) == '/productos/1/licitacoes'
+ # map.resources :products, :as => 'productos', :member => { :bids => :get }, :path_names => { :new => 'nuevo', :bids => 'licitacoes' }
#
# You can also set default action names from an environment, like this:
# config.action_controller.resources_path_names = { :new => 'nuevo', :edit => 'editar' }
@@ -528,13 +529,13 @@ module ActionController
resource = Resource.new(entities, options)
with_options :controller => resource.controller do |map|
+ map_associations(resource, options)
+
map_collection_actions(map, resource)
map_default_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
- map_associations(resource, options)
-
if block_given?
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
@@ -589,7 +590,10 @@ module ActionController
resource.collection_methods.each do |method, actions|
actions.each do |action|
[method].flatten.each do |m|
- map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
+ action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
+ action_path ||= action
+
+ map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
end
end
end
diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb
index 040a7e2cb6..09f6024d39 100644
--- a/actionpack/lib/action_controller/routing/route_set.rb
+++ b/actionpack/lib/action_controller/routing/route_set.rb
@@ -407,9 +407,24 @@ module ActionController
# don't use the recalled keys when determining which routes to check
routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }]
- routes.each do |route|
+ routes[1].each_with_index do |route, index|
results = route.__send__(method, options, merged, expire_on)
- return results if results && (!results.is_a?(Array) || results.first)
+ if results && (!results.is_a?(Array) || results.first)
+
+ # Compare results with Rails 3.0 behavior
+ if routes[0][index] != route
+ routes[0].each do |route2|
+ new_results = route2.__send__(method, options, merged, expire_on)
+ if new_results && (!new_results.is_a?(Array) || new_results.first)
+ ActiveSupport::Deprecation.warn "The URL you generated will use the first matching route in routes.rb rather than the \"best\" match. " +
+ "In Rails 3.0 #{new_results} would of been generated instead of #{results}"
+ break
+ end
+ end
+ end
+
+ return results
+ end
end
end
@@ -448,7 +463,10 @@ module ActionController
@routes_by_controller ||= Hash.new do |controller_hash, controller|
controller_hash[controller] = Hash.new do |action_hash, action|
action_hash[action] = Hash.new do |key_hash, keys|
- key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys)
+ key_hash[keys] = [
+ routes_for_controller_and_action_and_keys(controller, action, keys),
+ deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
+ ]
end
end
end
@@ -460,17 +478,16 @@ module ActionController
merged = options if expire_on[:controller]
action = merged[:action] || 'index'
- routes_by_controller[controller][action][merged.keys]
+ routes_by_controller[controller][action][merged.keys][1]
end
- def routes_for_controller_and_action(controller, action)
- selected = routes.select do |route|
+ def routes_for_controller_and_action_and_keys(controller, action, keys)
+ routes.select do |route|
route.matches_controller_and_action? controller, action
end
- (selected.length == routes.length) ? routes : selected
end
- def routes_for_controller_and_action_and_keys(controller, action, keys)
+ def deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
selected = routes.select do |route|
route.matches_controller_and_action? controller, action
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 5f9463eb91..4190fa21cd 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -246,7 +246,7 @@ module ActionDispatch
remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].scan(/[^,\s]+/)
unless remote_addr_list.blank?
- not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES}
+ not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES || addr =~ ActionController::Base.trusted_proxies}
return not_trusted_addrs.first unless not_trusted_addrs.empty?
end
remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
@@ -265,7 +265,7 @@ EOM
end
if remote_ips
- while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip
+ while remote_ips.size > 1 && (TRUSTED_PROXIES =~ remote_ips.last.strip || ActionController::Base.trusted_proxies =~ remote_ips.last.strip)
remote_ips.pop
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index dd75cda6b9..d22adfa749 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -345,14 +345,17 @@ module ActionDispatch
#
# Use the first argument to narrow down assertions to only statements
# of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
- # <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tt> and
- # <tt>:insert_html</tt>.
+ # <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tta>,
+ # <tt>:insert_html</tt> and <tt>:redirect</tt>.
#
# Use the argument <tt>:insert</tt> followed by an insertion position to narrow
# down the assertion to only statements that insert elements in that
# position. Possible values are <tt>:top</tt>, <tt>:bottom</tt>, <tt>:before</tt>
# and <tt>:after</tt>.
#
+ # Use the argument <tt>:redirect</tt> follwed by a path to check that an statement
+ # which redirects to the specified path is generated.
+ #
# Using the <tt>:remove</tt> statement, you will be able to pass a block, but it will
# be ignored as there is no HTML passed for this statement.
#
@@ -399,6 +402,9 @@ module ActionDispatch
#
# # The same, but shorter.
# assert_select "ol>li", 4
+ #
+ # # Checking for a redirect.
+ # assert_select_rjs :redirect, root_path
def assert_select_rjs(*args, &block)
rjs_type = args.first.is_a?(Symbol) ? args.shift : nil
id = args.first.is_a?(String) ? args.shift : nil
@@ -576,7 +582,8 @@ module ActionDispatch
: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}\\)"
+ :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
+ :redirect => "window.location.href = #{RJS_ANY_ID}"
}
[:remove, :show, :hide, :toggle].each do |action|
RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)"
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 7932f01ebb..c171a5a8f5 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -164,6 +164,9 @@ module ActionView #:nodoc:
#
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
class Base
+ module Subclasses
+ end
+
include Helpers, Rendering, Partials, ::ERB::Util
extend ActiveSupport::Memoizable
@@ -195,7 +198,9 @@ module ActionView #:nodoc:
attr_internal :request, :layout
- delegate :controller_path, :to => :controller, :allow_nil => true
+ def controller_path
+ @controller_path ||= controller && controller.controller_path
+ end
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :action_name, :controller_name, :to => :controller
@@ -210,30 +215,35 @@ module ActionView #:nodoc:
ActionView::PathSet.new(Array(value))
end
+ extlib_inheritable_accessor :helpers
attr_reader :helpers
- class ProxyModule < Module
- def initialize(receiver)
- @receiver = receiver
- end
+ def self.for_controller(controller)
+ @views ||= {}
- def include(*args)
- super(*args)
- @receiver.extend(*args)
- end
- end
+ # TODO: Decouple this so helpers are a separate concern in AV just like
+ # they are in AC.
+ if controller.class.respond_to?(:_helper_serial)
+ klass = @views[controller.class._helper_serial] ||= Class.new(self) do
+ Subclasses.const_set(controller.class.name.gsub(/::/, '__'), self)
- def self.for_controller(controller)
- new(controller.class.view_paths, {}, controller).tap do |view|
- view.helpers.include(controller._helpers) if controller.respond_to?(:_helpers)
+ if controller.respond_to?(:_helpers)
+ include controller._helpers
+ self.helpers = controller._helpers
+ end
+ end
+ else
+ klass = self
end
+
+ klass.new(controller.class.view_paths, {}, controller)
end
def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc:
@formats = formats || [:html]
@assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
@controller = controller
- @helpers = ProxyModule.new(self)
+ @helpers = self.class.helpers || Module.new
@_content_for = Hash.new {|h,k| h[k] = "" }
self.view_paths = view_paths
end
@@ -248,7 +258,7 @@ module ActionView #:nodoc:
def with_template(current_template)
_evaluate_assigns_and_ivars
last_template, self.template = template, current_template
- last_formats, self.formats = formats, [current_template.mime_type.to_sym] + Mime::SET.symbols
+ last_formats, self.formats = formats, current_template.formats
yield
ensure
self.template, self.formats = last_template, last_formats
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index dc4497581c..9951e11a37 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -98,7 +98,7 @@ module ActionView
options[:schema_date] = "2005" # The Atom spec copyright date
end
- xml = options[:xml] || eval("xml", block.binding)
+ xml = options.delete(:xml) || eval("xml", block.binding)
xml.instruct!
if options[:instruct]
options[:instruct].each do |target,attrs|
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index bde600f6ed..81029102b1 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -738,6 +738,7 @@ module ActionView
options = options.stringify_keys
tag_value = options.delete("value")
name_and_id = options.dup
+ name_and_id["id"] = name_and_id["for"]
add_default_name_and_id_for_value(tag_value, name_and_id)
options.delete("index")
options["for"] ||= name_and_id["id"]
@@ -936,6 +937,10 @@ module ActionView
@model_name ||= Struct.new(:partial_path).new(name.demodulize.underscore.sub!(/_builder$/, ''))
end
+ def to_model
+ self
+ end
+
def initialize(object_name, object, template, options, proc)
@nested_child_index = {}
@object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 8cb5882aab..4620a52272 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -162,6 +162,60 @@ module ActionView
InstanceTag.new(object, method, self, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
end
+
+ # Returns <tt><select></tt>, <tt><optgroup></tt> and <tt><option></tt> tags for the collection of existing return values of
+ # +method+ for +object+'s class. The value returned from calling +method+ on the instance +object+ will
+ # be selected. If calling +method+ returns +nil+, no selection is made without including <tt>:prompt</tt>
+ # or <tt>:include_blank</tt> in the +options+ hash.
+ #
+ # Parameters:
+ # * +object+ - The instance of the class to be used for the select tag
+ # * +method+ - The attribute of +object+ corresponding to the select tag
+ # * +collection+ - An array of objects representing the <tt><optgroup></tt> tags.
+ # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an
+ # array of child objects representing the <tt><option></tt> tags.
+ # * +group_label_method+ - The name of a method which, when called on a member of +collection+, returns a
+ # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag.
+ # * +option_key_method+ - The name of a method which, when called on a child object of a member of
+ # +collection+, returns a value to be used as the +value+ attribute for its <tt><option></tt> tag.
+ # * +option_value_method+ - The name of a method which, when called on a child object of a member of
+ # +collection+, returns a value to be used as the contents of its <tt><option></tt> tag.
+ #
+ # Example object structure for use with this method:
+ # class Continent < ActiveRecord::Base
+ # has_many :countries
+ # # attribs: id, name
+ # end
+ # class Country < ActiveRecord::Base
+ # belongs_to :continent
+ # # attribs: id, name, continent_id
+ # end
+ # class City < ActiveRecord::Base
+ # belongs_to :country
+ # # attribs: id, name, country_id
+ # end
+ #
+ # Sample usage:
+ # grouped_collection_select(:city, :country_id, @continents, :countries, :name, :id, :name)
+ #
+ # Possible output:
+ # <select name="city[country_id]">
+ # <optgroup label="Africa">
+ # <option value="1">South Africa</option>
+ # <option value="3">Somalia</option>
+ # </optgroup>
+ # <optgroup label="Europe">
+ # <option value="7" selected="selected">Denmark</option>
+ # <option value="2">Ireland</option>
+ # </optgroup>
+ # </select>
+ #
+ def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
+ InstanceTag.new(object, method, self, options.delete(:object)).to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
+ end
+
+
+
# Return select and option tags for the given object and method, using
# #time_zone_options_for_select to generate the list of option tags.
#
@@ -490,6 +544,15 @@ module ActionView
)
end
+ def to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
+ html_options = html_options.stringify_keys
+ add_default_name_and_id(html_options)
+ value = value(object)
+ content_tag(
+ "select", add_options(option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, value), options, value), html_options
+ )
+ end
+
def to_time_zone_select_tag(priority_zones, options, html_options)
html_options = html_options.stringify_keys
add_default_name_and_id(html_options)
@@ -524,6 +587,10 @@ module ActionView
@template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options))
end
+ def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
+ @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_options.merge(html_options))
+ end
+
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
@template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options))
end
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index c3ce4c671e..1d92bcb763 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -33,13 +33,15 @@ module ActionView
end
# Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
- # (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...").
+ # (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...")
+ # for a total length not exceeding <tt>:length</tt>.
+ #
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break.
#
# ==== Examples
#
# truncate("Once upon a time in a world far far away")
- # # => Once upon a time in a world f...
+ # # => Once upon a time in a world...
#
# truncate("Once upon a time in a world far far away", :separator => ' ')
# # => Once upon a time in a world...
@@ -48,19 +50,19 @@ module ActionView
# # => Once upon a...
#
# truncate("And they found that many people were sleeping better.", :length => 25, "(clipped)")
- # # => And they found that many (clipped)
+ # # => And they found t(clipped)
#
- # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 15)
- # # => And they found... (continued)
+ # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 25)
+ # # => And they f... (continued)
#
# You can still use <tt>truncate</tt> with the old API that accepts the
# +length+ as its optional second and the +ellipsis+ as its
# optional third parameter:
# truncate("Once upon a time in a world far far away", 14)
- # # => Once upon a time in a world f...
+ # # => Once upon a...
#
- # truncate("And they found that many people were sleeping better.", 15, "... (continued)")
- # # => And they found... (continued)
+ # truncate("And they found that many people were sleeping better.", 25, "... (continued)")
+ # # => And they f... (continued)
def truncate(text, *args)
options = args.extract_options!
unless args.empty?
@@ -239,12 +241,20 @@ module ActionView
#
# textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
# # => "<p>Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>.</p>"
- def textilize(text)
+ #
+ # textilize("This is worded <strong>strongly</strong>")
+ # # => "<p>This is worded <strong>strongly</strong></p>"
+ #
+ # textilize("This is worded <strong>strongly</strong>", :filter_html)
+ # # => "<p>This is worded &lt;strong&gt;strongly&lt;/strong&gt;</p>"
+ #
+ def textilize(text, *options)
+ options ||= [:hard_breaks]
+
if text.blank?
""
else
- textilized = RedCloth.new(text, [ :hard_breaks ])
- textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=)
+ textilized = RedCloth.new(text, options)
textilized.to_html
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index c5a6d1f084..b07304e361 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -568,7 +568,7 @@ module ActionView
when confirm && popup
"if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;"
when confirm && method
- "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method)} };return false;"
+ "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method, url, href)} };return false;"
when confirm
"return #{confirm_javascript_function(confirm)};"
when method
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 986d3af454..64f08c447d 100644
--- a/actionpack/lib/action_view/render/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -177,71 +177,70 @@ module ActionView
@partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new }
end
- def initialize(view_context, options, formats)
- object = options[:partial]
-
- @view, @formats = view_context, formats
- @options = options || {}
-
- if object.is_a?(String)
- @path = object
- elsif
- @object = object
- @path = partial_path unless collection
- end
-
- @locals = options[:locals] || {}
- @object ||= @options[:object] || @locals[:object]
- @layout = options[:layout]
+ def self.formats
+ @formats ||= Hash.new {|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new {|h,k| h[k] = {}}}}
end
- def render(&block)
- template = find if @path
+ def initialize(view_context, options, block)
+ partial = options[:partial]
- if collection
- render_collection(template, &block)
- else
- render_object(template, &block)
- end
- end
+ @view = view_context
+ @options = options
+ @locals = options[:locals] || {}
+ @block = block
- def render_template(template, &block)
- @options[:_template] = template
- @locals[:object] = @locals[template.variable_name] = @object
- @locals[@options[:as]] = @object if @options[:as]
+ # Set up some instance variables to speed up memoizing
+ @partial_names = self.class.partial_names[@view.controller.class]
+ @templates = self.class.formats
+ @format = view_context.formats
- content = @view._render_single_template(template, @locals, &block)
- return content if block_given? || !@layout
- find(@layout).render(@view, @locals) { content }
+ # Set up the object and path
+ @object = partial.is_a?(String) ? options[:object] : partial
+ @path = partial_path(partial)
end
- def render_object(template, &block)
- @object ||= @locals[template.variable_name]
- render_template(template, &block)
+ def render
+ return render_collection if collection
+
+ template = find_template
+ render_template(template, @object || @locals[template.variable_name])
end
- def render_collection(passed_template = nil, &block)
- @options[:_template] = passed_template
+ def render_collection
+ # Even if no template is rendered, this will ensure that the MIME type
+ # for the empty response is the same as the provided template
+ @options[:_template] = default_template = find_template
return nil if collection.blank?
if @options.key?(:spacer_template)
- spacer = @view.render_partial(
- :partial => @options[:spacer_template], :_details => @options[:_details])
+ spacer = find_template(@options[:spacer_template]).render(@view, @locals)
end
- index = 0
+ segments = []
- collection.map do |@object|
- @path = partial_path
- template = passed_template || find
+ collection.each_with_index do |object, index|
+ template = default_template || find_template(partial_path(object))
@locals[template.counter_name] = index
- index += 1
+ segments << render_template(template, object)
+ end
- render_template(template, &block)
- end.join(spacer)
+ segments.join(spacer)
end
+ def render_template(template, object = @object)
+ @options[:_template] ||= template
+
+ # TODO: is locals[:object] really necessary?
+ @locals[:object] = @locals[template.variable_name] = object
+ @locals[@options[:as]] = object if @options[:as]
+
+ content = @view._render_single_template(template, @locals, &@block)
+ return content if @block || !@options[:layout]
+ find_template(@options[:layout]).render(@view, @locals) { content }
+ end
+
+
private
def collection
@collection ||= if @object.respond_to?(:to_ary)
@@ -251,21 +250,22 @@ module ActionView
end
end
- def find(path = @path)
- prefix = @view.controller.controller_path unless path.include?(?/)
- @view.find(path, {:formats => @view.formats}, prefix, true)
+ def find_template(path = @path)
+ return if !path
+ @templates[path][@view.controller_path][@format][I18n.locale] ||= begin
+ prefix = @view.controller.controller_path unless path.include?(?/)
+ @view.find(path, {:formats => @view.formats}, prefix, true)
+ end
end
def partial_path(object = @object)
- self.class.partial_names[@view.controller.class][object.class] ||= begin
- return nil unless object.class.respond_to?(:model_name)
+ return object if object.is_a?(String)
+ @partial_names[object.class] ||= begin
+ return nil unless object.respond_to?(:to_model)
- name = object.class.model_name
- path = @view.controller_path
- if path && path.include?(?/)
- File.join(File.dirname(path), name.partial_path)
- else
- name.partial_path
+ object.to_model.class.model_name.partial_path.dup.tap do |partial|
+ path = @view.controller_path
+ partial.insert(0, "#{File.dirname(path)}/") if path.include?(?/)
end
end
end
@@ -279,7 +279,7 @@ module ActionView
end
def _render_partial(options, &block) #:nodoc:
- PartialRenderer.new(self, options, formats).render(&block)
+ PartialRenderer.new(self, options, block).render
end
end
diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb
index 4145045e2d..33d3f79ad3 100644
--- a/actionpack/lib/action_view/template/template.rb
+++ b/actionpack/lib/action_view/template/template.rb
@@ -7,19 +7,22 @@ require "action_view/template/resolver"
module ActionView
class Template
extend TemplateHandlers
- attr_reader :source, :identifier, :handler, :mime_type, :details
+ attr_reader :source, :identifier, :handler, :mime_type, :formats, :details
def initialize(source, identifier, handler, details)
@source = source
@identifier = identifier
@handler = handler
@details = details
+ @method_names = {}
format = details.delete(:format) || begin
# TODO: Clean this up
handler.respond_to?(:default_format) ? handler.default_format.to_sym.to_s : "html"
end
@mime_type = Mime::Type.lookup_by_extension(format.to_s)
+ @formats = [format.to_sym]
+ @formats << :html if format == :js
@details[:formats] = Array.wrap(format.to_sym)
end
@@ -30,12 +33,12 @@ module ActionView
# TODO: Figure out how to abstract this
def variable_name
- identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
+ @variable_name ||= identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
end
# TODO: Figure out how to abstract this
def counter_name
- "#{variable_name}_counter".to_sym
+ @counter_name ||= "#{variable_name}_counter".to_sym
end
# TODO: kill hax
@@ -90,7 +93,8 @@ module ActionView
def build_method_name(locals)
# TODO: is locals.keys.hash reliably the same?
- "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
+ @method_names[locals.keys.hash] ||=
+ "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
end
end
end
diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb
index 81944ff546..9f12e5e0a8 100644
--- a/actionpack/lib/action_view/template/text.rb
+++ b/actionpack/lib/action_view/template/text.rb
@@ -15,7 +15,9 @@ module ActionView #:nodoc:
def render(*) self end
def mime_type() @content_type end
-
+
+ def formats() [mime_type] end
+
def partial?() false end
end
end