aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view
diff options
context:
space:
mode:
authorJohn Mileham <jmileham@gmail.com>2011-03-24 15:03:08 -0400
committerJohn Mileham <jmileham@gmail.com>2011-03-24 15:03:08 -0400
commitb44a0ec153c84384e9b97a069e81f28bc5c2a4bf (patch)
tree94713aff0c241f91530dfd714bf685019c84ccab /actionpack/lib/action_view
parentd5994ee48af14d67f0eec7d23863d4b19211b078 (diff)
parent5214e73850916de3c9127d35a4ecee0424d364a3 (diff)
downloadrails-b44a0ec153c84384e9b97a069e81f28bc5c2a4bf.tar.gz
rails-b44a0ec153c84384e9b97a069e81f28bc5c2a4bf.tar.bz2
rails-b44a0ec153c84384e9b97a069e81f28bc5c2a4bf.zip
Merge branch 'master' of github.com:rails/rails into count_behavior
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb31
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionpack/lib/action_view/locale/en.yml2
-rw-r--r--actionpack/lib/action_view/template/handlers/erb.rb2
-rw-r--r--actionpack/lib/action_view/template/resolver.rb107
-rw-r--r--actionpack/lib/action_view/test_case.rb1
-rw-r--r--actionpack/lib/action_view/testing/resolvers.rb12
11 files changed, 131 insertions, 43 deletions
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index dc8e4bc316..6cd1565031 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -617,7 +617,7 @@ module ActionView
@options[:discard_second] ||= true unless @options[:include_seconds] && !@options[:discard_minute]
# If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
- # valid (otherwise it could be 31 and february wouldn't be a valid date)
+ # valid (otherwise it could be 31 and February wouldn't be a valid date)
if @datetime && @options[:discard_day] && !@options[:discard_month]
@datetime = @datetime.change(:day => 1)
end
@@ -644,7 +644,7 @@ module ActionView
@options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
# If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
- # valid (otherwise it could be 31 and february wouldn't be a valid date)
+ # valid (otherwise it could be 31 and February wouldn't be a valid date)
if @datetime && @options[:discard_day] && !@options[:discard_month]
@datetime = @datetime.change(:day => 1)
end
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index befaa3e8d9..48abf119f1 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -6,6 +6,7 @@ require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/output_safety'
+require 'active_support/core_ext/array/extract_options'
module ActionView
# = Action View Form Helpers
@@ -262,6 +263,24 @@ module ActionView
# ...
# </form>
#
+ # === Removing hidden model id's
+ #
+ # The form_for method automatically includes the model id as a hidden field in the form.
+ # This is used to maintain the correlation between the form data and its associated model.
+ # Some ORM systems do not use IDs on nested models so in this case you want to be able
+ # to disable the hidden id.
+ #
+ # In the following example the Post model has many Comments stored within it in a NoSQL database,
+ # thus there is no primary key for comments.
+ #
+ # Example:
+ #
+ # <%= form(@post) do |f| %>
+ # <% f.fields_for(:comments, :include_id => false) do |cf| %>
+ # ...
+ # <% end %>
+ # <% end %>
+ #
# === Customized form builders
#
# You can also build forms using a customized FormBuilder class. Subclass
@@ -332,7 +351,7 @@ module ActionView
options[:html][:remote] = options.delete(:remote)
options[:html][:authenticity_token] = options.delete(:authenticity_token)
-
+
builder = options[:parent_builder] = instantiate_builder(object_name, object, options, &proc)
fields_for = fields_for(object_name, object, options, &proc)
default_options = builder.multipart? ? { :multipart => true } : {}
@@ -862,9 +881,9 @@ module ActionView
private
- def instantiate_builder(record, record_object = nil, options = nil, &block)
- options, record_object = record_object, nil if record_object.is_a?(Hash)
- options ||= {}
+ def instantiate_builder(record, *args, &block)
+ options = args.extract_options!
+ record_object = args.shift
case record
when String, Symbol
@@ -1326,7 +1345,9 @@ module ActionView
def fields_for_nested_model(name, object, options, block)
object = convert_to_model(object)
- options[:hidden_field_id] = object.persisted?
+ parent_include_id = self.options.fetch(:include_id, true)
+ include_id = options.fetch(:include_id, parent_include_id)
+ options[:hidden_field_id] = object.persisted? && include_id
@template.fields_for(name, object, options, &block)
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 71f8534cbf..49aa434020 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -592,7 +592,7 @@ module ActionView
options.stringify_keys.tap do |html_options|
html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
# The following URL is unescaped, this is just a hash of options, and it is the
- # responsability of the caller to escape all the values.
+ # responsibility of the caller to escape all the values.
html_options["action"] = url_for(url_for_options, *parameters_for_url)
html_options["accept-charset"] = "UTF-8"
html_options["data-remote"] = true if html_options.delete("remote")
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 26f8dce3c3..05a9c5b4f1 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -369,7 +369,7 @@ module ActionView
# See <tt>number_to_human_size</tt> if you want to print a file size.
#
# You can also define you own unit-quantifier names if you want to use other decimal units
- # (eg.: 1500 becomes "1.5 kilometers", 0.150 becomes "150 mililiters", etc). You may define
+ # (eg.: 1500 becomes "1.5 kilometers", 0.150 becomes "150 milliliters", etc). You may define
# a wide range of unit quantifiers, even fractional ones (centi, deci, mili, etc).
#
# ==== Options
@@ -425,13 +425,13 @@ module ActionView
# thousand:
# one: "kilometer"
# other: "kilometers"
- # billion: "gazilion-distance"
+ # billion: "gazillion-distance"
#
# Then you could do:
#
# number_to_human(543934, :units => :distance) # => "544 kilometers"
# number_to_human(54393498, :units => :distance) # => "54400 kilometers"
- # number_to_human(54393498000, :units => :distance) # => "54.4 gazilion-distance"
+ # number_to_human(54393498000, :units => :distance) # => "54.4 gazillion-distance"
# number_to_human(343, :units => :distance, :precision => 1) # => "300 meters"
# number_to_human(1, :units => :distance) # => "1 meter"
# number_to_human(0.34, :units => :distance) # => "34 centimeters"
@@ -472,7 +472,7 @@ module ActionView
end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
- display_exponent = unit_exponents.find{|e| number_exponent >= e }
+ display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0
number /= 10 ** display_exponent
unit = case units
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index f3a429fcce..18e303778c 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -103,7 +103,7 @@ module ActionView
:form, :with, :update, :script, :type ]).merge(CALLBACKS)
# Returns the JavaScript needed for a remote function.
- # See the link_to_remote documentation at http://github.com/rails/prototype_legacy_helper as it takes the same arguments.
+ # See the link_to_remote documentation at https://github.com/rails/prototype_legacy_helper as it takes the same arguments.
#
# Example:
# # Generates: <select id="options" onchange="new Ajax.Updater('options',
@@ -131,7 +131,6 @@ module ActionView
"new Ajax.Updater(#{update}, "
url_options = options[:url]
- url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
function << "'#{ERB::Util.html_escape(escape_javascript(url_for(url_options)))}'"
function << ", #{javascript_options})"
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index e7ec1df2c8..59e6ce878f 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -26,7 +26,7 @@ module ActionView
#
# E.g. the value returned for a missing translation key :"blog.post.title" will be
# <span class="translation_missing" title="translation missing: blog.post.title">Title</span>.
- # This way your views will display rather reasonableful strings but it will still
+ # This way your views will display rather reasonable strings but it will still
# be easy to spot missing translations.
#
# Second, it'll scope the key by the current partial if the key starts
diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml
index 9004e52c5b..eb816b9446 100644
--- a/actionpack/lib/action_view/locale/en.yml
+++ b/actionpack/lib/action_view/locale/en.yml
@@ -5,7 +5,7 @@
format:
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
separator: "."
- # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
+ # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three)
delimiter: ","
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
precision: 3
diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb
index 0803114f44..a36837afc8 100644
--- a/actionpack/lib/action_view/template/handlers/erb.rb
+++ b/actionpack/lib/action_view/template/handlers/erb.rb
@@ -63,7 +63,7 @@ module ActionView
class_attribute :default_format
self.default_format = Mime::HTML
- # Default implemenation used.
+ # Default implementation used.
class_attribute :erb_implementation
self.erb_implementation = Erubis
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 4d999fb3b2..6c1063592f 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -5,6 +5,25 @@ require "action_view/template"
module ActionView
# = Action View Resolver
class Resolver
+ # Keeps all information about view path and builds virtual path.
+ class Path < String
+ attr_reader :name, :prefix, :partial, :virtual
+ alias_method :partial?, :partial
+
+ def initialize(name, prefix, partial)
+ @name, @prefix, @partial = name, prefix, partial
+ rebuild(@name, @prefix, @partial)
+ end
+
+ def rebuild(name, prefix, partial)
+ @virtual = ""
+ @virtual << "#{prefix}/" unless prefix.empty?
+ @virtual << (partial ? "_#{name}" : name)
+
+ self.replace(@virtual)
+ end
+ end
+
cattr_accessor :caching
self.caching = true
@@ -36,15 +55,12 @@ module ActionView
# because Resolver guarantees that the arguments are present and
# normalized.
def find_templates(name, prefix, partial, details)
- raise NotImplementedError
+ raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details) method"
end
# Helpers that builds a path. Useful for building virtual paths.
def build_path(name, prefix, partial)
- path = ""
- path << "#{prefix}/" unless prefix.empty?
- path << (partial ? "_#{name}" : name)
- path
+ Path.new(name, prefix, partial)
end
# Handles templates caching. If a key is given and caching is on
@@ -97,25 +113,24 @@ module ActionView
end
class PathResolver < Resolver
- EXTENSION_ORDER = [:locale, :formats, :handlers]
+ EXTENSIONS = [:locale, :formats, :handlers]
+ DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}"
+
+ def initialize(pattern=nil)
+ @pattern = pattern || DEFAULT_PATTERN
+ super()
+ end
private
def find_templates(name, prefix, partial, details)
path = build_path(name, prefix, partial)
- query(path, EXTENSION_ORDER.map { |ext| details[ext] }, details[:formats])
+ extensions = Hash[EXTENSIONS.map { |ext| [ext, details[ext]] }.flatten(0)]
+ query(path, extensions, details[:formats])
end
def query(path, exts, formats)
- query = File.join(@path, path)
-
- query << exts.map { |ext|
- "{#{ext.compact.map { |e| ".#{e}" }.join(',')},}"
- }.join
-
- query.gsub!(/\{\.html,/, "{.html,.text.html,")
- query.gsub!(/\{\.text,/, "{.text,.text.plain,")
-
+ query = build_query(path, exts)
templates = []
sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] }
@@ -126,12 +141,28 @@ module ActionView
contents = File.open(p, "rb") {|io| io.read }
templates << Template.new(contents, File.expand_path(p), handler,
- :virtual_path => path, :format => format, :updated_at => mtime(p))
+ :virtual_path => path.virtual, :format => format, :updated_at => mtime(p))
end
templates
end
+ # Helper for building query glob string based on resolver's pattern.
+ def build_query(path, exts)
+ query = @pattern.dup
+ query.gsub!(/\:prefix(\/)?/, path.prefix.empty? ? "" : "#{path.prefix}\\1") # prefix can be empty...
+ query.gsub!(/\:action/, path.partial? ? "_#{path.name}" : path.name)
+
+ exts.each { |ext, variants|
+ query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}")
+ }
+
+ query.gsub!(/\.{html,/, ".{html,text.html,")
+ query.gsub!(/\.{text,/, ".{text,text.plain,")
+
+ File.expand_path(query, @path)
+ end
+
# Returns the file mtime from the filesystem.
def mtime(p)
File.stat(p).mtime
@@ -149,11 +180,47 @@ module ActionView
end
end
- # A resolver that loads files from the filesystem.
+ # A resolver that loads files from the filesystem. It allows to set your own
+ # resolving pattern. Such pattern can be a glob string supported by some variables.
+ #
+ # ==== Examples
+ #
+ # Default pattern, loads views the same way as previous versions of rails, eg. when you're
+ # looking for `users/new` it will produce query glob: `users/new{.{en},}{.{html,js},}{.{erb,haml,rjs},}`
+ #
+ # FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}")
+ #
+ # This one allows you to keep files with different formats in seperated subdirectories,
+ # eg. `users/new.html` will be loaded from `users/html/new.erb` or `users/new.html.erb`,
+ # `users/new.js` from `users/js/new.erb` or `users/new.js.erb`, etc.
+ #
+ # FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{.:handlers,}")
+ #
+ # If you don't specify pattern then the default will be used.
+ #
+ # In order to use any of the customized resolvers above in a Rails application, you just need
+ # to configure ActionController::Base.view_paths in an initializer, for example:
+ #
+ # ActionController::Base.view_paths = FileSystemResolver.new(
+ # Rails.root.join("app/views"),
+ # ":prefix{/:locale}/:action{.:formats,}{.:handlers,}"
+ # )
+ #
+ # ==== Pattern format and variables
+ #
+ # Pattern have to be a valid glob string, and it allows you to use the
+ # following variables:
+ #
+ # * <tt>:prefix</tt> - usualy the controller path
+ # * <tt>:action</tt> - name of the action
+ # * <tt>:locale</tt> - possible locale versions
+ # * <tt>:formats</tt> - possible request formats (for example html, json, xml...)
+ # * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
+ #
class FileSystemResolver < PathResolver
- def initialize(path)
+ def initialize(path, pattern=nil)
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
- super()
+ super(pattern)
@path = File.expand_path(path)
end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 2ce109ea99..3e2ddffa16 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -185,6 +185,7 @@ module ActionView
@request
@routes
@templates
+ @options
@test_passed
@view
@view_context_class
diff --git a/actionpack/lib/action_view/testing/resolvers.rb b/actionpack/lib/action_view/testing/resolvers.rb
index 5c5cab7c7d..773dfcbb1d 100644
--- a/actionpack/lib/action_view/testing/resolvers.rb
+++ b/actionpack/lib/action_view/testing/resolvers.rb
@@ -8,8 +8,8 @@ module ActionView #:nodoc:
class FixtureResolver < PathResolver
attr_reader :hash
- def initialize(hash = {})
- super()
+ def initialize(hash = {}, pattern=nil)
+ super(pattern)
@hash = hash
end
@@ -21,8 +21,8 @@ module ActionView #:nodoc:
def query(path, exts, formats)
query = ""
- exts.each do |ext|
- query << '(' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)'
+ EXTENSIONS.each do |ext|
+ query << '(' << exts[ext].map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)'
end
query = /^(#{Regexp.escape(path)})#{query}$/
@@ -32,9 +32,9 @@ module ActionView #:nodoc:
next unless _path =~ query
handler, format = extract_handler_and_format(_path, formats)
templates << Template.new(source, _path, handler,
- :virtual_path => $1, :format => format, :updated_at => updated_at)
+ :virtual_path => path.virtual, :format => format, :updated_at => updated_at)
end
-
+
templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
end
end