actionpack 1.10.2 → 1.11.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.

Files changed (43) hide show
  1. data/CHANGELOG +57 -3
  2. data/README +7 -7
  3. data/lib/action_controller/assertions.rb +28 -11
  4. data/lib/action_controller/base.rb +22 -15
  5. data/lib/action_controller/caching.rb +6 -6
  6. data/lib/action_controller/components.rb +1 -1
  7. data/lib/action_controller/cookies.rb +3 -3
  8. data/lib/action_controller/dependencies.rb +1 -1
  9. data/lib/action_controller/filters.rb +40 -3
  10. data/lib/action_controller/flash.rb +4 -0
  11. data/lib/action_controller/helpers.rb +1 -1
  12. data/lib/action_controller/layout.rb +2 -1
  13. data/lib/action_controller/pagination.rb +2 -1
  14. data/lib/action_controller/rescue.rb +1 -1
  15. data/lib/action_controller/session/active_record_store.rb +18 -29
  16. data/lib/action_controller/templates/rescues/_trace.rhtml +0 -3
  17. data/lib/action_controller/templates/scaffolds/layout.rhtml +1 -1
  18. data/lib/action_controller/vendor/html-scanner/html/document.rb +2 -2
  19. data/lib/action_pack.rb +24 -0
  20. data/lib/action_pack/version.rb +2 -2
  21. data/lib/action_view/base.rb +1 -1
  22. data/lib/action_view/helpers/asset_tag_helper.rb +21 -3
  23. data/lib/action_view/helpers/form_options_helper.rb +1 -1
  24. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  25. data/lib/action_view/helpers/javascripts/controls.js +18 -5
  26. data/lib/action_view/helpers/javascripts/dragdrop.js +6 -3
  27. data/lib/action_view/helpers/javascripts/effects.js +181 -290
  28. data/lib/action_view/helpers/javascripts/prototype.js +8 -8
  29. data/lib/action_view/helpers/text_helper.rb +22 -0
  30. data/lib/action_view/helpers/url_helper.rb +1 -1
  31. data/lib/action_view/template_error.rb +2 -1
  32. data/rakefile +1 -1
  33. data/test/controller/components_test.rb +5 -0
  34. data/test/controller/filters_test.rb +2 -1
  35. data/test/controller/flash_test.rb +6 -0
  36. data/test/controller/new_render_test.rb +11 -0
  37. data/test/controller/redirect_test.rb +10 -0
  38. data/test/fixtures/layouts/standard.rhtml +1 -1
  39. data/test/template/asset_tag_helper_test.rb +19 -2
  40. data/test/template/javascript_helper_test.rb +1 -0
  41. data/test/template/text_helper_test.rb +9 -0
  42. metadata +5 -4
  43. data/lib/action_view/helpers/javascripts/slider.js +0 -258
@@ -27,7 +27,7 @@ module ActionController #:nodoc:
27
27
  # end
28
28
  #
29
29
  # Also note, that if the models follow the pattern of just 1 class per file in the form of MyClass => my_class.rb, then these
30
- # classes doesn't have to be required as Active Support will auto-require them.
30
+ # classes don't have to be required as Active Support will auto-require them.
31
31
  module ClassMethods
32
32
  # Specifies a variable number of models that this controller depends on. Models are normally Active Record classes or a similar
33
33
  # backend for modelling entity classes.
@@ -41,7 +41,7 @@ module ActionController #:nodoc:
41
41
  #
42
42
  # Now any actions performed on the BankController will have the audit method called before. On the VaultController,
43
43
  # first the audit method is called, then the verify_credentials method. If the audit method returns false, then
44
- # verify_credentials and the intended action is never called.
44
+ # verify_credentials and the intended action are never called.
45
45
  #
46
46
  # == Filter types
47
47
  #
@@ -74,7 +74,7 @@ module ActionController #:nodoc:
74
74
  #
75
75
  # As you can see, the block expects to be passed the controller after it has assigned the request to the internal variables.
76
76
  # This means that the block has access to both the request and response objects complete with convenience methods for params,
77
- # session, template, and assigns. Note: The inline method doesn't strictly has to be a block. Any object that responds to call
77
+ # session, template, and assigns. Note: The inline method doesn't strictly have to be a block; any object that responds to call
78
78
  # and returns 1 or -1 on arity will do (such as a Proc or an Method object).
79
79
  #
80
80
  # == Filter chain ordering
@@ -127,6 +127,25 @@ module ActionController #:nodoc:
127
127
  # end
128
128
  # end
129
129
  #
130
+ # == Filter chain skipping
131
+ #
132
+ # Some times its convenient to specify a filter chain in a superclass that'll hold true for the majority of the
133
+ # subclasses, but not necessarily all of them. The subclasses that behave in exception can then specify which filters
134
+ # they would like to be relieved of. Examples
135
+ #
136
+ # class ApplicationController < ActionController::Base
137
+ # before_filter :authenticate
138
+ # end
139
+ #
140
+ # class WeblogController < ApplicationController
141
+ # # will run the :authenticate filter
142
+ # end
143
+ #
144
+ # class SignupController < ActionController::Base
145
+ # # will not run the :authenticate filter
146
+ # skip_before_filter :authenticate
147
+ # end
148
+ #
130
149
  # == Filter conditions
131
150
  #
132
151
  # Filters can be limited to run for only specific actions. This can be expressed either by listing the actions to
@@ -143,7 +162,7 @@ module ActionController #:nodoc:
143
162
  # end
144
163
  # end
145
164
  #
146
- # When setting conditions on inline method (proc) filters the condition must come first and be placed in parenthesis.
165
+ # When setting conditions on inline method (proc) filters the condition must come first and be placed in parentheses.
147
166
  #
148
167
  # class UserPreferences < ActionController::Base
149
168
  # before_filter(:except => :new) { # some proc ... }
@@ -229,6 +248,24 @@ module ActionController #:nodoc:
229
248
  # Short-hand for append_around_filter since that's the most common of the two.
230
249
  alias :around_filter :append_around_filter
231
250
 
251
+ # Removes the specified filters from the +before+ filter chain. Note that this only works for skipping method-reference
252
+ # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
253
+ # of many sub-controllers need a different hierarchy.
254
+ def skip_before_filter(*filters)
255
+ for filter in filters.flatten
256
+ write_inheritable_attribute("before_filters", read_inheritable_attribute("before_filters") - [ filter ])
257
+ end
258
+ end
259
+
260
+ # Removes the specified filters from the +after+ filter chain. Note that this only works for skipping method-reference
261
+ # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
262
+ # of many sub-controllers need a different hierarchy.
263
+ def skip_after_filter(*filters)
264
+ for filter in filters.flatten
265
+ write_inheritable_attribute("after_filters", read_inheritable_attribute("after_filters") - [ filter ])
266
+ end
267
+ end
268
+
232
269
  # Returns all the before filters for this class and all its ancestors.
233
270
  def before_filters #:nodoc:
234
271
  read_inheritable_attribute("before_filters")
@@ -40,6 +40,10 @@ module ActionController #:nodoc:
40
40
  @flash.discard(k)
41
41
  v
42
42
  end
43
+
44
+ def [](k)
45
+ @flash[k]
46
+ end
43
47
  end
44
48
 
45
49
  class FlashHash < Hash
@@ -19,7 +19,7 @@ module ActionController #:nodoc:
19
19
  end
20
20
  end
21
21
 
22
- # The template helpers serves to relieve the templates from including the same inline code again and again. It's a
22
+ # The template helpers serve to relieve the templates from including the same inline code again and again. It's a
23
23
  # set of standardized methods for working with forms (FormHelper), dates (DateHelper), texts (TextHelper), and
24
24
  # Active Records (ActiveRecordHelper) that's available to all templates by default.
25
25
  #
@@ -24,7 +24,7 @@ module ActionController #:nodoc:
24
24
  # and if you ever want to change the structure of these two includes, you'll have to change all the templates.
25
25
  #
26
26
  # With layouts, you can flip it around and have the common structure know where to insert changing content. This means
27
- # that the header and footer is only mentioned in one place, like this:
27
+ # that the header and footer are only mentioned in one place, like this:
28
28
  #
29
29
  # <!-- The header part of this layout -->
30
30
  # <%= @content_for_layout %>
@@ -219,6 +219,7 @@ module ActionController #:nodoc:
219
219
  end
220
220
 
221
221
  erase_render_results
222
+ add_variables_to_assigns
222
223
  @template.instance_variable_set("@content_for_layout", content_for_layout)
223
224
  render_text(@template.render_file(layout, true), deprecated_status)
224
225
  else
@@ -49,7 +49,8 @@ module ActionController
49
49
  # def list
50
50
  # @person_pages = Paginator.new self, Person.count, 10, @params['page']
51
51
  # @people = Person.find :all, :order => 'last_name, first_name',
52
- # :conditions => @person_pages.current.to_sql
52
+ # :limit => @person_pages.items_per_page,
53
+ # :offset => @person_pages.current.offset
53
54
  # end
54
55
  #
55
56
  # Explicitly creates the paginator from the previous example and uses
@@ -56,7 +56,7 @@ module ActionController #:nodoc:
56
56
  end
57
57
  end
58
58
 
59
- # Overwrite to expand the meaning of a local request in order to show local rescues on other occurences than
59
+ # Overwrite to expand the meaning of a local request in order to show local rescues on other occurrences than
60
60
  # the remote IP being 127.0.0.1. For example, this could include the IP of the developer machine when debugging
61
61
  # remotely.
62
62
  def local_request? #:doc:
@@ -50,10 +50,10 @@ class CGI
50
50
  class ActiveRecordStore
51
51
  # The default Active Record class.
52
52
  class Session < ActiveRecord::Base
53
+ before_update :loaded? # Don't try to save if we haven't loaded the session
53
54
  before_save :marshal_data!
54
55
  before_save :ensure_data_not_too_big
55
- before_update :data_changed?
56
-
56
+
57
57
  class << self
58
58
 
59
59
  # Don't try to reload ARStore::Session in dev mode.
@@ -73,7 +73,6 @@ class CGI
73
73
 
74
74
  def marshal(data) Base64.encode64(Marshal.dump(data)) end
75
75
  def unmarshal(data) Marshal.load(Base64.decode64(data)) end
76
- def fingerprint(data) Digest::MD5.hexdigest(data) end
77
76
 
78
77
  def create_table!
79
78
  connection.execute <<-end_sql
@@ -109,17 +108,14 @@ class CGI
109
108
  end
110
109
  end
111
110
 
112
- # Lazy-unmarshal session state. Take a fingerprint so we can detect
113
- # whether to save changes later.
111
+ # Lazy-unmarshal session state.
114
112
  def data
115
113
  unless @data
116
- case @data = read_attribute('data')
114
+ case data = read_attribute('data')
117
115
  when String
118
- @fingerprint = self.class.fingerprint(@data)
119
- @data = self.class.unmarshal(@data)
120
- when nil
121
- @data = {}
122
- @fingerprint = nil
116
+ @data = self.class.unmarshal(data)
117
+ else
118
+ @data = data || {}
123
119
  end
124
120
  end
125
121
  @data
@@ -127,12 +123,12 @@ class CGI
127
123
 
128
124
  private
129
125
  def marshal_data!
130
- write_attribute('data', self.class.marshal(@data || {}))
126
+ write_attribute('data', self.class.marshal(self.data))
131
127
  end
132
-
133
- def data_changed?
134
- old_fingerprint, @fingerprint = @fingerprint, self.class.fingerprint(read_attribute('data'))
135
- old_fingerprint != @fingerprint
128
+
129
+ # Has the session been loaded yet?
130
+ def loaded?
131
+ !! @data
136
132
  end
137
133
 
138
134
  # Ensures that the data about to be stored in the database is not
@@ -188,7 +184,6 @@ class CGI
188
184
 
189
185
  def marshal(data) Base64.encode64(Marshal.dump(data)) end
190
186
  def unmarshal(data) Marshal.load(Base64.decode64(data)) end
191
- def fingerprint(data) Digest::MD5.hexdigest(data) end
192
187
 
193
188
  def create_table!
194
189
  @@connection.execute <<-end_sql
@@ -220,16 +215,13 @@ class CGI
220
215
  @new_record
221
216
  end
222
217
 
223
- # Lazy-unmarshal session state. Take a fingerprint so we can detect
224
- # whether to save changes later.
218
+ # Lazy-unmarshal session state.
225
219
  def data
226
220
  unless @data
227
221
  if @marshaled_data
228
- @fingerprint = self.class.fingerprint(@marshaled_data)
229
222
  @data, @marshaled_data = self.class.unmarshal(@marshaled_data), nil
230
223
  else
231
224
  @data = {}
232
- @fingerprint = nil
233
225
  end
234
226
  end
235
227
  @data
@@ -249,14 +241,11 @@ class CGI
249
241
  #{@@connection.quote(marshaled_data)} )
250
242
  end_sql
251
243
  else
252
- old_fingerprint, @fingerprint = @fingerprint, self.class.fingerprint(marshaled_data)
253
- if old_fingerprint != @fingerprint
254
- @@connection.update <<-end_sql, 'Update session'
255
- UPDATE #{@@table_name}
256
- SET #{@@connection.quote_column_name(@@data_column)}=#{@@connection.quote(marshaled_data)}
257
- WHERE #{@@connection.quote_column_name(@@session_id_column)}=#{@@connection.quote(session_id)}
258
- end_sql
259
- end
244
+ @@connection.update <<-end_sql, 'Update session'
245
+ UPDATE #{@@table_name}
246
+ SET #{@@connection.quote_column_name(@@data_column)}=#{@@connection.quote(marshaled_data)}
247
+ WHERE #{@@connection.quote_column_name(@@session_id_column)}=#{@@connection.quote(session_id)}
248
+ end_sql
260
249
  end
261
250
  end
262
251
 
@@ -4,9 +4,6 @@
4
4
  ["Framework Trace", @exception.framework_backtrace],
5
5
  ["Full Trace", @exception.clean_backtrace]
6
6
  ]
7
- if defined?(RAILS_ROOT)
8
- traces.each { |name, trace| trace.map! { |p| p.gsub(/^#{RAILS_ROOT}/, '<b>#{RAILS_ROOT}</b>') } }
9
- end
10
7
  names = traces.collect {|name, trace| name}
11
8
  %>
12
9
 
@@ -30,7 +30,7 @@
30
30
 
31
31
  #ErrorExplanation {
32
32
  width: 400px;
33
- border: 2px solid 'red';
33
+ border: 2px solid red;
34
34
  padding: 7px;
35
35
  padding-bottom: 12px;
36
36
  margin-bottom: 20px;
@@ -1,5 +1,5 @@
1
- require 'html/tokenizer'
2
- require 'html/node'
1
+ require File.dirname(__FILE__) + '/tokenizer'
2
+ require File.dirname(__FILE__) + '/node'
3
3
 
4
4
  module HTML #:nodoc:
5
5
 
@@ -0,0 +1,24 @@
1
+ #--
2
+ # Copyright (c) 2004 David Heinemeier Hansson
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'action_pack/version'
@@ -1,8 +1,8 @@
1
1
  module ActionPack
2
2
  module Version #:nodoc:
3
3
  MAJOR = 1
4
- MINOR = 10
5
- TINY = 2
4
+ MINOR = 11
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -122,7 +122,7 @@ module ActionView #:nodoc:
122
122
  attr_accessor :base_path, :assigns, :template_extension
123
123
  attr_accessor :controller
124
124
 
125
- attr_reader :logger, :params, :response, :session, :headers, :flash
125
+ attr_reader :logger, :params, :request, :response, :session, :headers, :flash
126
126
 
127
127
  # Specify trim mode for the ERB compiler. Defaults to '-'.
128
128
  # See ERB documentation for suitable values.
@@ -35,6 +35,9 @@ module ActionView
35
35
  compute_public_path(source, 'javascripts', 'js')
36
36
  end
37
37
 
38
+ JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls']
39
+ @@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup
40
+
38
41
  # Returns a script include tag per source given as argument. Examples:
39
42
  #
40
43
  # javascript_include_tag "xmlhr" # =>
@@ -46,8 +49,9 @@ module ActionView
46
49
  #
47
50
  # javascript_include_tag :defaults # =>
48
51
  # <script type="text/javascript" src="/javascripts/prototype.js"></script>
49
- # <script type="text/javascript" src="/javascripts/scriptaculous.js"></script>
50
- # <script type="text/javascript" src="/javascripts/application.js"></script> *see beloe
52
+ # <script type="text/javascript" src="/javascripts/effects.js"></script>
53
+ # ...
54
+ # <script type="text/javascript" src="/javascripts/application.js"></script> *see below
51
55
  #
52
56
  # If there's an <tt>application.js</tt> file in your <tt>public/javascripts</tt> directory,
53
57
  # <tt>javascript_include_tag :defaults</tt> will automatically include it. This file
@@ -56,7 +60,7 @@ module ActionView
56
60
  def javascript_include_tag(*sources)
57
61
  options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
58
62
  if sources.first == :defaults
59
- sources = ['prototype', 'scriptaculous']
63
+ sources = @@javascript_default_sources
60
64
  if defined?(RAILS_ROOT) and File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
61
65
  sources << 'application'
62
66
  end
@@ -66,6 +70,20 @@ module ActionView
66
70
  content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
67
71
  }.join("\n")
68
72
  end
73
+
74
+ # Register one or more additional JavaScript files to be included when
75
+ #
76
+ # javascript_include_tag :defaults
77
+ #
78
+ # is called. This method is intended to be called only from plugin initialization
79
+ # to register extra .js files the plugin installed in <tt>public/javascripts</tt>.
80
+ def self.register_javascript_include_default(*sources)
81
+ @@javascript_default_sources.concat(sources)
82
+ end
83
+
84
+ def self.reset_javascript_include_default #:nodoc:
85
+ @@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup
86
+ end
69
87
 
70
88
  # Returns path to a stylesheet asset. Example:
71
89
  #
@@ -146,7 +146,7 @@ module ActionView
146
146
  # Returns a string of option tags, like options_from_collection_for_select, but surrounds them with <optgroup> tags.
147
147
  #
148
148
  # An array of group objects are passed. Each group should return an array of options when calling group_method
149
- # Each group should should return its name when calling group_label_method.
149
+ # Each group should return its name when calling group_label_method.
150
150
  #
151
151
  # html_option_groups_from_collection(@continents, "countries", "continent_name", "country_id", "country_name", @selected_country.id)
152
152
  #
@@ -377,6 +377,7 @@ module ActionView
377
377
  # http://script.aculo.us for more documentation.
378
378
  def visual_effect(name, element_id = false, js_options = {})
379
379
  element = element_id ? "'#{element_id}'" : "element"
380
+ js_options[:queue] = "'#{js_options[:queue]}'" if js_options[:queue]
380
381
  "new Effect.#{name.to_s.camelize}(#{element},#{options_for_javascript(js_options)});"
381
382
  end
382
383
 
@@ -184,7 +184,10 @@ Autocompleter.Base.prototype = {
184
184
  this.show();
185
185
  this.active = true;
186
186
  }
187
- } else this.hide();
187
+ } else {
188
+ this.active = false;
189
+ this.hide();
190
+ }
188
191
  },
189
192
 
190
193
  markPrevious: function() {
@@ -425,6 +428,15 @@ Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
425
428
  //
426
429
  // see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
427
430
 
431
+ // Use this if you notice weird scrolling problems on some browsers,
432
+ // the DOM might be a bit confused when this gets called so do this
433
+ // waits 1 ms (with setTimeout) until it does the activation
434
+ Field.scrollFreeActivate = function(field) {
435
+ setTimeout(function() {
436
+ Field.activate(field);
437
+ }, 1);
438
+ }
439
+
428
440
  Ajax.InPlaceEditor = Class.create();
429
441
  Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
430
442
  Ajax.InPlaceEditor.prototype = {
@@ -490,7 +502,7 @@ Ajax.InPlaceEditor.prototype = {
490
502
  Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
491
503
  }
492
504
  },
493
- enterEditMode: function() {
505
+ enterEditMode: function(evt) {
494
506
  if (this.saving) return;
495
507
  if (this.editing) return;
496
508
  this.editing = true;
@@ -501,11 +513,12 @@ Ajax.InPlaceEditor.prototype = {
501
513
  Element.hide(this.element);
502
514
  this.createForm();
503
515
  this.element.parentNode.insertBefore(this.form, this.element);
504
- Field.focus(this.editField);
516
+ Field.scrollFreeActivate(this.editField);
505
517
  // stop the event to avoid a page refresh in Safari
506
- if (arguments.length > 1) {
507
- Event.stop(arguments[0]);
518
+ if (evt) {
519
+ Event.stop(evt);
508
520
  }
521
+ return false;
509
522
  },
510
523
  createForm: function() {
511
524
  this.form = document.createElement("form");