actionpack 1.0.1 → 1.1.0

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 CHANGED
@@ -1,3 +1,29 @@
1
+ *1.1.0*
2
+
3
+ * Added search through session to clear out association caches at the end of each request. This makes it possible to place Active Record objects
4
+ in the session without worrying about stale data in the associations (the main object is still subject to caching, naturally) #347 [Tobias Luetke]
5
+
6
+ * Added more informative exception when using helper :some_helper and the helper requires another file that fails, you'll get an
7
+ error message tells you what file actually failed to load, rather than falling back on assuming it was the helper file itself #346 [dblack]
8
+
9
+ * Added use of *_before_type_cast for all input and text fields. This is helpful for getting "100,000" back on a integer-based
10
+ validation where the value would normally be "100".
11
+
12
+ * Added Request#port_string to get something like ":8080" back on 8080 and "" on 80 (or 443 with https).
13
+
14
+ * Added Request#domain (returns string) and Request#subdomains (returns array).
15
+
16
+ * Added POST support for the breakpoint retries, so form processing that raises an exception can be retried with the original request [Florian Gross]
17
+
18
+ * Fixed regression with Base#reset_session that wouldn't use the the DEFAULT_SESSION_OPTIONS [adam@the-kramers.net]
19
+
20
+ * Fixed error rendering of rxml documents to not just swallow the exception and return 0 (still not guessing the right line, but hey)
21
+
22
+ * Fixed that textilize and markdown would instantiate their engines even on empty strings. This also fixes #333 [Ulysses]
23
+
24
+ * Fixed UrlHelper#link_to_unless so it doesn't care if the id is a string or fixnum [zenspider]
25
+
26
+
1
27
  *1.0.1*
2
28
 
3
29
  * Fixed a bug that would cause an ApplicationController to require itself three times and hence cause filters to be run three times [evl]
@@ -32,6 +32,7 @@ require 'action_controller/benchmarking'
32
32
  require 'action_controller/filters'
33
33
  require 'action_controller/layout'
34
34
  require 'action_controller/flash'
35
+ require 'action_controller/session'
35
36
  require 'action_controller/dependencies'
36
37
  require 'action_controller/scaffolding'
37
38
  require 'action_controller/helpers'
@@ -48,6 +49,7 @@ ActionController::Base.class_eval do
48
49
  include ActionController::Scaffolding
49
50
  include ActionController::Helpers
50
51
  include ActionController::Cookies
52
+ include ActionController::Session
51
53
  end
52
54
 
53
55
  require 'action_view'
@@ -431,7 +431,7 @@ module ActionController #:nodoc:
431
431
  # http://www.mnot.net/cache_docs/ for an overview of web caching and
432
432
  # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
433
433
  # for the Cache-Control header spec.
434
- def send_file(path, options = {})
434
+ def send_file(path, options = {}) #:doc:
435
435
  raise MissingFile unless File.file?(path) and File.readable?(path)
436
436
 
437
437
  options[:length] ||= File.size(path)
@@ -483,7 +483,7 @@ module ActionController #:nodoc:
483
483
  # send_data image.data, :type => image.content_type, :disposition => 'inline'
484
484
  #
485
485
  # See +send_file+ for more information on HTTP Content-* headers and caching.
486
- def send_data(data, options = {})
486
+ def send_data(data, options = {}) #:doc:
487
487
  logger.info "Sending data #{options[:filename]}" unless logger.nil?
488
488
  send_file_headers! options.merge(:length => data.size)
489
489
  render_text data
@@ -92,7 +92,7 @@ module ActionController #:nodoc:
92
92
 
93
93
  private
94
94
  def new_session
95
- CGI::Session.new(@cgi, DEFAULT_SESSION_OPTIONS.merge(@session_options).merge("new_session" => true))
95
+ CGI::Session.new(@cgi, session_options_with_string_keys.merge("new_session" => true))
96
96
  end
97
97
 
98
98
  def session_options_with_string_keys
@@ -55,8 +55,13 @@ module ActionController #:nodoc:
55
55
  class_name = Inflector.camelize(file_name)
56
56
  begin
57
57
  require_dependency(file_name)
58
- rescue LoadError
59
- raise LoadError, "Missing helper file helpers/#{file_name}.rb"
58
+ rescue LoadError => load_error
59
+ requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
60
+ if requiree == file_name
61
+ raise LoadError, "Missing helper file helpers/#{file_name}.rb"
62
+ else
63
+ raise LoadError, "Can't load file: #{requiree}"
64
+ end
60
65
  end
61
66
  raise ArgumentError, "Missing #{class_name} module in helpers/#{file_name}.rb" unless Object.const_defined?(class_name)
62
67
  add_template_helper(Object.const_get(class_name))
@@ -114,6 +114,15 @@ module ActionController #:nodoc:
114
114
  # If you have a layout that by default is applied to all the actions of a controller, you still have the option to rendering
115
115
  # a given action without a layout. Just use the method <tt>render_without_layout</tt>, which works just like Base.render --
116
116
  # it just doesn't apply any layouts.
117
+ #
118
+ # == Automatic layout assignment
119
+ #
120
+ # If there is a template in <tt>app/views/layouts/</tt> with the same name as the current controller then it will be automatically
121
+ # set as that controller's layout unless explicitly told otherwise. Say you have a WeblogController, for example. If a template named
122
+ # <tt>app/views/layouts/weblog.rhtml</tt> or <tt>app/views/layouts/weblog.rxml</tt> exists then it will be automatically set as
123
+ # the layout for your WeblogController. You can create a layout with the name <tt>application.rhtml</tt> or <tt>application.rxml</tt>
124
+ # and this will be set as the default controller if there is no layout with the same name as the current controller and there is
125
+ # no layout explicitly assigned with the +layout+ method. Setting a layout explicity will always override the automatic behaviour.
117
126
  module ClassMethods
118
127
  # If a layout is specified, all actions rendered through render and render_action will have their result assigned
119
128
  # to <tt>@content_for_layout</tt>, which can then be used by the layout to insert their contents with
@@ -50,6 +50,20 @@ module ActionController
50
50
  return env['REMOTE_ADDR']
51
51
  end
52
52
 
53
+ # Returns the domain part of a host, such as rubyonrails.org in "www.rubyonrails.org". You can specify
54
+ # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
55
+ def domain(tld_length = 1)
56
+ host.split(".").last(1 + tld_length).join(".")
57
+ end
58
+
59
+ # Returns all the subdomains as an array, so ["dev", "www"] would be returned for "dev.www.rubyonrails.org".
60
+ # You can specify a different <tt>tld_length</tt>, such as 2 to catch ["www"] instead of ["www", "rubyonrails"]
61
+ # in "www.rubyonrails.co.uk".
62
+ def subdomains(tld_length = 1)
63
+ parts = host.split(".")
64
+ parts - parts.last(1 + tld_length)
65
+ end
66
+
53
67
  def request_uri
54
68
  env["REQUEST_URI"]
55
69
  end
@@ -70,14 +84,13 @@ module ActionController
70
84
  env["SERVER_PORT"].to_i
71
85
  end
72
86
 
87
+ # Returns a string like ":8080" if the port is not 80 or 443 while on https.
88
+ def port_string
89
+ (protocol == "http://" && port == 80) || (protocol == "https://" && port == 443) ? "" : ":#{port}"
90
+ end
91
+
73
92
  def host_with_port
74
- if env['HTTP_HOST']
75
- env['HTTP_HOST']
76
- elsif (protocol == "http://" && port == 80) || (protocol == "https://" && port == 443)
77
- host
78
- else
79
- host + ":#{port}"
80
- end
93
+ env['HTTP_HOST'] || host + port_string
81
94
  end
82
95
 
83
96
  #--
@@ -0,0 +1,14 @@
1
+ module ActionController #:nodoc:
2
+ module Session #:nodoc:
3
+ def self.append_features(base) #:nodoc:
4
+ super #:nodoc:
5
+ base.after_filter(:clear_persistant_model_associations)
6
+ end
7
+
8
+ private
9
+ def clear_persistant_model_associations #:doc:
10
+ session = @session.instance_variable_get("@data")
11
+ session.each { |key, obj| obj.clear_association_cache if obj.respond_to?(:clear_association_cache) } if session
12
+ end
13
+ end
14
+ end
@@ -1,4 +1,15 @@
1
- <% if defined?(Breakpoint) then %><a href="?BP-RETRY=1">Retry with Breakpoint</a><% end %>
1
+ <% if defined?(Breakpoint) %>
2
+ <br /><br />
3
+ <%= form_tag({}, "method" => @request.method) %>
4
+ <input type="hidden" name="BP-RETRY" value="1" />
5
+
6
+ <% for key, value in @request.params %>
7
+ <input type="hidden" name="<%= key %>" value="<%= value %>" />
8
+ <% end %>
9
+
10
+ <input type="submit" value="Retry with Breakpoint" />
11
+ </form>
12
+ <% end %>
2
13
 
3
14
  <%
4
15
  request_parameters_without_action = @request.parameters.clone
@@ -37,6 +37,10 @@ module ActionController #:nodoc:
37
37
  @cookies.freeze
38
38
  end
39
39
 
40
+ def port=(number)
41
+ @env["SERVER_PORT"] = number.to_i
42
+ end
43
+
40
44
  def action=(action_name)
41
45
  @query_parameters.update({ "action" => action_name })
42
46
  @parameters = nil
@@ -132,7 +132,6 @@ module ActionView
132
132
  end
133
133
 
134
134
  alias_method :tag_without_error_wrapping, :tag
135
-
136
135
  def tag(name, options)
137
136
  if object.respond_to?("errors") && object.errors.respond_to?("on")
138
137
  error_wrapping(tag_without_error_wrapping(name, options), object.errors.on(@method_name))
@@ -142,7 +141,6 @@ module ActionView
142
141
  end
143
142
 
144
143
  alias_method :content_tag_without_error_wrapping, :content_tag
145
-
146
144
  def content_tag(name, value, options)
147
145
  if object.respond_to?("errors") && object.errors.respond_to?("on")
148
146
  error_wrapping(content_tag_without_error_wrapping(name, value, options), object.errors.on(@method_name))
@@ -135,15 +135,15 @@ module ActionView
135
135
  html_options.merge!({ "size" => options["maxlength"]}) if options["maxlength"] && !options["size"]
136
136
  html_options.delete("size") if field_type == "hidden"
137
137
  html_options.merge!({ "type" => field_type})
138
- html_options.merge!({ "value" => value.to_s }) unless options["value"]
138
+ html_options.merge!({ "value" => value_before_type_cast }) unless options["value"]
139
139
  add_default_name_and_id(html_options)
140
140
  tag("input", html_options)
141
141
  end
142
142
 
143
143
  def to_radio_button_tag(tag_value, options={})
144
144
  html_options = DEFAULT_FIELD_OPTIONS.merge(options)
145
- html_options.merge!({"checked"=>"checked"}) if value == tag_value
146
- html_options.merge!({"type"=>"radio", "value"=>tag_value.to_s})
145
+ html_options.merge!({ "checked" => "checked" }) if value == tag_value
146
+ html_options.merge!({ "type" => "radio", "value"=> tag_value.to_s })
147
147
 
148
148
  add_default_name_and_id(html_options)
149
149
  tag("input", html_options)
@@ -152,11 +152,11 @@ module ActionView
152
152
  def to_text_area_tag(options = {})
153
153
  options = DEFAULT_TEXT_AREA_OPTIONS.merge(options)
154
154
  add_default_name_and_id(options)
155
- content_tag("textarea", html_escape(value), options)
155
+ content_tag("textarea", html_escape(value_before_type_cast), options)
156
156
  end
157
157
 
158
158
  def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
159
- options.merge!({"checked" => "checked"}) if !value.nil? && ((value.is_a?(TrueClass) || value.is_a?(FalseClass)) ? value : value.to_i > 0)
159
+ options.merge!({ "checked" => "checked" }) if !value.nil? && ((value.is_a?(TrueClass) || value.is_a?(FalseClass)) ? value : value.to_i > 0)
160
160
  options.merge!({ "type" => "checkbox", "value" => checked_value })
161
161
  add_default_name_and_id(options)
162
162
  tag("input", options) << tag("input", ({ "name" => options['name'], "type" => "hidden", "value" => unchecked_value }))
@@ -191,6 +191,14 @@ module ActionView
191
191
  object.send(@method_name) unless object.nil?
192
192
  end
193
193
 
194
+ def value_before_type_cast
195
+ unless object.nil?
196
+ object.respond_to?(@method_name + "_before_type_cast") ?
197
+ object.send(@method_name + "_before_type_cast") :
198
+ object.send(@method_name)
199
+ end
200
+ end
201
+
194
202
  private
195
203
  def add_default_name_and_id(options)
196
204
  options['name'] = tag_name unless options.has_key? "name"
@@ -1,4 +1,5 @@
1
1
  require 'cgi'
2
+ require 'erb'
2
3
 
3
4
  module ActionView
4
5
  module Helpers
@@ -69,7 +69,7 @@ module ActionView
69
69
  # Returns the text with all the Textile codes turned into HTML-tags.
70
70
  # <i>This method is only available if RedCloth can be required</i>.
71
71
  def textilize(text)
72
- RedCloth.new(text).to_html
72
+ text.empty? ? "" : RedCloth.new(text).to_html
73
73
  end
74
74
 
75
75
  # Returns the text with all the Textile codes turned into HTML-tags, but without the regular bounding <p> tag.
@@ -90,7 +90,7 @@ module ActionView
90
90
  # Returns the text with all the Markdown codes turned into HTML-tags.
91
91
  # <i>This method is only available if BlueCloth can be required</i>.
92
92
  def markdown(text)
93
- BlueCloth.new(text).to_html
93
+ text.empty? ? "" : BlueCloth.new(text).to_html
94
94
  end
95
95
  rescue LoadError
96
96
  # We can't really help what's not there
@@ -96,9 +96,9 @@ module ActionView
96
96
  def destination_equal_to_current(options)
97
97
  params_without_location = @params.reject { |key, value| %w( controller action id ).include?(key) }
98
98
 
99
- options[:action] == @params['action'] &&
100
- options[:id] == @params['id'] &&
101
- options[:controller] == @params['controller'] &&
99
+ options[:action].to_s == @params['action'].to_s &&
100
+ options[:id].to_s == @params['id'].to_s &&
101
+ options[:controller].to_s == @params['controller'].to_s &&
102
102
  (options.has_key?(:params) ? params_without_location == options[:params] : true)
103
103
  end
104
104
 
@@ -120,4 +120,4 @@ module ActionView
120
120
  end
121
121
  end
122
122
  end
123
- end
123
+ end
@@ -49,14 +49,13 @@ module ActionView
49
49
  end
50
50
 
51
51
  def line_number
52
- begin
53
- @original_exception.backtrace.join.scan(/\((?:erb)\):([0-9]*)/).first.first.to_i
54
- rescue
55
- begin
56
- original_exception.message.scan(/\((?:eval)\):([0-9]*)/).first.first.to_i
57
- rescue
58
- 1
59
- end
52
+ trace = @original_exception.backtrace.join
53
+ if trace.include?("erb):")
54
+ trace.scan(/\((?:erb)\):([0-9]*)/).first.first.to_i
55
+ elsif trace.include?("eval):")
56
+ trace.scan(/\((?:eval)\):([0-9]*)/).first.first.to_i
57
+ else
58
+ 1
60
59
  end
61
60
  end
62
61
 
data/rakefile CHANGED
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
8
8
 
9
9
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
10
10
  PKG_NAME = 'actionpack'
11
- PKG_VERSION = '1.0.1' + PKG_BUILD
11
+ PKG_VERSION = '1.1.0' + PKG_BUILD
12
12
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
13
13
 
14
14
  desc "Default Task"
@@ -70,6 +70,12 @@ class HelperTest < Test::Unit::TestCase
70
70
  assert_raise(LoadError) { @controller_class.helper :missing }
71
71
  end
72
72
 
73
+ def test_declare_missing_file_from_helper
74
+ require 'broken_helper'
75
+ rescue LoadError => e
76
+ assert_nil /\bbroken_helper\b/.match(e.to_s)[1]
77
+ end
78
+
73
79
  def test_helper_block
74
80
  assert_nothing_raised {
75
81
  @controller_class.helper { def block_helper_method; end }
@@ -107,4 +113,4 @@ class HelperTest < Test::Unit::TestCase
107
113
  self.class.const_set('TestHelper', helper_module)
108
114
  $VERBOSE = old_verbose
109
115
  end
110
- end
116
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/../abstract_unit'
2
+
3
+ class RequestTest < Test::Unit::TestCase
4
+ def setup
5
+ @request = ActionController::TestRequest.new
6
+ end
7
+
8
+ def test_domains
9
+ @request.host = "www.rubyonrails.org"
10
+ assert_equal "rubyonrails.org", @request.domain
11
+
12
+ @request.host = "www.rubyonrails.co.uk"
13
+ assert_equal "rubyonrails.co.uk", @request.domain(2)
14
+ end
15
+
16
+ def test_subdomains
17
+ @request.host = "www.rubyonrails.org"
18
+ assert_equal %w( www ), @request.subdomains
19
+
20
+ @request.host = "www.rubyonrails.co.uk"
21
+ assert_equal %w( www ), @request.subdomains(2)
22
+
23
+ @request.host = "dev.www.rubyonrails.co.uk"
24
+ assert_equal %w( dev www ), @request.subdomains(2)
25
+ end
26
+
27
+ def test_port_string
28
+ @request.port = 80
29
+ assert_equal "", @request.port_string
30
+
31
+ @request.port = 8080
32
+ assert_equal ":8080", @request.port_string
33
+ end
34
+
35
+ def test_host_with_port
36
+ @request.env['HTTP_HOST'] = "rubyonrails.org:8080"
37
+ assert_equal "rubyonrails.org:8080", @request.host_with_port
38
+ @request.env['HTTP_HOST'] = nil
39
+
40
+ @request.host = "rubyonrails.org"
41
+ @request.port = 80
42
+ assert_equal "rubyonrails.org", @request.host_with_port
43
+
44
+ @request.host = "rubyonrails.org"
45
+ @request.port = 81
46
+ assert_equal "rubyonrails.org:81", @request.host_with_port
47
+ end
48
+ end
@@ -14,6 +14,11 @@ class ActiveRecordHelperTest < Test::Unit::TestCase
14
14
  include ActionView::Helpers::UrlHelper
15
15
 
16
16
  Post = Struct.new("Post", :title, :author_name, :body, :secret, :written_on)
17
+ Post.class_eval do
18
+ alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast)
19
+ alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast)
20
+ alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast)
21
+ end
17
22
  Column = Struct.new("Column", :type, :name, :human_name)
18
23
 
19
24
  def setup
@@ -6,7 +6,12 @@ class FormHelperTest < Test::Unit::TestCase
6
6
  include ActionView::Helpers::FormHelper
7
7
 
8
8
  old_verbose, $VERBOSE = $VERBOSE, nil
9
- Post = Struct.new("Post", :title, :author_name, :body, :secret, :written_on)
9
+ Post = Struct.new("Post", :title, :author_name, :body, :secret, :written_on, :cost)
10
+ Post.class_eval do
11
+ alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast)
12
+ alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast)
13
+ alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast)
14
+ end
10
15
  $VERBOSE = old_verbose
11
16
 
12
17
  def setup
@@ -43,6 +43,9 @@ class UrlHelperTest < Test::Unit::TestCase
43
43
  @params = { "controller" => "weblog", "action" => "show"}
44
44
  assert_equal "Showing", link_to_unless_current("Showing", :action => "show", :controller => "weblog")
45
45
  assert "<a href=\"http://www.world.com\">Listing</a>", link_to_unless_current("Listing", :action => "list", :controller => "weblog")
46
+
47
+ @params = { "controller" => "weblog", "action" => "show", "id" => "1"}
48
+ assert_equal "Showing", link_to_unless_current("Showing", :action => "show", :controller => "weblog", :id => 1)
46
49
  end
47
50
 
48
51
  def test_mail_to
@@ -58,4 +61,4 @@ class UrlHelperTest < Test::Unit::TestCase
58
61
  assert "<a href=\"http://www.world.com\">Hello</a>",
59
62
  link_to("Hello", {:action => 'myaction'}, nil)
60
63
  end
61
- end
64
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.1
3
3
  specification_version: 1
4
4
  name: actionpack
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.1
7
- date: 2004-12-17
6
+ version: 1.1.0
7
+ date: 2004-12-23
8
8
  summary: Web-flow and rendering framework putting the VC in MVC.
9
9
  require_paths:
10
10
  - lib
@@ -53,6 +53,7 @@ files:
53
53
  - lib/action_controller/response.rb
54
54
  - lib/action_controller/scaffolding.rb
55
55
  - lib/action_controller/session
56
+ - lib/action_controller/session.rb
56
57
  - lib/action_controller/support
57
58
  - lib/action_controller/templates
58
59
  - lib/action_controller/test_process.rb
@@ -116,6 +117,7 @@ files:
116
117
  - test/controller/layout_test.rb
117
118
  - test/controller/redirect_test.rb
118
119
  - test/controller/render_test.rb
120
+ - test/controller/request_test.rb
119
121
  - test/controller/send_file_test.rb
120
122
  - test/controller/url_test.rb
121
123
  - test/fixtures/helpers