actionpack 1.5.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +35 -0
- data/lib/action_controller.rb +4 -7
- data/lib/action_controller/base.rb +0 -3
- data/lib/action_controller/caching.rb +3 -1
- data/lib/action_controller/cgi_process.rb +13 -8
- data/lib/action_controller/components.rb +3 -3
- data/lib/action_controller/request.rb +5 -1
- data/lib/action_controller/routing.rb +4 -4
- data/lib/action_controller/session/active_record_store.rb +23 -10
- data/lib/action_view/helpers/active_record_helper.rb +15 -13
- data/lib/action_view/helpers/asset_tag_helper.rb +6 -6
- data/lib/action_view/helpers/date_helper.rb +26 -30
- data/lib/action_view/helpers/form_helper.rb +82 -54
- data/lib/action_view/helpers/form_options_helper.rb +27 -23
- data/lib/action_view/helpers/form_tag_helper.rb +18 -18
- data/lib/action_view/helpers/tag_helper.rb +4 -4
- data/lib/action_view/helpers/text_helper.rb +11 -11
- data/lib/action_view/helpers/url_helper.rb +48 -33
- data/rakefile +2 -2
- data/test/controller/request_test.rb +12 -1
- data/test/controller/routing_tests.rb +24 -0
- data/test/template/active_record_helper_test.rb +1 -1
- data/test/template/asset_tag_helper_test.rb +4 -4
- data/test/template/form_helper_test.rb +32 -25
- data/test/template/form_options_helper_test.rb +14 -10
- data/test/template/form_tag_helper_test.rb +3 -2
- data/test/template/tag_helper_test.rb +8 -5
- data/test/template/text_helper_test.rb +7 -7
- data/test/template/url_helper_test.rb +51 -18
- metadata +4 -5
- data/test/template/url_helper_test.rb.rej +0 -105
data/CHANGELOG
CHANGED
@@ -1,3 +1,38 @@
|
|
1
|
+
*1.5.1* (7th March, 2005)
|
2
|
+
|
3
|
+
* Fixed that the routes.rb file wouldn't be found on symlinked setups due to File.expand_path #793 [piotr@t-p-l.com]
|
4
|
+
|
5
|
+
* Changed ActiveRecordStore to use Marshal instead of YAML as the latter proved troublesome in persisting circular dependencies. Updating existing applications MUST clear their existing session table from data to start using this updated store #739 [Jamis Buck]
|
6
|
+
|
7
|
+
* Added shortcut :id assignment to render_component and friends (before you had to go through :params) #784 [Lucas Carlson]
|
8
|
+
|
9
|
+
* Fixed that map.connect should convert arguments to strings #780 [Nicholas Seckar]
|
10
|
+
|
11
|
+
* Added UrlHelper#link_to_if/link_to_unless to enable other conditions that just link_to_unless_current #757 [mindel]
|
12
|
+
|
13
|
+
* Fixed that single quote was not escaped in a UrlHelper#link_to javascript confirm #549 [Scott Barron]
|
14
|
+
|
15
|
+
* Removed the default border on link_image_to (it broke xhtml strict) -- can be specified with :border => 0 #517 [?/caleb]
|
16
|
+
|
17
|
+
* Fixed that form helpers would treat string and symbol keys differently in html_options (and possibly create duplicate entries) #112 [bitsweat]
|
18
|
+
|
19
|
+
* Fixed that broken pipe errors (clients disconnecting in mid-request) could bring down a fcgi process
|
20
|
+
|
21
|
+
* Added the original exception message to session recall errors (so you can see which class wasnt required)
|
22
|
+
|
23
|
+
* Fixed that RAILS_ROOT might not be defined when AP was loaded, so do a late initialization of the ROUTE_FILE #761 [Scott Barron]
|
24
|
+
|
25
|
+
* Fix request.path_info and clear up LoadingModule behavior #754 [Nicholas Seckar]
|
26
|
+
|
27
|
+
* Fixed caching to be aware of extensions (so you can cache files like api.wsdl or logo.png) #734 [Nicholas Seckar]
|
28
|
+
|
29
|
+
* Fixed that Routes would raise NameErrors if a controller component contains characters that are not valid constant names #733 [Nicholas Seckar]
|
30
|
+
|
31
|
+
* Added PATH_INFO access from the request that allows urls like the following to be interpreted by rails: http://www.example.com/dispatcher.cgi/controller/action -- that makes it possible to use rails as a CGI under lighttpd and would also allow (for example) Rublog to be ported to rails without breaking existing links to Rublog-powered blogs. #728 [Jamis Buck]
|
32
|
+
|
33
|
+
* Fixed that caching the root would result in .html not index.html #731, #734 [alisdair/Nicholas Seckar]
|
34
|
+
|
35
|
+
|
1
36
|
*1.5.0* (24th February, 2005)
|
2
37
|
|
3
38
|
* Added Routing as a replacement for mod_rewrite pretty urls [Nicholas Seckar]. Read more in ActionController::Base.url_for and on http://manuals.rubyonrails.com/read/book/9
|
data/lib/action_controller.rb
CHANGED
@@ -22,16 +22,13 @@
|
|
22
22
|
#++
|
23
23
|
|
24
24
|
$:.unshift(File.dirname(__FILE__))
|
25
|
+
$:.unshift(File.dirname(__FILE__) + "/../../activesupport/lib")
|
25
26
|
|
26
27
|
begin
|
27
|
-
require 'active_support'
|
28
|
+
require 'active_support'
|
28
29
|
rescue LoadError
|
29
|
-
|
30
|
-
|
31
|
-
rescue LoadError
|
32
|
-
require 'rubygems'
|
33
|
-
require_gem 'activesupport'
|
34
|
-
end
|
30
|
+
require 'rubygems'
|
31
|
+
require_gem 'activesupport'
|
35
32
|
end
|
36
33
|
|
37
34
|
require 'action_controller/base'
|
@@ -2,9 +2,6 @@ require 'action_controller/request'
|
|
2
2
|
require 'action_controller/response'
|
3
3
|
require 'action_controller/routing'
|
4
4
|
require 'action_controller/url_rewriter'
|
5
|
-
require 'active_support/class_attribute_accessors'
|
6
|
-
require 'active_support/class_inheritable_attributes'
|
7
|
-
require 'active_support/inflector'
|
8
5
|
require 'drb'
|
9
6
|
|
10
7
|
module ActionController #:nodoc:
|
@@ -90,7 +90,9 @@ module ActionController #:nodoc:
|
|
90
90
|
|
91
91
|
private
|
92
92
|
def page_cache_file(path)
|
93
|
-
(path.empty? ? "/index" : path)
|
93
|
+
name = ((path.empty? || path == "/") ? "/index" : path)
|
94
|
+
name << '.html' unless (name.split('/').last || name).include? '.'
|
95
|
+
return name
|
94
96
|
end
|
95
97
|
|
96
98
|
def page_cache_path(path)
|
@@ -86,7 +86,7 @@ module ActionController #:nodoc:
|
|
86
86
|
ActionController::SessionRestoreError,
|
87
87
|
"Session contained objects where the class definition wasn't available. " +
|
88
88
|
"Remember to require classes for all objects kept in the session. " +
|
89
|
-
"The session has been deleted."
|
89
|
+
"The session has been deleted. (Original exception: #{e.message} [#{e.class}])"
|
90
90
|
)
|
91
91
|
end
|
92
92
|
end
|
@@ -120,14 +120,19 @@ module ActionController #:nodoc:
|
|
120
120
|
convert_content_type!(@headers)
|
121
121
|
$stdout.binmode if $stdout.respond_to?(:binmode)
|
122
122
|
$stdout.sync = false
|
123
|
-
|
123
|
+
|
124
|
+
begin
|
125
|
+
print @cgi.header(@headers)
|
124
126
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
127
|
+
if @cgi.send(:env_table)['REQUEST_METHOD'] == 'HEAD'
|
128
|
+
return
|
129
|
+
elsif @body.respond_to?(:call)
|
130
|
+
@body.call(self)
|
131
|
+
else
|
132
|
+
print @body
|
133
|
+
end
|
134
|
+
rescue Errno::EPIPE => e
|
135
|
+
# lost connection to the FCGI process -- ignore the output, then
|
131
136
|
end
|
132
137
|
end
|
133
138
|
|
@@ -6,13 +6,13 @@ module ActionController #:nodoc:
|
|
6
6
|
# # Performs a method and then lets hello_world output its render
|
7
7
|
# def delegate_action
|
8
8
|
# do_other_stuff_before_hello_world
|
9
|
-
# render_component :controller => "greeter", :action => "hello_world"
|
9
|
+
# render_component :controller => "greeter", :action => "hello_world", :params => { "person" => "david" }
|
10
10
|
# end
|
11
11
|
# end
|
12
12
|
#
|
13
13
|
# class GreeterController < ActionController::Base
|
14
14
|
# def hello_world
|
15
|
-
# render_text "Hello World!"
|
15
|
+
# render_text "#{@params['person']} says, Hello World!"
|
16
16
|
# end
|
17
17
|
# end
|
18
18
|
#
|
@@ -54,7 +54,7 @@ module ActionController #:nodoc:
|
|
54
54
|
request_for_component = @request.dup
|
55
55
|
request_for_component.send(
|
56
56
|
:instance_variable_set, :@parameters,
|
57
|
-
(options[:params] || {}).merge({ "controller" => options[:controller], "action" => options[:action] })
|
57
|
+
(options[:params] || {}).merge({ "controller" => options[:controller], "action" => options[:action], "id" => options[:id] })
|
58
58
|
)
|
59
59
|
return request_for_component
|
60
60
|
end
|
@@ -77,6 +77,10 @@ module ActionController
|
|
77
77
|
(%r{^\w+\://[^/]+(/.*|$)$} =~ env['REQUEST_URI']) ? $1 : env['REQUEST_URI'] # Remove domain, which webrick puts into the request_uri.
|
78
78
|
end
|
79
79
|
|
80
|
+
def path_info
|
81
|
+
(/^(.*)\.html$/ =~ env['PATH_INFO']) ? $1 : env['PATH_INFO']
|
82
|
+
end
|
83
|
+
|
80
84
|
def protocol
|
81
85
|
env["HTTPS"] == "on" ? 'https://' : 'http://'
|
82
86
|
end
|
@@ -86,7 +90,7 @@ module ActionController
|
|
86
90
|
end
|
87
91
|
|
88
92
|
def path
|
89
|
-
|
93
|
+
(path_info && !path_info.empty?) ? path_info : (request_uri ? request_uri.split('?').first : '')
|
90
94
|
end
|
91
95
|
|
92
96
|
def port
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module ActionController
|
2
2
|
# See http://manuals.rubyonrails.com/read/chapter/65
|
3
3
|
module Routing
|
4
|
-
ROUTE_FILE = defined?(RAILS_ROOT) ? File.expand_path(File.join(RAILS_ROOT, 'config', 'routes')) : nil
|
5
|
-
|
6
4
|
class Route #:nodoc:
|
7
5
|
attr_reader :defaults # The defaults hash
|
8
6
|
|
@@ -17,7 +15,7 @@ module ActionController
|
|
17
15
|
raise ArgumentError, "Regexp requirement on #{k}, but #{k} is not in this route's path!" unless @items.include? k
|
18
16
|
@requirements[k] = v
|
19
17
|
else
|
20
|
-
(@items.include?(k) ? @defaults : @requirements)[k] = v
|
18
|
+
(@items.include?(k) ? @defaults : @requirements)[k] = (v.nil? ? nil : v.to_s)
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
@@ -134,6 +132,7 @@ module ActionController
|
|
134
132
|
def eat_path_to_controller(path)
|
135
133
|
path.inject([Controllers, 1]) do |(mod, length), name|
|
136
134
|
name = name.camelize
|
135
|
+
return nil, nil unless /^[A-Z][_a-zA-Z\d]*$/ =~ name
|
137
136
|
controller_name = name + "Controller"
|
138
137
|
return mod.const_get(controller_name), path[length..-1] if mod.const_available? controller_name
|
139
138
|
return nil, nil unless mod.const_available? name
|
@@ -281,7 +280,8 @@ module ActionController
|
|
281
280
|
|
282
281
|
def reload
|
283
282
|
begin
|
284
|
-
|
283
|
+
route_file = defined?(RAILS_ROOT) ? File.join(RAILS_ROOT, 'config', 'routes') : nil
|
284
|
+
require_dependency(route_file) if route_file
|
285
285
|
rescue LoadError, ScriptError => e
|
286
286
|
raise RoutingError, "Cannot load config/routes.rb:\n #{e.message}"
|
287
287
|
ensure # Ensure that there is at least one route:
|
@@ -3,21 +3,25 @@ begin
|
|
3
3
|
require 'active_record'
|
4
4
|
require 'cgi'
|
5
5
|
require 'cgi/session'
|
6
|
+
require 'base64'
|
6
7
|
|
7
8
|
# Contributed by Tim Bates
|
8
9
|
class CGI
|
9
10
|
class Session
|
10
|
-
#
|
11
|
+
# Active Record database-based session storage class.
|
11
12
|
#
|
12
13
|
# Implements session storage in a database using the ActiveRecord ORM library. Assumes that the database
|
13
14
|
# has a table called +sessions+ with columns +id+ (numeric, primary key), +sessid+ and +data+ (text).
|
14
|
-
# The session data is stored in the +data+ column in
|
15
|
-
# only data that can be
|
15
|
+
# The session data is stored in the +data+ column in the binary Marshal format; the user is responsible for ensuring that
|
16
|
+
# only data that can be Marshaled is stored in the session.
|
17
|
+
#
|
18
|
+
# Adding +created_at+ or +updated_at+ datetime columns to the sessions table will enable stamping of the data, which can
|
19
|
+
# be used to clear out old sessions.
|
20
|
+
#
|
21
|
+
# It's highly recommended to have an index on the sessid column to improve performance.
|
16
22
|
class ActiveRecordStore
|
17
23
|
# The ActiveRecord class which corresponds to the database table.
|
18
24
|
class Session < ActiveRecord::Base
|
19
|
-
serialize :data
|
20
|
-
# Isn't this class definition beautiful?
|
21
25
|
end
|
22
26
|
|
23
27
|
# Create a new ActiveRecordStore instance. This constructor is used internally by CGI::Session.
|
@@ -30,8 +34,8 @@ class CGI
|
|
30
34
|
# This session's ActiveRecord database row will be created if it does not exist, or opened if it does.
|
31
35
|
def initialize(session, option=nil)
|
32
36
|
ActiveRecord::Base.silence do
|
33
|
-
@session = Session.find_by_sessid(session.session_id) || Session.new("sessid" => session.session_id, "data" => {})
|
34
|
-
@data = @session.data
|
37
|
+
@session = Session.find_by_sessid(session.session_id) || Session.new("sessid" => session.session_id, "data" => marshalize({}))
|
38
|
+
@data = unmarshalize(@session.data)
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
@@ -52,18 +56,27 @@ class CGI
|
|
52
56
|
# Restore session state from the session's ActiveRecord object.
|
53
57
|
def restore
|
54
58
|
return unless @session
|
55
|
-
@data = @session.data
|
59
|
+
@data = unmarshalize(@session.data)
|
56
60
|
end
|
57
61
|
|
58
62
|
# Save session state in the session's ActiveRecord object.
|
59
63
|
def update
|
60
64
|
return unless @session
|
61
|
-
ActiveRecord::Base.silence { @session.update_attribute "data", @data }
|
65
|
+
ActiveRecord::Base.silence { @session.update_attribute "data", marshalize(@data) }
|
62
66
|
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def unmarshalize(data)
|
70
|
+
Marshal.load(Base64.decode64(data))
|
71
|
+
end
|
72
|
+
|
73
|
+
def marshalize(data)
|
74
|
+
Base64.encode64(Marshal.dump(data))
|
75
|
+
end
|
63
76
|
end #ActiveRecordStore
|
64
77
|
end #Session
|
65
78
|
end #CGI
|
66
79
|
|
67
80
|
rescue LoadError
|
68
81
|
# Couldn't load Active Record, so don't make this store available
|
69
|
-
end
|
82
|
+
end
|
@@ -15,7 +15,7 @@ module ActionView
|
|
15
15
|
module ActiveRecordHelper
|
16
16
|
# Returns a default input tag for the type of object returned by the method. Example
|
17
17
|
# (title is a VARCHAR column and holds "Hello World"):
|
18
|
-
# input("post", "title") =>
|
18
|
+
# input("post", "title") =>
|
19
19
|
# <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
|
20
20
|
def input(record_name, method)
|
21
21
|
InstanceTag.new(record_name, method, self).to_tag
|
@@ -41,7 +41,7 @@ module ActionView
|
|
41
41
|
# It's possible to specialize the form builder by using a different action name and by supplying another
|
42
42
|
# block renderer. Example (entry is a new record that has a message attribute using VARCHAR):
|
43
43
|
#
|
44
|
-
# form("entry", :action => "sign", :input_block =>
|
44
|
+
# form("entry", :action => "sign", :input_block =>
|
45
45
|
# Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}<br />" }) =>
|
46
46
|
#
|
47
47
|
# <form action='/post/sign' method='post'>
|
@@ -56,16 +56,17 @@ module ActionView
|
|
56
56
|
# form << content_tag("b", "Department")
|
57
57
|
# form << collection_select("department", "id", @departments, "id", "name")
|
58
58
|
# end
|
59
|
-
def form(record_name, options =
|
60
|
-
|
59
|
+
def form(record_name, options = nil)
|
60
|
+
options = (options || {}).symbolize_keys
|
61
|
+
record = instance_eval("@#{record_name}")
|
61
62
|
|
62
63
|
options[:action] ||= record.new_record? ? "create" : "update"
|
63
|
-
action
|
64
|
+
action = url_for(:action => options[:action])
|
64
65
|
|
65
66
|
submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
|
66
|
-
|
67
|
+
|
67
68
|
id_field = record.new_record? ? "" : InstanceTag.new(record_name, "id", self).to_input_field_tag("hidden")
|
68
|
-
|
69
|
+
|
69
70
|
formtag = %(<form action="#{action}" method="post">#{id_field}) + all_input_tags(record, record_name, options)
|
70
71
|
yield formtag if block_given?
|
71
72
|
formtag + %(<input type="submit" value="#{submit_value}" /></form>)
|
@@ -73,7 +74,7 @@ module ActionView
|
|
73
74
|
|
74
75
|
# Returns a string containing the error message attached to the +method+ on the +object+, if one exists.
|
75
76
|
# This error message is wrapped in a DIV tag, which can be specialized to include both a +prepend_text+ and +append_text+
|
76
|
-
# to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message
|
77
|
+
# to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message
|
77
78
|
# "can't be empty" on the title attribute):
|
78
79
|
#
|
79
80
|
# <%= error_message_on "post", "title" %> =>
|
@@ -86,19 +87,20 @@ module ActionView
|
|
86
87
|
"<div class=\"#{css_class}\">#{prepend_text + (errors.is_a?(Array) ? errors.first : errors) + append_text}</div>"
|
87
88
|
end
|
88
89
|
end
|
89
|
-
|
90
|
+
|
90
91
|
# Returns a string with a div containing all the error messages for the object located as an instance variable by the name
|
91
92
|
# of <tt>object_name</tt>. This div can be tailored by the following options:
|
92
93
|
#
|
93
94
|
# * <tt>header_tag</tt> - Used for the header of the error div (default: h2)
|
94
95
|
# * <tt>id</tt> - The id of the error div (default: errorExplanation)
|
95
96
|
# * <tt>class</tt> - The class of the error div (default: errorExplanation)
|
96
|
-
def error_messages_for(object_name, options={})
|
97
|
+
def error_messages_for(object_name, options = {})
|
98
|
+
options = options.symbolize_keys
|
97
99
|
object = instance_eval "@#{object_name}"
|
98
100
|
unless object.errors.empty?
|
99
101
|
content_tag("div",
|
100
102
|
content_tag(
|
101
|
-
options[:header_tag] || "h2",
|
103
|
+
options[:header_tag] || "h2",
|
102
104
|
"#{pluralize(object.errors.count, "error")} prohibited this #{object_name.gsub("_", " ")} from being saved"
|
103
105
|
) +
|
104
106
|
content_tag("p", "There were problems with the following fields:") +
|
@@ -107,7 +109,7 @@ module ActionView
|
|
107
109
|
)
|
108
110
|
end
|
109
111
|
end
|
110
|
-
|
112
|
+
|
111
113
|
private
|
112
114
|
def all_input_tags(record, record_name, options)
|
113
115
|
input_block = options[:input_block] || default_input_block
|
@@ -116,7 +118,7 @@ module ActionView
|
|
116
118
|
|
117
119
|
def default_input_block
|
118
120
|
Proc.new { |record, column| "<p><label for=\"#{record}_#{column.name}\">#{column.human_name}</label><br />#{input(record, column.name)}</p>" }
|
119
|
-
end
|
121
|
+
end
|
120
122
|
end
|
121
123
|
|
122
124
|
class InstanceTag #:nodoc:
|
@@ -10,15 +10,15 @@ module ActionView
|
|
10
10
|
# either be <tt>:rss</tt> (default) or <tt>:atom</tt> and the +options+ follow the url_for style of declaring a link target.
|
11
11
|
#
|
12
12
|
# Examples:
|
13
|
-
# auto_discovery_link_tag # =>
|
13
|
+
# auto_discovery_link_tag # =>
|
14
14
|
# <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/action" />
|
15
|
-
# auto_discovery_link_tag(:atom) # =>
|
15
|
+
# auto_discovery_link_tag(:atom) # =>
|
16
16
|
# <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/action" />
|
17
|
-
# auto_discovery_link_tag(:rss, :action => "feed") # =>
|
17
|
+
# auto_discovery_link_tag(:rss, :action => "feed") # =>
|
18
18
|
# <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/feed" />
|
19
19
|
def auto_discovery_link_tag(type = :rss, options = {})
|
20
20
|
tag(
|
21
|
-
"link", "rel" => "alternate", "type" => "application/#{type}+xml", "title" => type.to_s.upcase,
|
21
|
+
"link", "rel" => "alternate", "type" => "application/#{type}+xml", "title" => type.to_s.upcase,
|
22
22
|
"href" => url_for(options.merge(:only_path => false))
|
23
23
|
)
|
24
24
|
end
|
@@ -38,7 +38,7 @@ module ActionView
|
|
38
38
|
content_tag("script", "", "language" => "JavaScript", "type" => "text/javascript", "src" => source)
|
39
39
|
}.join("\n")
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# Returns a css link tag per source given as argument. Examples:
|
43
43
|
#
|
44
44
|
# stylesheet_link_tag "style" # =>
|
@@ -48,7 +48,7 @@ module ActionView
|
|
48
48
|
# <link href="/stylesheets/random.styles" media="screen" rel="Stylesheet" type="text/css" />
|
49
49
|
# <link href="/css/stylish.css" media="screen" rel="Stylesheet" type="text/css" />
|
50
50
|
def stylesheet_link_tag(*sources)
|
51
|
-
sources.collect { |source|
|
51
|
+
sources.collect { |source|
|
52
52
|
source = "/stylesheets/#{source}" unless source.include?("/")
|
53
53
|
source = "#{source}.css" unless source.include?(".")
|
54
54
|
tag("link", "rel" => "Stylesheet", "type" => "text/css", "media" => "screen", "href" => source)
|
@@ -5,7 +5,7 @@ module ActionView
|
|
5
5
|
# The Date Helper primarily creates select/option tags for different kinds of dates and date elements. All of the select-type methods
|
6
6
|
# share a number of common options that are as follows:
|
7
7
|
#
|
8
|
-
# * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" would give
|
8
|
+
# * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" would give
|
9
9
|
# birthday[month] instead of date[month] if passed to the select_month method.
|
10
10
|
# * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date.
|
11
11
|
# * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true, the select_month
|
@@ -13,11 +13,11 @@ module ActionView
|
|
13
13
|
module DateHelper
|
14
14
|
DEFAULT_PREFIX = "date" unless const_defined?("DEFAULT_PREFIX")
|
15
15
|
|
16
|
-
# Reports the approximate distance in time between to Time objects. For example, if the distance is 47 minutes, it'll return
|
16
|
+
# Reports the approximate distance in time between to Time objects. For example, if the distance is 47 minutes, it'll return
|
17
17
|
# "about 1 hour". See the source for the complete wording list.
|
18
18
|
def distance_of_time_in_words(from_time, to_time)
|
19
19
|
distance_in_minutes = ((to_time - from_time) / 60).round
|
20
|
-
|
20
|
+
|
21
21
|
case distance_in_minutes
|
22
22
|
when 0 then "less than a minute"
|
23
23
|
when 1 then "1 minute"
|
@@ -28,7 +28,7 @@ module ActionView
|
|
28
28
|
else "#{(distance_in_minutes / 1440).round} days"
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
# Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
|
33
33
|
def distance_of_time_in_words_to_now(from_time)
|
34
34
|
distance_of_time_in_words(from_time, Time.now)
|
@@ -48,7 +48,7 @@ module ActionView
|
|
48
48
|
#
|
49
49
|
# date_select("post", "written_on")
|
50
50
|
# date_select("post", "written_on", :start_year => 1995)
|
51
|
-
# date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true,
|
51
|
+
# date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true,
|
52
52
|
# :discard_day => true, :include_blank => true)
|
53
53
|
# date_select("post", "written_on", :order => [:day, :month, :year])
|
54
54
|
# date_select("user", "birthday", :order => [:month, :day])
|
@@ -107,7 +107,7 @@ module ActionView
|
|
107
107
|
|
108
108
|
0.upto(59) do |minute|
|
109
109
|
minute_options << ((datetime.kind_of?(Fixnum) ? datetime : datetime.min) == minute ?
|
110
|
-
"<option selected=\"selected\">#{leading_zero_on_single_digits(minute)}</option>\n" :
|
110
|
+
"<option selected=\"selected\">#{leading_zero_on_single_digits(minute)}</option>\n" :
|
111
111
|
"<option>#{leading_zero_on_single_digits(minute)}</option>\n"
|
112
112
|
)
|
113
113
|
end
|
@@ -122,7 +122,7 @@ module ActionView
|
|
122
122
|
|
123
123
|
0.upto(23) do |hour|
|
124
124
|
hour_options << ((datetime.kind_of?(Fixnum) ? datetime : datetime.hour) == hour ?
|
125
|
-
"<option selected=\"selected\">#{leading_zero_on_single_digits(hour)}</option>\n" :
|
125
|
+
"<option selected=\"selected\">#{leading_zero_on_single_digits(hour)}</option>\n" :
|
126
126
|
"<option>#{leading_zero_on_single_digits(hour)}</option>\n"
|
127
127
|
)
|
128
128
|
end
|
@@ -137,18 +137,18 @@ module ActionView
|
|
137
137
|
|
138
138
|
1.upto(31) do |day|
|
139
139
|
day_options << ((date.kind_of?(Fixnum) ? date : date.day) == day ?
|
140
|
-
"<option selected=\"selected\">#{day}</option>\n" :
|
140
|
+
"<option selected=\"selected\">#{day}</option>\n" :
|
141
141
|
"<option>#{day}</option>\n"
|
142
142
|
)
|
143
143
|
end
|
144
144
|
|
145
145
|
select_html("day", day_options, options[:prefix], options[:include_blank], options[:discard_type])
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
# Returns a select tag with options for each of the months January through December with the current month selected.
|
149
149
|
# The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are used as values
|
150
150
|
# (what's submitted to the server). It's also possible to use month numbers for the presentation instead of names --
|
151
|
-
# set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names,
|
151
|
+
# set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names,
|
152
152
|
# set the <tt>:add_month_numbers</tt> key in +options+ to true. Examples:
|
153
153
|
#
|
154
154
|
# select_month(Date.today) # Will use keys like "January", "March"
|
@@ -158,7 +158,7 @@ module ActionView
|
|
158
158
|
month_options = []
|
159
159
|
|
160
160
|
1.upto(12) do |month_number|
|
161
|
-
month_name = if options[:use_month_numbers]
|
161
|
+
month_name = if options[:use_month_numbers]
|
162
162
|
month_number
|
163
163
|
elsif options[:add_month_numbers]
|
164
164
|
month_number.to_s + " - " + Date::MONTHNAMES[month_number]
|
@@ -167,16 +167,16 @@ module ActionView
|
|
167
167
|
end
|
168
168
|
|
169
169
|
month_options << ((date.kind_of?(Fixnum) ? date : date.month) == month_number ?
|
170
|
-
%(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
|
170
|
+
%(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
|
171
171
|
%(<option value="#{month_number}">#{month_name}</option>\n)
|
172
172
|
)
|
173
173
|
end
|
174
174
|
|
175
175
|
select_html("month", month_options, options[:prefix], options[:include_blank], options[:discard_type])
|
176
176
|
end
|
177
|
-
|
177
|
+
|
178
178
|
# Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius
|
179
|
-
# can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. The <tt>date</tt> can also be substituted
|
179
|
+
# can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. The <tt>date</tt> can also be substituted
|
180
180
|
# for a year given as a number. Example:
|
181
181
|
#
|
182
182
|
# select_year(Date.today, :start_year => 1992, :end_year => 2007)
|
@@ -187,14 +187,14 @@ module ActionView
|
|
187
187
|
|
188
188
|
(options[:start_year] || default_start_year).upto(options[:end_year] || default_end_year) do |year|
|
189
189
|
year_options << ((date.kind_of?(Fixnum) ? date : date.year) == year ?
|
190
|
-
"<option selected=\"selected\">#{year}</option>\n" :
|
190
|
+
"<option selected=\"selected\">#{year}</option>\n" :
|
191
191
|
"<option>#{year}</option>\n"
|
192
192
|
)
|
193
193
|
end
|
194
194
|
|
195
195
|
select_html("year", year_options, options[:prefix], options[:include_blank], options[:discard_type])
|
196
196
|
end
|
197
|
-
|
197
|
+
|
198
198
|
private
|
199
199
|
def select_html(type, options, prefix = nil, include_blank = false, discard_type = false)
|
200
200
|
select_html = %(<select name="#{prefix || DEFAULT_PREFIX})
|
@@ -206,7 +206,7 @@ module ActionView
|
|
206
206
|
|
207
207
|
return select_html
|
208
208
|
end
|
209
|
-
|
209
|
+
|
210
210
|
def leading_zero_on_single_digits(number)
|
211
211
|
number > 9 ? number : "0#{number}"
|
212
212
|
end
|
@@ -217,36 +217,32 @@ module ActionView
|
|
217
217
|
|
218
218
|
def to_date_select_tag(options = {})
|
219
219
|
defaults = { :discard_type => true }
|
220
|
-
options = defaults.merge(options)
|
221
|
-
options_with_prefix = Proc.new { |position| options.
|
220
|
+
options = defaults.merge(options)
|
221
|
+
options_with_prefix = Proc.new { |position| options.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") }
|
222
222
|
date = options[:include_blank] ? (value || 0) : (value || Date.today)
|
223
223
|
|
224
224
|
date_select = ""
|
225
|
-
|
226
|
-
if options[:month_before_year] # For backwards compatibility
|
227
|
-
options[:order] = [:month, :year, :day]
|
228
|
-
end
|
229
|
-
|
225
|
+
options[:order] = [:month, :year, :day] if options[:month_before_year] # For backwards compatibility
|
230
226
|
options[:order] ||= [:year, :month, :day]
|
231
227
|
|
232
228
|
position = {:year => 1, :month => 2, :day => 3}
|
233
|
-
|
229
|
+
|
234
230
|
discard = {}
|
235
231
|
discard[:year] = true if options[:discard_year]
|
236
232
|
discard[:month] = true if options[:discard_month]
|
237
233
|
discard[:day] = true if options[:discard_day] or options[:discard_month]
|
238
|
-
|
234
|
+
|
239
235
|
options[:order].each do |param|
|
240
236
|
date_select << self.send("select_#{param}", date, options_with_prefix.call(position[param])) unless discard[param]
|
241
237
|
end
|
242
238
|
|
243
239
|
return date_select
|
244
240
|
end
|
245
|
-
|
241
|
+
|
246
242
|
def to_datetime_select_tag(options = {})
|
247
243
|
defaults = { :discard_type => true }
|
248
|
-
options = defaults.merge(options)
|
249
|
-
options_with_prefix = Proc.new { |position| options.
|
244
|
+
options = defaults.merge(options)
|
245
|
+
options_with_prefix = Proc.new { |position| options.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") }
|
250
246
|
datetime = options[:include_blank] ? (value || 0) : (value || Time.now)
|
251
247
|
|
252
248
|
datetime_select = select_year(datetime, options_with_prefix.call(1))
|
@@ -254,7 +250,7 @@ module ActionView
|
|
254
250
|
datetime_select << select_day(datetime, options_with_prefix.call(3)) unless options[:discard_day] || options[:discard_month]
|
255
251
|
datetime_select << " — " + select_hour(datetime, options_with_prefix.call(4)) unless options[:discard_hour]
|
256
252
|
datetime_select << " : " + select_minute(datetime, options_with_prefix.call(5)) unless options[:discard_minute] || options[:discard_hour]
|
257
|
-
|
253
|
+
|
258
254
|
return datetime_select
|
259
255
|
end
|
260
256
|
end
|