Compare commits

..

328 Commits

Author SHA1 Message Date
Loren Segal
9891ca89c6 Add .yardopts so YARD can document Rails 2010-08-30 07:00:04 +09:00
Xavier Noria
e38fa05781 implements String#strip_heredoc 2010-08-29 23:51:19 +02:00
Xavier Noria
c7106e827e revises a deprecation message 2010-08-29 22:48:53 +02:00
Santiago Pastorino
3d0c92868c -v=1.0.0 not needed 2010-08-29 16:53:44 -03:00
Santiago Pastorino
a8a9f00058 Make CI install bundler stable since 1.0 is out 2010-08-29 16:19:16 -03:00
Santiago Pastorino
ca73b5ba65 No more beta or rc on guides 2010-08-29 15:22:29 -03:00
David Heinemeier Hansson
9f9c50f917 No more build 2010-08-29 13:03:41 -05:00
David Heinemeier Hansson
b63b6c4033 Depend on ARel 1.0 w/ tiny fixes 2010-08-29 12:56:49 -05:00
David Heinemeier Hansson
647ed22aad Depend on Bundler 1.0 w/ tiny fixes 2010-08-29 12:55:21 -05:00
David Heinemeier Hansson
851552bd80 Prep for final release 2010-08-29 12:53:51 -05:00
Sam Ruby
829df8007d Make rake routes gracefully handle routes with no name
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-29 14:39:22 -03:00
José Valim
a2c547f592 Ensure we are not calling length on nil. 2010-08-28 22:53:48 -03:00
Santiago Pastorino
15e9b53a57 PERF: Avoid two method calls 2010-08-28 21:35:43 -03:00
Mike Perham
90d4a19285 Support pluggable cache stores.
[#5486 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-08-28 15:51:39 -07:00
Jeremy Kemper
0f94ca31b1 Clean up CHANGELOGs 2010-08-28 15:50:43 -07:00
Jesse Storimer
ef01f8840b Ensure that inherited helper_methods are available after calling clear_helpers [#5348 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-28 18:09:02 -03:00
Fred Wu
3edd3d052e Fixed the session name generated by the app_generator. Also refactored the corresponding test suites to be cleaner. [#5434 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-28 18:08:50 -03:00
yury
331234e0ab Micro optimization for build_named_route_call in PolymorphicRoutes:
1. use map instead of inject
2. use [].join("_") instead of '<<'. It is a little bit faster for ruby 1.9.2 and x2 faster for ruby 1.8.7. http://gist.github.com/548143

[#5450 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-28 18:08:47 -03:00
Thiago Pradi
cc5a9c642b Fixing typo [#5485 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-28 18:08:46 -03:00
Santiago Pastorino
bf35d1e7c0 type="password" for password_fields 2010-08-28 04:54:13 -03:00
Andrew White
7f83aefd38 Read the route name directly from the route instead of looking it up in the named routes hash
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-08-27 17:05:30 -07:00
Joost Baaij
0c87873455 Use common terminology 2010-08-28 00:03:31 +02:00
Joost Baaij
8da45763b2 escape constants that should not be linked to 2010-08-28 00:03:16 +02:00
Joost Baaij
5502a78c3e mention the alert and notice accessors on the flash 2010-08-28 00:03:01 +02:00
Joost Baaij
6c84fd80b7 expand cookie examples with signed and permanent methods 2010-08-28 00:02:33 +02:00
Xavier Noria
c144f50347 solves everything in guides raised by WARNINGS=1 (except for one which is abandoned atm) 2010-08-27 23:20:57 +02:00
Xavier Noria
e2d73f01a9 adds a comment in cli.rb so that it is clear that exec_script_rails! performs an exec call 2010-08-27 23:20:56 +02:00
Sam Aarons
ba03dd4774 Fix em_mysql2 error in rake db:create
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-27 14:57:45 -03:00
José Valim
dbbf198f5c Add missing require. 2010-08-27 14:57:40 -03:00
Santiago Pastorino
3ba8e31005 Make InstanceTagMethods#value_before_type_cast raise if the model don't respond to attr_before_type_cast or attr method
[#3374] [#5471 state:committed]
2010-08-27 09:09:02 -03:00
Jeremy Kemper
e8a083ecc2 Ruby 1.9: be sure to explicitly reference toplevel constants within BasicObject deprecation proxies 2010-08-26 23:17:12 -07:00
Carlos Antonio da Silva
39f2f18679 Removing some unuseful begin/end and refactor prompt_option_tag a bit
[#5469 state:committed]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-27 01:19:39 -03:00
Xavier Noria
983a5e2970 updates de title of the generators guide in the home and index 2010-08-27 00:17:36 +02:00
Xavier Noria
2af7f29203 getting started guide: adds a reference to Michael Hartl's free online book in the what's next section 2010-08-26 23:47:30 +02:00
José Valim
a2d3e6e29f Be sure to call helper :all just on direct children. (Tests by Jesse Storimer) 2010-08-26 18:18:43 -03:00
José Valim
473feeb32d Doh, be sure to store the string modification. 2010-08-26 16:48:04 -03:00
José Valim
d806aa2b68 Do not modify frozen strings in place. 2010-08-26 16:26:17 -03:00
José Valim
daf2f95830 Update CHANGELOG. 2010-08-26 16:03:34 -03:00
José Valim
52e962086d Add clear_helpers as a way to clean up all helpers added to this controller, maintaing just the helper with the same name as the controller. 2010-08-26 16:03:10 -03:00
José Valim
b78011314e Ensure templates like template.html are found but still uses the proper virtual path. 2010-08-26 15:32:41 -03:00
Xavier Noria
9df512be94 getting started guide: revises text wrt bundler 2010-08-26 15:59:23 +02:00
Xavier Noria
ace0f87056 revises a few link texts 2010-08-26 15:59:15 +02:00
Jaime Iniesta
1c2a2f711d change 'a SQL' to 'an SQL' as suggested by the api documentation guidelines 2010-08-26 14:23:29 +02:00
Jaime Iniesta
a3161096c2 lifecycle should be two words, life cycle 2010-08-26 14:23:10 +02:00
Jaime Iniesta
217fb3e9b5 Fix capture_helper.rb api documentation, unescaped script tag was breaking it on the content_for explanation 2010-08-26 14:22:55 +02:00
Xavier Noria
dcdb8bae38 Revert "to_json => as_json"
This reverts commit 7a6d8e4ad4.

Reason: The method that gives you a Ruby string with JSON source code is #to_json
2010-08-26 02:00:04 +02:00
Xavier Noria
27512c2161 adds missing require for #parameterize 2010-08-26 01:56:27 +02:00
Aleksander Pohl
60685475dc - Fix non-ascii characters in headers
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-08-26 01:46:00 +02:00
James Miller
3ecbae0672 to_json => as_json 2010-08-26 01:44:12 +02:00
James Miller
59cd141c81 mysql2 is now the default, typos 2010-08-26 01:43:43 +02:00
James Miller
d7f1226412 Fix typo, favour => favor 2010-08-26 01:43:17 +02:00
Joost Baaij
6a035099b2 Restored top-level documentation for ActionController::Base.
This information was lost in commit bd6b61be88.
This might have been intentional, but this class does represent the starting
point for all things related to actions, and as such should document it.

I couldn't find any trace of this documentation, which seems like a waste.
Updated parts here and there to conform to current best practices.
2010-08-26 01:43:01 +02:00
Joost Baaij
3b3cfa44f6 fixed capitalization 2010-08-26 01:42:48 +02:00
Joost Baaij
908544c90e change rdoc to conform to api guidelines 2010-08-26 01:42:26 +02:00
Joost Baaij
2722c82f6e remove unwanted linebreak 2010-08-26 01:42:12 +02:00
Rémy Coutable
d810854d42 Restore consistency with the rest of the doc. 2010-08-26 01:41:51 +02:00
Rémy Coutable
e12ff5b3bd Fixed a missing simple quote. 2010-08-26 01:41:24 +02:00
Neeraj Singh
61292a1f87 minor formatting fixes 2010-08-26 01:40:15 +02:00
Xavier Noria
8bad8ac758 AS guide: Array.wrap vs splat is only valid for 1.8 2010-08-25 20:30:28 +02:00
Andrew White
241dfa3c90 Catch mysql2 access denied errors in rake db:create [#5432 state:resolved]
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-08-25 18:07:42 +02:00
Aaron Patterson
9ba46cf15a use blank? instead of present?, mark SQL literals as SQL literals 2010-08-25 05:17:32 -07:00
Aaron Patterson
3dc9880866 no need to send on a public method 2010-08-25 05:17:31 -07:00
Aaron Patterson
da7a28027a refactor select { is_a? } to grep() 2010-08-25 05:17:31 -07:00
Aaron Patterson
bfe956d785 run tests in verbose mode 2010-08-25 05:17:31 -07:00
Aaron Patterson
e991f39709 mark SQL literals as SQL literals 2010-08-25 05:17:31 -07:00
Jakub Suder
aec084955d better callstack reporting in deprecation messages
now the reported line is the first line in the stack
that's outside Rails, which is the one that actually
caused the problem in the first place

[#5231 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-25 07:25:19 -03:00
Andrew White
55c1f351c4 Remove rails info route from rake routes output [#5452 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-25 07:25:18 -03:00
Mikel Lindsaar
d887dbc2d6 Make ActiveResource::InvalidRequestError more user friendly
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-08-25 10:06:27 +02:00
Andrew White
37467bf0fc Use nested scope for routes defined at the :resources scope level (as in Rails 2.3)
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-24 21:14:32 -03:00
Xavier Noria
30dcac2926 :nodoc:s #unscoped until its behavior is more clear, now sometimes works, sometimes not 2010-08-25 01:10:54 +02:00
Xavier Noria
5deeb43fca edit pass to a recent doc patch 2010-08-25 01:10:54 +02:00
Neeraj Singh
78f6f0dc4b touch operationg if used along with belongs_to will also be invoked on associated objects 2010-08-25 01:10:54 +02:00
Trevor Turk
174d5cd7ee Note about how to exit the console in the Getting Started guide 2010-08-25 01:10:53 +02:00
Neeraj Singh
2ae4f01650 unscoped does not work when chained with named_scope 2010-08-25 01:10:53 +02:00
José Valim
3a831cb7d6 Allow format to be skipped. This is used internally by mount. 2010-08-24 16:56:51 -03:00
José Valim
0d7b8f8c83 Finally fix the bug where symbols and strings were not having the same behavior in the router.
If you were using symbols before for methods like match/get/post/put/delete, it is likely that this commit will break your routes.
Everything should behave the same if you are using strings, if not, please open up a ticket.
2010-08-24 16:44:47 -03:00
José Valim
91916e6c3c Ensure shortcuts inside resources also generates helpers. 2010-08-24 14:54:23 -03:00
José Valim
6b54a6a8ff Hide internal apps from rake routes [#5443 state:resolved] 2010-08-24 13:22:34 -03:00
José Valim
6d1e87b16b Fix how routes inside namespaces are generated. 2010-08-24 13:05:56 -03:00
Santiago Pastorino
7830f8d9f8 Allow actions which start with A-Za-z_ only 2010-08-24 12:44:14 -03:00
Aaron Suggs
d8196bf994 Bump rake dependency to 0.8.4. [#5279 state:resolved]
This rake version adds the Rake::RDocTask#rdoc_task_name method, used in
railties/lib/rails/tasks/documentation.rake

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-24 11:58:00 -03:00
Neeraj Singh
aa384de7dd @user.touch should not fail if User does not have updated_at/updated_on column.
[#5439 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-24 11:27:00 -03:00
Andrew White
78486cb9c5 Reset symbolized path parameters when a test request is recycled [#5437 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-24 11:26:53 -03:00
José Valim
6579173814 Ensure prefix in routes are generated properly. 2010-08-24 11:26:37 -03:00
Joost Baaij
a32f46d0ce fix broken relative links [#5415 state:committed]
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-08-24 16:15:43 +02:00
José Valim
c857bd23c0 Ensure timestamps are not generated when explicitly set to false [#5440 state:resolved] 2010-08-24 10:47:38 -03:00
Wincent Colaiuta
5ccdb362b4 Add test case for ActiveRecord::Base.record_timestamps = false
This is a failing test case for Lighthouse ticket #5440:

  https://rails.lighthouseapp.com/projects/8994/tickets/5440

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-24 10:47:30 -03:00
José Valim
7a7012c717 Fix a bug where symbols and strings were not behaving the same in the router. [#5431 state:resolved] 2010-08-24 10:19:01 -03:00
Andrew White
8feb2856ea When custom resource actions are specified using strings add the default name and action if the string is a valid ruby method name.
[#5431 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-24 10:09:44 -03:00
Krekoten' Marjan
5708412052 Fix test of generated Gemfile with mysql selected as DB driver
[#5435 state:committed]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-24 09:39:13 -03:00
David Heinemeier Hansson
822fa17c6c mysql db defaults to mysql2 gem 2010-08-23 21:40:59 -05:00
David Heinemeier Hansson
04aa14f8d7 Bump rails version 2010-08-23 21:31:08 -05:00
David Heinemeier Hansson
bc61196bf5 Depend on latest arel RC 2010-08-23 21:27:58 -05:00
Santiago Pastorino
aafb29073a Point guides to bundler 1.0.0.rc.6 2010-08-23 23:27:13 -03:00
David Heinemeier Hansson
880eaa145e Depend on latest Bundler RC 2010-08-23 21:22:22 -05:00
David Heinemeier Hansson
fc6db6226f Prefer the mysql2 gem for MySQL database.ymls 2010-08-23 21:19:20 -05:00
David Heinemeier Hansson
8931dd17a9 Prep for RC2 2010-08-23 21:15:48 -05:00
Santiago Pastorino
c8b84a1c8c Config is deprecated on 1.8.8 and 1.9.3 use RbConfig 2010-08-23 23:09:35 -03:00
Aaron Patterson
36fcc99cce marking sql literals as sql literals 2010-08-23 18:49:10 -07:00
José Valim
a1ca2e0a38 Update CHANGELOG for ActionPack. 2010-08-23 21:53:56 -03:00
Aaron Patterson
6a1ea881cf we should mark sql strings as sql literals 2010-08-23 14:27:16 -07:00
Aaron Patterson
1cc653f9b3 sql literal strings should be marked as sql literal strings 2010-08-23 13:57:32 -07:00
Aaron Patterson
eeb9b379f9 we should mark strings as SQL Literal values 2010-08-23 13:30:46 -07:00
Brian Lopez
ce04ea973c mysql2 adapter is being maintained in the mysql2 gem itself
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-23 16:01:16 -03:00
Brian Lopez
ab64dc9c20 no need to depend on mysql2 master anymore
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-23 15:51:01 -03:00
Raimonds Simanovskis
f10fb1c4e9 use database from ARUNIT_DB_NAME environment variable when running tests on Oracle 2010-08-24 01:49:42 +08:00
Xavier Noria
2570fda5ab removes words moved in previous edit of the generator generator USAGE 2010-08-23 09:45:34 +02:00
Xavier Noria
b97ad85d44 generators guide: edit pass 2010-08-23 09:15:10 +02:00
Xavier Noria
d125687b97 adds USAGE to the generator generator USAGE (not sure this meta thing is any good at 8:12 AM with little coffee) 2010-08-23 09:15:10 +02:00
Raimonds Simanovskis
2c81a31039 Do not use time zone in test_read_attributes_before_type_cast_on_datetime for Oracle database
As currently string_to_time method is not doing time zone conversion to database time zone
2010-08-23 07:34:07 +08:00
Raimonds Simanovskis
bedf6a0061 updated test_should_record_timestamp_for_join_table for Oracle 2010-08-23 07:34:07 +08:00
Santiago Pastorino
6edae4553e Bump up rack-mount to 0.6.12 2010-08-22 20:29:14 -03:00
Santiago Pastorino
8235c9288f type fixed 2010-08-23 01:23:24 +02:00
Aaron Patterson
6ca6ef2ab0 removing duplicate tests 2010-08-22 16:06:21 -07:00
Santiago Pastorino
0579963a38 Silence warnings for Encoding.default_external= and Encoding.default_internal= 2010-08-22 18:43:51 -03:00
Santiago Pastorino
7cb44a5092 Fix namespace problem on object which inherit from ActiveSupport::BasicObject 2010-08-22 17:18:02 -03:00
Andrew White
df0a7bfb8f Cache the symbolized path parameters using a instance variable in the request object rather than the environment hash. This it to prevent stale parameters in later routing constraints/redirects as only the normal path parameters are set by Rack::Mount.
Also if a constraint proc arity is more than one, pass the symbolized path parameters
as the first argument to match redirect proc args and provide easier access.

[#5157 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-22 16:18:42 -03:00
Santiago Pastorino
2106782828 Set default_internal and default_external on AS for testing purposes 2010-08-22 02:23:13 -03:00
Santiago Pastorino
e88f8bee5e Set default_internal and default_external on AM for testing purposes 2010-08-21 22:53:42 -03:00
Santiago Pastorino
11e9883f19 Move encoding settings for testing purposes to abstract_unit file 2010-08-21 22:38:15 -03:00
Raphomet
b4e5da6bde Trifling typos
[#5422 state:committed]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-21 19:22:54 -03:00
Brian Lopez
7dbc99ef0d reload bob after his journy to a new timezone 2010-08-20 20:00:21 -07:00
Jeremy Kemper
d0e3323d5b Revert "Just add connection management middleware if running in a concurrent environment."
This reverts commit 6b29dc876f.
2010-08-20 18:55:12 -07:00
Xavier Noria
68e2d1e496 prevent RDoc from autolinking "Rails" in the API home page 2010-08-21 02:29:39 +02:00
Xavier Noria
9011f8f49c requires horo 1.0.2 2010-08-21 02:29:25 +02:00
Nick Sieger
b4a520874a Fix hash modification during iteration in Mapper [#5420]
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-20 18:28:19 -03:00
Andrew White
47f6d8b880 Support routing constraints in functional tests
Extend assert_recognizes and assert_generates to support passing
full urls as the path argument. This allows testing of routing
constraints such as subdomain and host within functional tests.

[#5005 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-20 14:51:50 -03:00
Aaron Patterson
612c233a28 adding FOUND_ROWS to the connect flags for mysql2 2010-08-20 10:15:52 -07:00
Neeraj Singh
8f72ddc12b after_validation should be called irrespective of the result of validation.
I confirmed that this is the behavior on 2.3.x .

[5419 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-20 11:24:58 -03:00
Andrew White
47280f083a Don't add the standard https port when using redirect in routes.rb and ensure that request.scheme returns https when using a reverse proxy.
[#5408 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-20 10:41:43 -03:00
Andrew White
c6391e6676 Allow symbols for :path resource(s) option [#5306 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-20 09:33:33 -03:00
Xavier Noria
20088f6fff deletes the rdoc task of each component, they are no longer published separately 2010-08-20 13:34:28 +02:00
Xavier Noria
d033b237c4 the pdoc task is no longer needed 2010-08-20 13:33:51 +02:00
Aaron Patterson
809a04ba8f fisting after_rollback and after commit callbacks 2010-08-20 00:06:32 -07:00
Santiago Pastorino
ac66de4a82 Bump up tzinfo to 0.3.23 2010-08-20 02:46:10 -03:00
Aaron Patterson
e509d4afc9 updates return number of rows matched rather than number of rows affected 2010-08-19 19:13:35 -07:00
Andrew White
ad063263bc Optimize find_sti_class when store_full_sti_class is true
[#5403]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-08-19 16:03:37 -05:00
José Valim
8f2b2781b0 Use attribute readers as they are faster in general. 2010-08-19 15:15:46 -03:00
Andrew White
6b52a58f72 Move regexps in options hash to :constraints hash so that they are pushed into the scope [#5208 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-19 15:09:46 -03:00
Andrew White
1031fe1478 Move edit route before show route so that it will have precedence if the :id parameter allows slashes [#5409 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-19 15:09:40 -03:00
Neeraj Singh
758f01d49e While creating a new record using has_many create method default scope of child should be respected.
author.posts.create should take into account default_scope
defined on post.

[#3939: state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-19 15:09:34 -03:00
Santiago Pastorino
21c9795c15 Bump up rack-mount to 0.6.10 2010-08-19 14:50:06 -03:00
Aaron Patterson
49e406efb7 removing useless ternary 2010-08-19 10:46:01 -07:00
Aaron Patterson
1ef9b98a31 we should wrap strings as sql literals 2010-08-19 10:35:23 -07:00
Santiago Pastorino
bef90f8449 We need bundle update only here 2010-08-19 14:13:54 -03:00
Jeremy Kemper
64f4dc68f6 Memoize STI class lookups for the duration of a request 2010-08-19 11:28:49 -05:00
Aaron Patterson
a16ec2f4cf refactor if / else to ||= 2010-08-18 23:37:11 -07:00
Xavier Noria
6fb6ddb9a7 avoids warnings about mismatched indentations in Ruby 1.9.2 2010-08-19 03:44:31 +02:00
Xavier Noria
632a224bd1 now for real, the suite loads everything and these went unpatched 2010-08-19 03:00:34 +02:00
Xavier Noria
6580c6df36 avoids a ton o warnings activesupport/lib/active_support/dependencies.rb:239: warning: loading in progress, circular require considered harmful ... activesupport/lib/active_support/core_ext/hash/indifferent_access.rb while running the suite in Ruby 1.9.2 2010-08-19 03:00:19 +02:00
Xavier Noria
ddce48a355 get rid of the warning "+ after local variable is interpreted as binary operator even though it seems like unary operator" in Ruby 1.9.2 2010-08-19 02:29:02 +02:00
wycats
06632578c2 Revert "It's snowing!"
This reverts commit e4283007d6.
2010-08-18 16:49:34 -07:00
Aaron Patterson
2f6383e340 refactoring to remove duplicate logic 2010-08-18 12:10:37 -07:00
Aaron Patterson
7e85b16518 call to present? is not necessary 2010-08-18 11:51:39 -07:00
Javier Martín
12f7f7a714 Don't pluralize resource methods [#4704 state:resolved]
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-18 13:58:21 -03:00
Santiago Pastorino
82eff0ffe9 Bump up rdoc to 2.5.10 2010-08-18 13:55:56 -03:00
wycats
588ac71213 1.8 block variable shadowing strikes again 2010-08-17 16:52:34 -07:00
wycats
0a41ece3e3 Sadly, this segv's in 1.8 :( 2010-08-17 16:52:34 -07:00
Andre Arko
c40856c46c Allow member actions (get, etc) to accept strings, with test 2010-08-18 07:36:49 +08:00
Xavier Noria
23303d6ab7 you rarely want ^ or $ in validations, use \A when you mean \A 2010-08-18 00:35:05 +02:00
Trey Bean
017840beb8 Missing object for comparison in ActiveModel::EachValidator example code. 2010-08-18 00:34:46 +02:00
Matthew Mongeau
92f4cca4a3 to_sentence should return a duplicate 2010-08-17 13:53:22 -07:00
Jeff Lawson
82a58abe05 Bug Fix -- clean up connection after stored procedure [#3151 state:resolved] 2010-08-17 13:14:57 -07:00
Jeff Lawson
90176a6f15 Bug Fix -- clean up connection after stored procedure [#3151 state:resolved] 2010-08-17 13:14:57 -07:00
Xavier Noria
4b21dfe9a7 debugging guide: revises the section on debugging RJS 2010-08-17 13:33:53 +02:00
Luke Brown
c11ba424e7 Added an example and explaination for using an optional path scope for the locale 2010-08-17 13:31:52 +02:00
Josiah Ivey
21063e5e27 Debugging Guide: Improve grammar for the RJS section 2010-08-17 13:31:40 +02:00
Santiago Pastorino
22d242c2ca recommended is the right word here 2010-08-17 13:31:28 +02:00
Santiago Pastorino
6f478b0698 Restore pet -> owner relationship to the previous state
[#5365]
2010-08-16 22:47:49 -03:00
Mark Turner
fc43c62fc6 added testcase for belongs_to with a counter_cache and touch
[#5365 state:committed]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-16 22:47:40 -03:00
Peter Wagenet
b9281e8e2c Class Attribute setter returns set value
Signed-off-by: wycats <wycats@gmail.com>
2010-08-16 18:38:33 -07:00
Xavier Noria
5f5c508444 code gardening: we have assert_(nil|blank|present), more concise, with better default failure messages - let's use them 2010-08-17 03:31:39 +02:00
Santiago Pastorino
020aeb6192 assert_equal here 2010-08-16 22:01:04 -03:00
Tobias Lütke
141634ddc6 Added test case to verify that transaction callbacks are correctly propagated to class observers
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-16 22:00:52 -03:00
Xavier Noria
14be1789b7 the (public) routing DSL does not accept symbols for get|post|put|delete|match 2010-08-17 02:50:31 +02:00
Raimonds Simanovskis
1d2e075bf1 Replaced hardcoded SessionStore table creation SQL with calls to ActiveRecord adapter migration methods
Otherwise hardcoded table creation SQL was failing on Oracle database
2010-08-17 06:18:39 +08:00
Raimonds Simanovskis
d1480926e8 added dependencies in Gemfile for running ActiveRecord tests with Oracle database 2010-08-17 06:18:38 +08:00
José Valim
047e411fd2 annoted_source_code may return nil if an erro rhappens during template compiling. 2010-08-16 14:12:07 -03:00
wycats
452a56ad51 Make sure apps upgrading from 2.3 get defaulted to UTF-8 (ht: parndt) 2010-08-15 16:31:40 -07:00
wycats
83cb532009 Test callbacks 2010-08-15 16:31:40 -07:00
Xavier Noria
c330e96a6e routing guide: wildcard segments are quite flexible, go beyond the simple use case 2010-08-16 01:12:10 +02:00
wycats
a34dce9717 Add back #callback and deprecate it 2010-08-15 15:36:18 -07:00
wycats
b8ec4eaac5 find .text.html and .text.plain files, and deprecate it 2010-08-15 15:27:57 -07:00
wycats
688368100a headers["X-Foo-Count"] = 2 is deprecated properly now 2010-08-15 15:18:22 -07:00
wycats
19fb031d84 render :file in 2.3 behaved like render :template in Rails 3 (adding the current controller as a prefix) 2010-08-15 15:07:05 -07:00
Subba Rao Pasupuleti
dbe5ae488e select tags coerce the :selected option, options to strings before comparison [#5056 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-15 16:54:31 -03:00
Bryce Thornton
1091a6e9b7 Allow for any possible TLD when using the :all option with the cookie session store. This works for subdomain.mysite.local, google.co.uk, google.com.au, etc. [#5147 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-15 16:54:31 -03:00
José Valim
8520045200 Improve routes task code and print the application as :to => RackApp. [#5338 state:resolved] 2010-08-15 16:54:31 -03:00
Mark Turner
ebf7447b34 make rake routes print the name of a Rack endpoint app [#5338 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-15 16:54:31 -03:00
Santiago Pastorino
10177d3a38 Revert "Makes AR use AMo to_key implementation"
This reverts commit ccd4364a13.
2010-08-15 11:37:50 -03:00
José Valim
f224c66a91 to_key should return all exists keys (if any exists), regardless if the object is persisted or not. If you need it to reflect persistance, you should use to_param. 2010-08-15 11:30:06 -03:00
Mikel Lindsaar
88fc37ff03 Making time_zone_options_for_select return a html_safe string
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-15 09:59:24 -03:00
Santiago Pastorino
bdeeca358b This is not needed anymore 2010-08-15 09:18:46 -03:00
Santiago Pastorino
5f7bfb1c3a Makes use of class << self instead of def self. 2010-08-15 08:42:05 -03:00
Santiago Pastorino
ae7732f957 remove already defined method to avoid warnings 2010-08-15 08:03:26 -03:00
Santiago Pastorino
df8a941a43 Revert "connection reader is defined later"
This reverts commit f4cce71d96.
2010-08-15 08:03:17 -03:00
Santiago Pastorino
6d68cde2c5 connection reader is defined later 2010-08-15 07:21:10 -03:00
Santiago Pastorino
0f1b9bbbf8 Makes topics.written_on null => true back again some tests rely on that 2010-08-15 07:20:58 -03:00
Santiago Pastorino
477a9d4d86 MySQL2 added to CI 2010-08-14 21:56:29 -03:00
Santiago Pastorino
a036999ed1 Should be Boolean there 2010-08-14 19:49:33 -03:00
Santiago Pastorino
707248a629 Add missing model 2010-08-14 18:50:15 -03:00
Santiago Pastorino
ecf59b4776 Both tests are using the same model, move the model to another file and add the missing require 2010-08-14 18:50:07 -03:00
Santiago Pastorino
677564f8f7 object/try should be required after abstract_unit to have AS in the load path 2010-08-14 18:34:15 -03:00
Mark Hayes
f6f7ae4020 in Rendering objects with RecordIdentifier example, locals should reference @account not @buyer 2010-08-14 13:26:03 +02:00
Santiago Pastorino
b3ece73114 deprected -> deprecated 2010-08-14 13:26:03 +02:00
Subba Rao Pasupuleti
76c91a237c Adding missing required statement
[#5056 state:resolved]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-14 06:28:54 -03:00
Santiago Pastorino
05ba082c6a Fixes some ActionMailer tests 2010-08-14 05:59:05 -03:00
Santiago Pastorino
3270c58ebb Deletes trailing whitespaces (over text files only find * -type f -exec sed 's/[ \t]*$//' -i {} \;) 2010-08-14 04:20:06 -03:00
Santiago Pastorino
ccd4364a13 Makes AR use AMo to_key implementation
[#5249]
2010-08-13 22:28:26 -03:00
Santiago Pastorino
6373dd466f This method is actually not used, it's implemented on the concrete adapters
[#5331 state:committed]
2010-08-13 21:20:50 -03:00
Aaron Patterson
59e63e76c3 converting to a symbol is not necessary 2010-08-13 16:50:22 -07:00
Prem Sichanugrist
433d7a26fe Removing most of the symbol to proc usage in Active Record
This will hopefully make Active Record run a bit more faster.
2010-08-13 16:22:54 -07:00
Aaron Patterson
79e15f0340 removing a lolinject 2010-08-13 14:45:06 -07:00
Santiago Pastorino
3698da65e5 Moves local_request? to require.local?
[#5361 state:committed]
2010-08-13 18:17:26 -03:00
Aaron Patterson
108179b068 avoid direct use of arel constants 2010-08-13 13:32:48 -07:00
Aaron Patterson
bacf78150c removing references to arel constants 2010-08-13 12:35:58 -07:00
Aaron Patterson
e86b758592 avoiding symbol to proc again 2010-08-13 12:35:58 -07:00
Aaron Patterson
abd973689d do not use arel constants directly 2010-08-13 12:35:58 -07:00
Aaron Patterson
fb6edb1769 symbol to proc is slow, we should avoid it 2010-08-13 12:35:58 -07:00
Jeremy Kemper
e4283007d6 It's snowing! 2010-08-12 13:32:39 -07:00
Xavier Noria
91ae6e9933 be more precise re :validate and :autosave 2010-08-12 19:32:26 +02:00
Subba Rao Pasupuleti
fe2d65864e no callbacks should be created for empty array [#5289 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-12 13:13:41 -03:00
Subba Rao Pasupuleti
9df227983f tidy up validations length code [#5297 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-12 13:13:37 -03:00
Greg Campbell
d03a1249a0 Add missing ActiveModel::Validations require
[#5311 state: resolved]

ActiveModel::Validations uses Hash#except, but does not require it from
ActiveSupport.  (This wasn't showing up in the tests, because it was
required in the helper, and was also required in
ActiveModel::Serialization).

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-12 13:13:33 -03:00
Neeraj Singh
9528aa9f86 Ensure we can nest include calls [#5285 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-12 13:13:26 -03:00
Xavier Noria
4dcce5d06e revises some autosave docs, style and content 2010-08-12 17:40:32 +02:00
Paco Guzman
ab68d4b52e applied guidelines to "# =>" 2010-08-12 17:40:20 +02:00
Xavier Noria
1e6e868d8c commit review: applies guidelines to "# =>" 2010-08-12 17:40:10 +02:00
Neeraj Singh
198bffe3be updating documentation for named_scope and default_scope 2010-08-12 17:39:52 +02:00
Neeraj Singh
06af291346 adding more documentation for autosave option 2010-08-12 17:39:05 +02:00
José Valim
30ea923040 Make update_attribute behave as in Rails 2.3 and document the behavior intrinsic to its implementation. 2010-08-12 12:06:57 -03:00
Mark Turner
7325dd21b3 fixed indentation in test cases
Signed-off-by: wycats <wycats@gmail.com>
2010-08-11 23:56:11 -07:00
wycats
f2d22ecbb3 Replace snowman with utf8=✓ 2010-08-11 18:37:06 -07:00
Paul Hieromnimon
1c970b8394 Raising exception if fixture file can't be found 2010-08-11 15:45:29 -07:00
Aaron Patterson
c8509d5303 subtracting blank strings is slightly faster than blank? 2010-08-11 15:44:54 -07:00
Xavier Noria
36cb62eb9d AS guide: some revisions 2010-08-12 00:15:43 +02:00
Xavier Noria
bfd728182c no need to assign if we are gonna return 2010-08-12 00:15:43 +02:00
Aaron Patterson
ff760dd6ce avoid multiple hash lookups 2010-08-11 14:59:47 -07:00
Aaron Patterson
5352a89d50 dry up the hash dup and avoid sending nil values 2010-08-11 14:45:07 -07:00
Aaron Patterson
a56ee4c9a2 avoiding tap saves us time 2010-08-11 11:43:27 -07:00
Aaron Patterson
dac2b37b03 unless Array#empty? is faster than if Array#present? 2010-08-11 11:28:13 -07:00
Aaron Patterson
8464ee0650 stop using private methods 2010-08-11 11:24:59 -07:00
José Valim
e1b85c3bda Ensure @config is not a reserved instance variable in controllers. [#5342 state:resolved] 2010-08-11 10:27:11 -03:00
José Valim & Carlos Antonio da Silva
1fbcd5f5fc layout_for works again with objects as specified in the documentation and Rails 2.3 [#5357 state:resolved] 2010-08-11 10:27:11 -03:00
Nick Sieger
43b8722f4b Missed one spot for --skip-active-record, which means that new Gemfile isn't set up right
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-11 00:43:49 -03:00
Gonçalo Silva
d9b77ddecd added support for more printers 2010-08-10 10:24:00 -07:00
José Valim
6f88b82263 Revert "require_dependency should require using the normal mechanism if possible to avoid double-requires"
This was causing double requires since 991cd59a22 was reverted.
This reverts commit 8bf79739b4.
2010-08-10 11:20:04 -03:00
Xavier Noria
b2eaac24c3 fixes a typo reported by rymai 2010-08-10 15:35:23 +02:00
Xavier Noria
5859f5eee1 AS guide: removes some duplication, and makes a second pass on method delegation 2010-08-10 11:53:27 +02:00
Xavier Noria
63ffec85b7 adds the AS guide to the guides index 2010-08-10 04:09:52 +02:00
Xavier Noria
ca3fc4b325 AS guide: documents Module#redefine_method 2010-08-10 03:59:48 +02:00
Xavier Noria
aaa52c6d1f AS guide: documents Module#(instance_)method_names 2010-08-10 03:46:21 +02:00
Xavier Noria
68bed3a4ad AS guide: documents Module#delegate 2010-08-10 03:29:26 +02:00
Xavier Noria
8968eecb93 AS guide: documents Process.daemon 2010-08-10 01:53:53 +02:00
Xavier Noria
3c404c56eb AS guide: documents date/datetime/time arithmetic with durations 2010-08-10 01:31:23 +02:00
Jeremy Kemper
cbf89a378c Merge remote branch 'brianmario/3-0-stable' into 3-0-stable 2010-08-09 16:12:33 -07:00
Brian Lopez
2d681838c0 move mysql2 adapter into core 2010-08-09 15:30:06 -07:00
Brian Lopez
b02751c961 ignore this test for mysql2 2010-08-09 15:29:59 -07:00
Brian Lopez
3ccf3504d2 skip the before_type_cast_on_datetime test entirely for mysql2 2010-08-09 15:29:53 -07:00
Brian Lopez
98384b1ce8 typo 2010-08-09 15:29:33 -07:00
Brian Lopez
a263a8ffd5 update tests for mysql2 support 2010-08-09 15:29:26 -07:00
wycats
dd7e872e85 Properly deprecate register_javascript_include_default and reset_javascript_include_default 2010-08-09 12:42:09 -07:00
wycats
f85b206e7a rename _snowman to _e 2010-08-09 12:06:51 -07:00
wycats
22cbc3f0fa Improve best_standards_support to use only IE=Edge in development mode 2010-08-09 11:48:53 -07:00
Xavier Noria
efb2bd0409 adds missing requires for Object#try 2010-08-09 15:14:00 +02:00
Xavier Noria
195e891954 form helpers guide: fixes an example 2010-08-09 14:11:37 +02:00
Xavier Noria
28d82bd2e9 adds URL to the body generated by the redirect macro in the routes mapper as per the RFC, extracts common test pattern into a test macro, adds a test to cover the :status option 2010-08-09 13:32:45 +02:00
Xavier Noria
4d4b865b11 AC guide: commit review, block examples go at column 0, use .example.com as example domain 2010-08-09 12:25:22 +02:00
Adam Meehan
5c109e243f typo in AM 2010-08-09 12:25:11 +02:00
Daniel McNevin
f7996be0c7 updated the action_controller guide with the new session configuration options 2010-08-09 12:24:56 +02:00
Neeraj Singh
d55491c844 correcting wrong example 2010-08-08 18:34:58 +02:00
Xavier Noria
4b18d3c210 routing guide: documents the CONTROLLER environment variable understood by the routes task 2010-08-08 18:30:09 +02:00
Xavier Noria
783dc5207b updates horo dependency to 1.0.1 2010-08-08 11:29:21 +02:00
Xavier Noria
78c7705b32 undoes one of the modifications to RDoc::Parser.binary? 2010-08-07 20:10:56 +02:00
Xavier Noria
5aec933385 quick hack: hijacks the predicate RDoc::Parser.binary? so that it does not consider a handful of ordinary Ruby files in the Rails tree as binary (and thus excluded from the API) 2010-08-07 15:19:22 +02:00
Xavier Noria
413c9c8235 adds Abstract Controller to the API 2010-08-07 01:45:48 +02:00
Aaron Patterson
91930dc30b reduce the number of times current_connection_id is called in with_connection() 2010-08-06 16:38:53 -07:00
Aaron Patterson
001a574785 test to ensure that respond_to? delegates to arel 2010-08-06 15:23:11 -07:00
Aaron Patterson
a897a1f4a3 sorry AR, my privates are none of your business 2010-08-06 14:52:33 -07:00
Aaron Patterson
8fb0c9f509 do not rely on arel class structure 2010-08-06 11:31:32 -07:00
Xavier Noria
0bb8d0561a AS guide: documents calculations with Time objects 2010-08-06 17:31:48 +02:00
Xavier Noria
bed98b9bf2 AR guide: fixes a query 2010-08-06 13:37:44 +02:00
Neeraj Singh
148dd2eac6 fixing typo 2010-08-05 22:58:36 +02:00
Neeraj Singh
06e4c48815 more documentation for class_inheritable_* 2010-08-05 22:58:20 +02:00
Aaron Patterson
0a86cb5972 fixing whitespace errors 2010-08-05 08:15:07 -07:00
Xavier Noria
e34fb808db AS guide: documents DateTime#advance 2010-08-05 15:57:59 +02:00
Tom Stuart
2005f8234a Fix ActiveSupport::Callbacks' define_callbacks and ActiveSupport::Concern documentation to look like native English 2010-08-05 15:57:44 +02:00
Aaron Patterson
05a49c7718 avoid passing lists of lists to the group clause 2010-08-04 16:24:29 -07:00
Xavier Noria
902d732617 Merge remote branch 'docrails/master' into 3-0-stable 2010-08-05 01:15:08 +02:00
Łukasz Strzałkowski
84d5461d43 Fixed broken test suite - there was problem with namespacing in DeprecatedConstant class 2010-08-05 05:28:39 +08:00
Łukasz Strzałkowski
18bcc548bf Typo in class name 2010-08-05 05:28:39 +08:00
Aaron Patterson
ba9602b9e7 call to_a since we are not passing anything to all() 2010-08-04 14:22:20 -07:00
Aaron Patterson
906ef233e4 fisting indentation 2010-08-04 14:11:20 -07:00
Piotr Sarnacki
4da32babdf Reload action_methods in AbstractController after defining new method.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-04 14:45:55 -03:00
José Valim
87365272e9 Revert "If a file is in the load path, require it without its full path (in more places)"
Caused failures in ActionMailer test suite.

This reverts commit 963638aac8.
2010-08-04 14:45:55 -03:00
Aaron Patterson
f316a851dd do not pass AR objects to ARel 2010-08-04 08:44:35 -07:00
José Valim
19c77a0d2b Revert "Put lib back on the autoload path"
This was causing engines/gems to eager load everything in lib. Another fix is comming soon.

This reverts commit 02a5842cd0.
2010-08-04 14:16:18 +02:00
wycats
2498cdaf14 I'm unsure how cloning was working in Rails 3 before 2010-08-04 04:05:28 -07:00
wycats
963638aac8 If a file is in the load path, require it without its full path (in more places) 2010-08-04 03:21:37 -07:00
wycats
fbc40a4d94 Fix a subtle bug involving RAILS_ROOT 2010-08-04 03:20:56 -07:00
wycats
32d840d98a Concernify SanitizeHelper and TextHelper so including TextHelper correctly include SanitizeHelper and extends its ClassMethods 2010-08-04 03:20:44 -07:00
wycats
bd1cf94a29 Add a fake UrlRewriter, since instantiating it in tests happens, but is basically crazysauce 2010-08-04 03:20:08 -07:00
wycats
d599e94e45 require_dependency should require using the normal mechanism if possible to avoid double-requires 2010-08-04 02:16:48 -07:00
wycats
91e4249c02 Provide a bit more information in the deprecation for config.gem 2010-08-04 02:15:15 -07:00
wycats
07c5e5416b Shim Initializer.run 2010-08-04 01:07:23 -07:00
rohit
8158afa47e Give extracted options back to args in AMo callbacks. Fixes two failing tests in AR.
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-04 00:33:23 -03:00
Aaron Patterson
9269e55b1f avoid passing AR::Base objects to Arel when we can 2010-08-03 17:57:59 -07:00
wycats
b46b5a6d54 Fix up constant deprecation to be less dependent on load order 2010-08-03 16:03:35 -07:00
wycats
46a1da7c79 Put lib back on the autoload path 2010-08-03 15:00:17 -07:00
RainerBlessing
8b7219b9d6 query value is converted to_s instead of to_yaml 2010-08-03 14:55:15 -07:00
wycats
109dc3c39c Deprecate the @controller instance variable 2010-08-03 14:23:46 -07:00
wycats
af8e085190 Move the deprecations before the load hooks 2010-08-03 12:50:41 -07:00
wycats
146a013c42 Fix a couple of mistaken deprecation solutions 2010-08-03 12:50:13 -07:00
wycats
84703be5ff Deprecate ActionController::UrlWriter properly 2010-08-03 12:41:18 -07:00
wycats
43cc69cb65 Fix the session= deprecation to include the secret key 2010-08-03 12:31:39 -07:00
wycats
01186652cc Even though exempt_from_layout is no longer needed, some people are still using it. Deprecate it instead of removing. 2010-08-03 12:29:03 -07:00
wycats
7a1bba4799 Allow :name to be a Symbol (was this removed by accident?) 2010-08-03 12:22:10 -07:00
wycats
4474470ffd update this for a change in the core method 2010-08-03 11:49:44 -07:00
wycats
9ae7f04cd6 properly deprecate #{type}_validation_on_#{on} 2010-08-03 11:48:06 -07:00
wycats
1318bf6e33 Properly deprecate validate_on_#{on} 2010-08-03 11:48:06 -07:00
Subba Rao Pasupuleti
5987fd4c79 Tidy up error.rb code
[#5288 state:committed]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-08-03 14:58:53 -03:00
Santiago Pastorino
677e1e58b6 Stub is_a? not instance_of? here 2010-08-03 12:20:11 -03:00
José Valim
3b170b2e14 Freeze options so we raise an error when people modify it in place. 2010-08-03 15:37:35 +02:00
José Valim
79583ca9b1 validates_length_of should not change the options hash in place. [#5283 state:resolved] 2010-08-03 15:37:26 +02:00
rohit
257e9c4ec4 Failing test for validates_length_of, when both too_short and too_long messages are set [#5283 state:open]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-03 15:37:17 +02:00
Samuel Lebeau
a44779e9bb Avoid potentially expensive inspect call in router. [#4491 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-03 12:03:45 +02:00
José Valim
503931df05 Merge branch 'master' into 3-0-stable 2010-08-03 10:55:09 +02:00
wycats
f73e9d2df8 Properly deprecate config.load_paths and config.gem 2010-08-02 23:39:33 -07:00
1433 changed files with 60076 additions and 69457 deletions

8
.gitignore vendored
View File

@@ -1,27 +1,21 @@
*.gem
pkg
.bundle
Gemfile.lock
.Gemfile
debug.log
doc/rdoc
activemodel/doc
activeresource/doc
activerecord/doc
activerecord/sqlnet.log
actionpack/doc
actionmailer/doc
activesupport/doc
activesupport/test/tmp
activemodel/test/fixtures/fixture_database.sqlite3
actionpack/test/tmp
activesupport/test/fixtures/isolation_test
dist
railties/test/500.html
railties/test/fixtures/tmp
railties/test/initializer/root/log
railties/doc
railties/guides/output
railties/tmp
.rvmrc
.rbenv-version
RDOC_MAIN.rdoc

View File

@@ -1,25 +0,0 @@
script: 'ci/travis.rb'
rvm:
- 1.8.7
- 1.9.2
- 1.9.3
env:
- "GEM=railties"
- "GEM=ap,am,amo,ares,as"
- "GEM=ar:mysql"
- "GEM=ar:mysql2"
- "GEM=ar:sqlite3"
- "GEM=ar:postgresql"
notifications:
email: false
irc:
on_success: change
on_failure: always
channels:
- "irc.freenode.org#rails-contrib"
campfire:
on_success: change
on_failure: always
rooms:
- secure: "CGWvthGkBKNnTnk9YSmf9AXKoiRI33fCl5D3jU4nx3cOPu6kv2R9nMjt9EAo\nOuS4Q85qNSf4VNQ2cUPNiNYSWQ+XiTfivKvDUw/QW9r1FejYyeWarMsSBWA+\n0fADjF1M2dkDIVLgYPfwoXEv7l+j654F1KLKB69F0F/netwP9CQ="
bundler_args: --path vendor/bundle

View File

@@ -1,4 +1,3 @@
--exclude /templates/
--quiet
act*/lib/**/*.rb
railties/lib/**/*.rb

75
Gemfile
View File

@@ -1,90 +1,63 @@
source "http://rubygems.org"
gemspec
source 'http://rubygems.org'
if ENV['AREL']
gem "arel", :path => ENV['AREL']
else
gem "arel", :git => "git://github.com/rails/arel.git"
end
gem "bcrypt-ruby", "~> 3.0.0"
gem "jquery-rails"
# This needs to be with require false to avoid
# it being automatically loaded by sprockets
gem "uglifier", ">= 1.0.3", :require => false
gem "rails", :path => File.dirname(__FILE__)
gem "rake", ">= 0.8.7"
gem "mocha", "0.10.5"
group :doc do
# The current sdoc cannot generate GitHub links due
# to a bug, but the PR that fixes it has been there
# for some weeks unapplied. As a temporary solution
# this is our own fork with the fix.
gem "sdoc", :git => 'git://github.com/fxn/sdoc.git'
gem "RedCloth", "~> 4.2" if RUBY_VERSION < "1.9.3"
gem "w3c_validators"
end
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
gem "rdoc", ">= 2.5.10"
gem "horo", ">= 1.0.2"
# AS
gem "memcache-client", ">= 1.8.5"
# AM
gem "text-format", "~> 1.0.0"
platforms :mri_18 do
gem "system_timer"
gem "json"
end
# Add your own local bundler stuff
instance_eval File.read ".Gemfile" if File.exists? ".Gemfile"
platforms :mri do
group :test do
gem 'ruby-prof', '~> 0.11.2'
end
gem "ruby-debug", ">= 0.10.3"
end
platforms :ruby do
if ENV["RB_FSEVENT"]
gem "rb-fsevent"
end
gem "json"
gem "yajl-ruby"
gem "nokogiri", ">= 1.4.4"
gem 'json'
gem 'yajl-ruby'
gem "nokogiri", ">= 1.4.3.1"
# AR
gem "sqlite3", "~> 1.3.4"
gem "sqlite3-ruby", "~> 1.3.1", :require => 'sqlite3'
group :db do
gem "pg", ">= 0.11.0"
gem "pg", ">= 0.9.0"
gem "mysql", ">= 2.8.1"
gem "mysql2", ">= 0.3.10"
gem "mysql2", ">= 0.2.3"
end
end
platforms :jruby do
gem "json"
gem "activerecord-jdbcsqlite3-adapter", ">= 1.2.0"
gem "ruby-debug", ">= 0.10.3"
# This is needed by now to let tests work on JRuby
# TODO: When the JRuby guys merge jruby-openssl in
# jruby this will be removed
gem "jruby-openssl"
gem "activerecord-jdbcsqlite3-adapter"
group :db do
gem "activerecord-jdbcmysql-adapter", ">= 1.2.0"
gem "activerecord-jdbcpostgresql-adapter", ">= 1.2.0"
gem "activerecord-jdbcmysql-adapter"
gem "activerecord-jdbcpostgresql-adapter"
end
end
# gems that are necessary for ActiveRecord tests with Oracle database
if ENV['ORACLE_ENHANCED_PATH'] || ENV['ORACLE_ENHANCED']
platforms :ruby do
gem "ruby-oci8", ">= 2.0.4"
gem 'ruby-oci8', ">= 2.0.4"
end
if ENV['ORACLE_ENHANCED_PATH']
gem "activerecord-oracle_enhanced-adapter", :path => ENV['ORACLE_ENHANCED_PATH']
gem 'activerecord-oracle_enhanced-adapter', :path => ENV['ORACLE_ENHANCED_PATH']
else
gem "activerecord-oracle_enhanced-adapter", :git => "git://github.com/rsim/oracle-enhanced.git"
end
end
gem 'benchmark-ips'

View File

@@ -1 +1 @@
3.1.8
3.0.0

View File

@@ -1,43 +1,38 @@
== Welcome to Rails
== Welcome to \Rails
Rails is a web-application framework that includes everything needed to create
database-backed web applications according to the {Model-View-Controller (MVC)}[http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller] pattern.
\Rails is a web-application framework that includes everything needed to create
database-backed web applications according to the Model-View-Control pattern.
Understanding the MVC pattern is key to understanding Rails. MVC divides your application
into three layers, each with a specific responsibility.
This pattern splits the view (also called the presentation) into "dumb"
templates that are primarily responsible for inserting pre-built data in between
HTML tags. The model contains the "smart" domain objects (such as Account,
Product, Person, Post) that holds all the business logic and knows how to
persist themselves to a database. The controller handles the incoming requests
(such as Save New Account, Update Product, Show Post) by manipulating the model
and directing data to the view.
The View layer is composed of "templates" that are responsible for providing
appropriate representations of your application's resources. Templates
can come in a variety of formats, but most view templates are \HTML with embedded Ruby
code (.erb files).
The Model layer represents your domain model (such as Account, Product, Person, Post)
and encapsulates the business logic that is specific to your application. In Rails,
database-backed model classes are derived from ActiveRecord::Base. Active Record allows
you to present the data from database rows as objects and embellish these data objects
with business logic methods. Although most Rails models are backed by a database, models
can also be ordinary Ruby classes, or Ruby classes that implement a set of interfaces as
provided by the ActiveModel module. You can read more about Active Record in its
In \Rails, the model is handled by what's called an object-relational mapping
layer entitled Active Record. This layer allows you to present the data from
database rows as objects and embellish these data objects with business logic
methods. You can read more about Active Record in its
{README}[link:files/activerecord/README_rdoc.html].
The Controller layer is responsible for handling incoming HTTP requests and providing a
suitable response. Usually this means returning \HTML, but Rails controllers can also
generate XML, JSON, PDFs, mobile-specific views, and more. Controllers manipulate models
and render view templates in order to generate the appropriate HTTP response.
The controller and view are handled by the Action Pack, which handles both
layers by its two parts: Action View and Action Controller. These two layers
are bundled in a single package due to their heavy interdependence. This is
unlike the relationship between the Active Record and Action Pack that is much
more separate. Each of these packages can be used independently outside of
\Rails. You can read more about Action Pack in its
{README}[link:files/actionpack/README_rdoc.html].
In Rails, the Controller and View layers are handled together by Action Pack.
These two layers are bundled in a single package due to their heavy interdependence.
This is unlike the relationship between Active Record and Action Pack which are
independent. Each of these packages can be used independently outside of Rails. You
can read more about Action Pack in its {README}[link:files/actionpack/README_rdoc.html].
== Getting Started
1. Install Rails at the command prompt if you haven't yet:
1. Install \Rails at the command prompt if you haven't yet:
gem install rails
2. At the command prompt, create a new Rails application:
2. At the command prompt, create a new \Rails application:
rails new myapp
@@ -49,25 +44,25 @@ can read more about Action Pack in its {README}[link:files/actionpack/README_rdo
Run with <tt>--help</tt> for options.
4. Go to http://localhost:3000 and you'll see:
4. Go to http://localhost:3000/ and you'll see:
"Welcome aboard: You're riding Ruby on Rails!"
5. Follow the guidelines to start developing your application. You may find the following resources handy:
5. Follow the guidelines to start developing your application. You can find the following resources handy:
* The README file created within your application.
* The {Getting Started with Rails}[http://guides.rubyonrails.org/getting_started.html].
* The {Ruby on Rails Tutorial}[http://railstutorial.org/book].
* The {Ruby on Rails Guides}[http://guides.rubyonrails.org].
* The {API Documentation}[http://api.rubyonrails.org].
* The {Ruby on Rails guides}[http://guides.rubyonrails.org/getting_started.html].
* The {API documentation}[http://api.rubyonrails.org].
== Contributing
We encourage you to contribute to Ruby on Rails! Please check out the {Contributing to Rails
guide}[http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html] for guidelines about how
We encourage you to contribute to Ruby on \Rails! Please check out the {Contributing to Rails
guide}[http://edgeguides.rubyonrails.org/contributing_to_rails.html] for guidelines about how
to proceed. {Join us}[http://contributors.rubyonrails.org]!
== License
Ruby on Rails is released under the MIT license.
Ruby on \Rails is released under the MIT license.

142
Rakefile Executable file → Normal file
View File

@@ -1,17 +1,34 @@
#!/usr/bin/env rake
gem 'rdoc', '>= 2.5.10'
require 'rdoc'
require 'rake'
require 'rdoc/task'
require 'sdoc'
require 'net/http'
require 'rake/gempackagetask'
$:.unshift File.expand_path('..', __FILE__)
require "tasks/release"
# RDoc skips some files in the Rails tree due to its binary? predicate. This is a quick
# hack for edge docs, until we decide which is the correct way to address this issue.
# If not fixed in RDoc itself, via an option or something, we should probably move this
# to railties and use it also in doc:rails.
def hijack_rdoc!
require "rdoc/parser"
class << RDoc::Parser
def binary?(file)
s = File.read(file, 1024) or return false
desc "Build gem files for all projects"
task :build => "all:build"
desc "Release all gems to gemcutter and create a tag"
task :release => "all:release"
if s[0, 2] == Marshal.dump('')[0, 2] then
true
elsif file =~ /erb\.rb$/ then
false
elsif s.index("\x00") then # ORIGINAL is s.scan(/<%|%>/).length >= 4 || s.index("\x00")
true
elsif 0.respond_to? :fdiv then
s.count("^ -~\t\r\n").fdiv(s.size) > 0.3
else # HACK 1.8.6
(s.count("^ -~\t\r\n").to_f / s.size) > 0.3
end
end
end
end
PROJECTS = %w(activesupport activemodel actionpack actionmailer activeresource activerecord railties)
@@ -37,6 +54,27 @@ task :smoke do
system %(cd activerecord && #{$0} sqlite3:isolated_test)
end
spec = eval(File.read('rails.gemspec'))
Rake::GemPackageTask.new(spec) do |pkg|
pkg.gem_spec = spec
end
desc "Release all gems to gemcutter. Package rails, package & push components, then push rails"
task :release => :release_projects do
require 'rake/gemcutter'
Rake::Gemcutter::Tasks.new(spec).define
Rake::Task['gem:push'].invoke
end
desc "Release all components to gemcutter."
task :release_projects => :package do
errors = []
PROJECTS.each do |project|
system(%(cd #{project} && #{$0} release)) || errors << project
end
fail("Errors in #{errors.join(', ')}") unless errors.empty?
end
desc "Install gems for all projects."
task :install => :gem do
version = File.read("RAILS_VERSION").strip
@@ -50,67 +88,35 @@ end
desc "Generate documentation for the Rails framework"
RDoc::Task.new do |rdoc|
RDOC_MAIN = 'RDOC_MAIN.rdoc'
# This is a hack.
#
# Backslashes are needed to prevent RDoc from autolinking "Rails" to the
# documentation of the Rails module. On the other hand, as of this
# writing README.rdoc is displayed in the front page of the project in
# GitHub, where backslashes are shown and look weird.
#
# The temporary solution is to have a README.rdoc without backslashes for
# GitHub, and gsub it to generate the main page of the API.
#
# Also, relative links in GitHub have to point to blobs, whereas in the API
# they need to point to files.
#
# The idea for the future is to have totally different files, since the
# API is no longer a generic entry point to Rails and deserves a
# dedicated main page specifically thought as an API entry point.
rdoc.before_running_rdoc do
rdoc_main = File.read('README.rdoc')
# The ^(?=\S) assertion prevents code blocks from being processed,
# since no autolinking happens there and RDoc displays the backslash
# otherwise.
rdoc_main.gsub!(/^(?=\S).*?\b(?=Rails)\b/) { "#$&\\" }
rdoc_main.gsub!(%r{link:blob/master/(\w+)/README\.rdoc}, "link:files/\\1/README_rdoc.html")
File.open(RDOC_MAIN, 'w') do |f|
f.write(rdoc_main)
end
rdoc.rdoc_files.include(RDOC_MAIN)
end
hijack_rdoc!
rdoc.rdoc_dir = 'doc/rdoc'
rdoc.title = "Ruby on Rails Documentation"
rdoc.options << '-f' << 'sdoc'
rdoc.options << '-T' << 'rails'
rdoc.options << '-f' << 'horo'
rdoc.options << '-c' << 'utf-8'
rdoc.options << '-g' # SDoc flag, link methods to GitHub
rdoc.options << '-m' << RDOC_MAIN
rdoc.options << '-m' << 'README.rdoc'
rdoc.rdoc_files.include('railties/CHANGELOG.md')
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('railties/CHANGELOG')
rdoc.rdoc_files.include('railties/MIT-LICENSE')
rdoc.rdoc_files.include('railties/README.rdoc')
rdoc.rdoc_files.include('railties/lib/**/*.rb')
rdoc.rdoc_files.exclude('railties/lib/rails/generators/**/templates/**/*.rb')
rdoc.rdoc_files.exclude('railties/lib/rails/generators/**/templates/*')
rdoc.rdoc_files.include('activerecord/README.rdoc')
rdoc.rdoc_files.include('activerecord/CHANGELOG.md')
rdoc.rdoc_files.include('activerecord/CHANGELOG')
rdoc.rdoc_files.include('activerecord/lib/active_record/**/*.rb')
rdoc.rdoc_files.exclude('activerecord/lib/active_record/vendor/*')
rdoc.rdoc_files.include('activeresource/README.rdoc')
rdoc.rdoc_files.include('activeresource/CHANGELOG.md')
rdoc.rdoc_files.include('activeresource/CHANGELOG')
rdoc.rdoc_files.include('activeresource/lib/active_resource.rb')
rdoc.rdoc_files.include('activeresource/lib/active_resource/*')
rdoc.rdoc_files.include('actionpack/README.rdoc')
rdoc.rdoc_files.include('actionpack/CHANGELOG.md')
rdoc.rdoc_files.include('actionpack/CHANGELOG')
rdoc.rdoc_files.include('actionpack/lib/abstract_controller/**/*.rb')
rdoc.rdoc_files.include('actionpack/lib/action_controller/**/*.rb')
rdoc.rdoc_files.include('actionpack/lib/action_dispatch/**/*.rb')
@@ -118,18 +124,17 @@ RDoc::Task.new do |rdoc|
rdoc.rdoc_files.exclude('actionpack/lib/action_controller/vendor/*')
rdoc.rdoc_files.include('actionmailer/README.rdoc')
rdoc.rdoc_files.include('actionmailer/CHANGELOG.md')
rdoc.rdoc_files.include('actionmailer/CHANGELOG')
rdoc.rdoc_files.include('actionmailer/lib/action_mailer/base.rb')
rdoc.rdoc_files.include('actionmailer/lib/action_mailer/mail_helper.rb')
rdoc.rdoc_files.exclude('actionmailer/lib/action_mailer/vendor/*')
rdoc.rdoc_files.include('activesupport/README.rdoc')
rdoc.rdoc_files.include('activesupport/CHANGELOG.md')
rdoc.rdoc_files.include('activesupport/CHANGELOG')
rdoc.rdoc_files.include('activesupport/lib/active_support/**/*.rb')
rdoc.rdoc_files.exclude('activesupport/lib/active_support/vendor/*')
rdoc.rdoc_files.include('activemodel/README.rdoc')
rdoc.rdoc_files.include('activemodel/CHANGELOG.md')
rdoc.rdoc_files.include('activemodel/CHANGELOG')
rdoc.rdoc_files.include('activemodel/lib/active_model/**/*.rb')
end
@@ -139,7 +144,6 @@ task :rdoc do
FileUtils.copy "activerecord/examples/associations.png", "doc/rdoc/files/examples/associations.png"
end
desc 'Bump all versions to match version.rb'
task :update_versions do
require File.dirname(__FILE__) + "/version"
@@ -167,27 +171,3 @@ task :update_versions do
end
end
end
#
# We have a webhook configured in Github that gets invoked after pushes.
# This hook triggers the following tasks:
#
# * updates the local checkout
# * updates Rails Contributors
# * generates and publishes edge docs
# * if there's a new stable tag, generates and publishes stable docs
#
# Everything is automated and you do NOT need to run this task normally.
#
# We publish a new version by tagging, and pushing a tag does not trigger
# that webhook. Stable docs would be updated by any subsequent regular
# push, but if you want that to happen right away just run this.
#
desc 'Publishes docs, run this AFTER a new stable tag has been pushed'
task :publish_docs do
Net::HTTP.new('rails-hooks.hashref.com').start do |http|
request = Net::HTTP::Post.new('/rails-master-hook')
response = http.request(request)
puts response.body
end
end

409
actionmailer/CHANGELOG Normal file
View File

@@ -0,0 +1,409 @@
*Rails 3.0.0 (August 29, 2010)*
* subject is automatically looked up on I18n using mailer_name and action_name as scope as in t(".subject") [JK]
* Changed encoding behaviour of mail, so updated tests in actionmailer and bumped mail version to 2.2.1 [ML]
* Added ability to pass Proc objects to the defaults hash [ML]
* Removed all quoting.rb type files from ActionMailer and put Mail 2.2.0 in instead [ML]
* Lot of updates to various test cases that now work better with the new Mail and so have different expectations
* Added interceptors and observers from Mail [ML]
ActionMailer::Base.register_interceptor calls Mail.register_interceptor
ActionMailer::Base.register_observer calls Mail.register_observer
* Mail::Part now no longer has nil as a default charset, it is always set to something, and defaults to UTF-8
* Added explict setting of charset in set_fields! method to make sure Mail has the user defined default
* Removed quoting.rb and refactored for Mail to take responsibility of all quoting and auto encoding requirements for the header.
* Fixed several tests which had incorrect encoding.
* Changed all utf-8 to UTF-8 for consistency
* Whole new API added with tests. See base.rb for full details. Old API is deprecated.
* The Mail::Message class has helped methods for all the field types that return 'common' defaults for the common use case, so to get the subject, mail.subject will give you a string, mail.date will give you a DateTime object, mail.from will give you an array of address specs (mikel@test.lindsaar.net) etc. If you want to access the field object itself, call mail[:field_name] which will return the field object you want, which you can then chain, like mail[:from].formatted
* Mail#content_type now returns the content_type field as a string. If you want the mime type of a mail, then you call Mail#mime_type (eg, text/plain), if you want the parameters of the content type field, you call Mail#content_type_parameters which gives you a hash, eg {'format' => 'flowed', 'charset' => 'utf-8'}
* ActionMailer::Base :default_implicit_parts_order now is in the sequence of the order you want, no reversing of ordering takes place. The default order now is text/plain, then text/enriched, then text/html and then any other part that is not one of these three.
* Mail does not have "quoted_body", "quoted_subject" etc. All of these are accessed via body.encoded, subject.encoded etc
* Every object in a Mail object returns an object, never a string. So Mail.body returns a Mail::Body class object, need to call #encoded or #decoded to get the string you want.
* Mail::Message#set_content_type does not exist, it is simply Mail::Message#content_type
* Every mail message gets a unique message_id unless you specify one, had to change all the tests that check for equality with expected.encoded == actual.encoded to first replace their message_ids with control values
* Mail now has a proper concept of parts, remove the ActionMailer::Part and ActionMailer::PartContainer classes
* Calling #encoded on any object returns it as a string ready to go into the output stream of an email, this means it includes the \r\n at the end of the lines and the object is pre-wrapped with \r\n\t if it is a header field. Also, the "encoded" value includes the field name if it is a header field.
* Attachments are only the actual attachment, with filename etc. A part contains an attachment. The part has the content_type etc. So attachments.last.content_type is invalid. But parts.last.content_type
* There is no idea of a "sub_head" in Mail. A part is just a Message with some extra functionality, so it just has a "header" like a normal mail message
*2.3.2 [Final] (March 15, 2009)*
* Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones]
* Fixed RFC-2045 quoted-printable bug #1421 [squadette]
* Fixed that no body charset would be set when there are attachments present #740 [Paweł Kondzior]
*2.2.1 [RC2] (November 14th, 2008)*
* Turn on STARTTLS if it is available in Net::SMTP (added in Ruby 1.8.7) and the SMTP server supports it (This is required for Gmail's SMTP server) #1336 [Grant Hollingworth]
*2.2.0 [RC1] (October 24th, 2008)*
* Add layout functionality to mailers [Pratik Naik]
Mailer layouts behaves just like controller layouts, except layout names need to
have '_mailer' postfix for them to be automatically picked up.
*2.1.0 (May 31st, 2008)*
* Fixed that a return-path header would be ignored #7572 [joost]
* Less verbose mail logging: just recipients for :info log level; the whole email for :debug only. #8000 [iaddict, Tarmo Tänav]
* Updated TMail to version 1.2.1 [Mikel Lindsaar]
* Fixed that you don't have to call super in ActionMailer::TestCase#setup #10406 [jamesgolick]
*2.0.2* (December 16th, 2007)
* Included in Rails 2.0.2
*2.0.1* (December 7th, 2007)
* Update ActionMailer so it treats ActionView the same way that ActionController does. Closes #10244 [Rick Olson]
* Pass the template_root as an array as ActionView's view_path
* Request templates with the "#{mailer_name}/#{action}" as opposed to just "#{action}"
* Fixed that partials would be broken when using text.plain.erb as the extension #10130 [java]
* Update README to use new smtp settings configuration API. Closes #10060 [psq]
* Allow ActionMailer subclasses to individually set their delivery method (so two subclasses can have different delivery methods) #10033 [Zach Dennis]
* Update TMail to v1.1.0. Use an updated version of TMail if available. [Mikel Lindsaar]
* Introduce a new base test class for testing Mailers. ActionMailer::TestCase [Michael Koziarski]
* Fix silent failure of rxml templates. #9879 [jstewart]
* Fix attachment decoding when using the TMail C extension. #7861 [orangechicken]
* Increase mail delivery test coverage. #8692 [Kamal Fariz Mahyuddin]
* Register alternative template engines using ActionMailer::Base.register_template_extension('haml'). #7534 [cwd, Josh Peek]
* Only load ActionController::UrlWriter if ActionController is present [Rick Olson]
* Make sure parsed emails recognized attachments nested inside multipart parts. #6714 [Jamis Buck]
* Allow mailer actions named send by using __send__ internally. #6467 [iGEL]
* Add assert_emails and assert_no_emails to test the number of emails delivered. #6479 [Jonathan Viney]
# Assert total number of emails delivered:
assert_emails 0
ContactMailer.deliver_contact
assert_emails 1
# Assert number of emails delivered within a block:
assert_emails 1 do
post :signup, :name => 'Jonathan'
end
*1.3.3* (March 12th, 2007)
* Depend on Action Pack 1.13.3
*1.3.2* (February 5th, 2007)
* Deprecate server_settings renaming it to smtp_settings, add sendmail_settings to allow you to override the arguments to and location of the sendmail executable. [Michael Koziarski]
*1.3.1* (January 16th, 2007)
* Depend on Action Pack 1.13.1
*1.3.0* (January 16th, 2007)
* Make mime version default to 1.0. closes #2323 [ror@andreas-s.net]
* Make sure quoted-printable text is decoded correctly when only portions of the text are encoded. closes #3154. [jon@siliconcircus.com]
* Make sure DOS newlines in quoted-printable text are normalized to unix newlines before unquoting. closes #4166 and #4452. [Jamis Buck]
* Fixed that iconv decoding should catch InvalidEncoding #3153 [jon@siliconcircus.com]
* Tighten rescue clauses. #5985 [james@grayproductions.net]
* Automatically included ActionController::UrlWriter, such that URL generation can happen within ActionMailer controllers. [David Heinemeier Hansson]
* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
* Mailer template root applies to a class and its subclasses rather than acting globally. #5555 [somekool@gmail.com]
* Resolve action naming collision. #5520 [ssinghi@kreeti.com]
* ActionMailer::Base documentation rewrite. Closes #4991 [Kevin Clark, Marcel Molina Jr.]
* Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
* Correct spurious documentation example code which results in a SyntaxError. [Marcel Molina Jr.]
*1.2.1* (April 6th, 2006)
* Be part of Rails 1.1.1
*1.2.0* (March 27th, 2006)
* Nil charset caused subject line to be improperly quoted in implicitly multipart messages #2662 [ehalvorsen+rails@runbox.com]
* Parse content-type apart before using it so that sub-parts of the header can be set correctly #2918 [Jamis Buck]
* Make custom headers work in subparts #4034 [elan@bluemandrill.com]
* Template paths with dot chars in them no longer mess up implicit template selection for multipart messages #3332 [Chad Fowler]
* Make sure anything with content-disposition of "attachment" is passed to the attachment presenter when parsing an email body [Jamis Buck]
* Make sure TMail#attachments includes anything with content-disposition of "attachment", regardless of content-type [Jamis Buck]
*1.1.5* (December 13th, 2005)
* Become part of Rails 1.0
*1.1.4* (December 7th, 2005)
* Rename Version constant to VERSION. #2802 [Marcel Molina Jr.]
* Stricter matching for implicitly multipart filenames excludes files ending in unsupported extensions (such as foo.rhtml.bak) and without a two-part content type (such as foo.text.rhtml or foo.text.really.plain.rhtml). #2398 [Dave Burt <dave@burt.id.au>, Jeremy Kemper]
*1.1.3* (November 7th, 2005)
* Allow Mailers to have custom initialize methods that set default instance variables for all mail actions #2563 [mrj@bigpond.net.au]
*1.1.2* (October 26th, 2005)
* Upgraded to Action Pack 1.10.2
*1.1.1* (October 19th, 2005)
* Upgraded to Action Pack 1.10.1
*1.1.0* (October 16th, 2005)
* Update and extend documentation (rdoc)
* Minero Aoki made TMail available to Rails/ActionMailer under the MIT license (instead of LGPL) [RubyConf '05]
* Austin Ziegler made Text::Simple available to Rails/ActionMailer under a MIT-like licens [See rails ML, subject "Text::Format Licence Exception" on Oct 15, 2005]
* Fix vendor require paths to prevent files being required twice
* Don't add charset to content-type header for a part that contains subparts (for AOL compatibility) #2013 [John Long]
* Preserve underscores when unquoting message bodies #1930
* Encode multibyte characters correctly #1894
* Multipart messages specify a MIME-Version header automatically #2003 [John Long]
* Add a unified render method to ActionMailer (delegates to ActionView::Base#render)
* Move mailer initialization to a separate (overridable) method, so that subclasses may alter the various defaults #1727
* Look at content-location header (if available) to determine filename of attachments #1670
* ActionMailer::Base.deliver(email) had been accidentally removed, but was documented in the Rails book #1849
* Fix problem with sendmail delivery where headers should be delimited by \n characters instead of \r\n, which confuses some mail readers #1742 [Kent Sibilev]
*1.0.1* (11 July, 2005)
* Bind to Action Pack 1.9.1
*1.0.0* (6 July, 2005)
* Avoid adding nil header values #1392
* Better multipart support with implicit multipart/alternative and sorting of subparts [John Long]
* Allow for nested parts in multipart mails #1570 [Flurin Egger]
* Normalize line endings in outgoing mail bodies to "\n" #1536 [John Long]
* Allow template to be explicitly specified #1448 [tuxie@dekadance.se]
* Allow specific "multipart/xxx" content-type to be set on multipart messages #1412 [Flurin Egger]
* Unquoted @ characters in headers are now accepted in spite of RFC 822 #1206
* Helper support (borrowed from ActionPack)
* Silently ignore Errno::EINVAL errors when converting text.
* Don't cause an error when parsing an encoded attachment name #1340 [lon@speedymac.com]
* Nested multipart message parts are correctly processed in TMail::Mail#body
* BCC headers are removed when sending via SMTP #1402
* Added 'content_type' accessor, to allow content type to be set on a per-message basis. content_type defaults to "text/plain".
* Silently ignore Iconv::IllegalSequence errors when converting text #1341 [lon@speedymac.com]
* Support attachments and multipart messages.
* Added new accessors for the various mail properties.
* Fix to only perform the charset conversion if a 'from' and a 'to' charset are given (make no assumptions about what the charset was) #1276 [Jamis Buck]
* Fix attachments and content-type problems #1276 [Jamis Buck]
* Fixed the TMail#body method to look at the content-transfer-encoding header and unquote the body according to the rules it specifies #1265 [Jamis Buck]
* Added unquoting even if the iconv lib can't be loaded--in that case, only the charset conversion is skipped #1265 [Jamis Buck]
* Added automatic decoding of base64 bodies #1214 [Jamis Buck]
* Added that delivery errors are caught in a way so the mail is still returned whether the delivery was successful or not
* Fixed that email address like "Jamis Buck, M.D." <wild.medicine@example.net> would cause the quoter to generate emails resulting in "bad address" errors from the mail server #1220 [Jamis Buck]
*0.9.1* (20th April, 2005)
* Depend on Action Pack 1.8.1
*0.9.0* (19th April, 2005)
* Added that deliver_* will now return the email that was sent
* Added that quoting to UTF-8 only happens if the characters used are in that range #955 [Jamis Buck]
* Fixed quoting for all address headers, not just to #955 [Jamis Buck]
* Fixed unquoting of emails that doesn't have an explicit charset #1036 [wolfgang@stufenlos.net]
*0.8.1* (27th March, 2005)
* Fixed that if charset was found that the end of a mime part declaration TMail would throw an error #919 [lon@speedymac.com]
* Fixed that TMail::Unquoter would fail to recognize quoting method if it was in lowercase #919 [lon@speedymac.com]
* Fixed that TMail::Encoder would fail when it attempts to parse e-mail addresses which are encoded using something other than the messages encoding method #919 [lon@speedymac.com]
* Added rescue for missing iconv library and throws warnings if subject/body is called on a TMail object without it instead
*0.8.0* (22th March, 2005)
* Added framework support for processing incoming emails with an Action Mailer class. See example in README.
*0.7.1* (7th March, 2005)
* Bind to newest Action Pack (1.5.1)
*0.7.0* (24th February, 2005)
* Added support for charsets for both subject and body. The default charset is now UTF-8 #673 [Jamis Buck]. Examples:
def iso_charset(recipient)
@recipients = recipient
@subject = "testing iso charsets"
@from = "system@loudthinking.com"
@body = "Nothing to see here."
@charset = "iso-8859-1"
end
def unencoded_subject(recipient)
@recipients = recipient
@subject = "testing unencoded subject"
@from = "system@loudthinking.com"
@body = "Nothing to see here."
@encode_subject = false
@charset = "iso-8859-1"
end
*0.6.1* (January 18th, 2005)
* Fixed sending of emails to use Tmail#from not the deprecated Tmail#from_address
*0.6* (January 17th, 2005)
* Fixed that bcc and cc should be settable through @bcc and @cc -- not just @headers["Bcc"] and @headers["Cc"] #453 [Eric Hodel]
* Fixed Action Mailer to be "warnings safe" so you can run with ruby -w and not get framework warnings #453 [Eric Hodel]
*0.5*
* Added access to custom headers, like cc, bcc, and reply-to #268 [Andreas Schwarz]. Example:
def post_notification(recipients, post)
@recipients = recipients
@from = post.author.email_address_with_name
@headers["bcc"] = SYSTEM_ADMINISTRATOR_EMAIL
@headers["reply-to"] = "notifications@example.com"
@subject = "[#{post.account.name} #{post.title}]"
@body["post"] = post
end
*0.4* (5)
* Consolidated the server configuration options into Base#server_settings= and expanded that with controls for authentication and more [Marten]
NOTE: This is an API change that could potentially break your application if you used the old application form. Please do change!
* Added Base#deliveries as an accessor for an array of emails sent out through that ActionMailer class when using the :test delivery option. [Jeremy Kemper]
* Added Base#perform_deliveries= which can be set to false to turn off the actual delivery of the email through smtp or sendmail.
This is especially useful for functional testing that shouldn't send off real emails, but still trigger delivery_* methods.
* Added option to specify delivery method with Base#delivery_method=. Default is :smtp and :sendmail is currently the only other option.
Sendmail is assumed to be present at "/usr/sbin/sendmail" if that option is used. [Kent Sibilev]
* Dropped "include TMail" as it added to much baggage into the default namespace (like Version) [Chad Fowler]
*0.3*
* First release

View File

@@ -1,26 +0,0 @@
## Rails 3.1.8 (Aug 9, 2012)
* No changes.
## Rails 3.1.7 (Jul 26, 2012)
* No changes.
## Rails 3.1.6 (Jun 12, 2012)
* No changes.
## Rails 3.1.5 (May 31, 2012) ##
* Increase minimum version of mail.
## Rails 3.1.1 (October 7, 2011) ##
* No changes
## Rails 3.1.0 (August 30, 2011) ##
* No changes
Please check [3-0-stable](https://github.com/rails/rails/blob/3-0-stable/actionmailer/CHANGELOG) for previous changes.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2011 David Heinemeier Hansson
Copyright (c) 2004-2010 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -10,7 +10,7 @@ Mail gem. It provides a way to make emails using templates in the same
way that Action Controller renders views using templates.
Additionally, an Action Mailer class can be used to process incoming email,
such as allowing a blog to accept new posts from an email (which could even
such as allowing a weblog to accept new posts from an email (which could even
have been sent from a phone).
== Sending emails
@@ -32,7 +32,7 @@ This can be as simple as:
end
The body of the email is created by using an Action View template (regular
ERB) that has the instance variables that are declared in the mailer action.
ERb) that has the instance variables that are declared in the mailer action.
So the corresponding body template for the method above could look like this:
@@ -59,9 +59,7 @@ generated would look like this:
Mr. david@loudthinking.com
Thank you for signing up!
In previous version of Rails you would call <tt>create_method_name</tt> and
In previous version of rails you would call <tt>create_method_name</tt> and
<tt>deliver_method_name</tt>. Rails 3.0 has a much simpler interface, you
simply call the method and optionally call +deliver+ on the return value.
@@ -74,25 +72,12 @@ Or you can just chain the methods together like:
Notifier.welcome.deliver # Creates the email and sends it immediately
== Setting defaults
It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally it is also possible to pass in a Proc that will get evaluated when it is needed.
Note that every value you set with this method will get over written if you use the same key in your mailer method.
Example:
class Authenticationmailer < ActionMailer::Base
default :from => "awesome@application.com", :subject => Proc.new { "E-mail was generated at #{Time.now}" }
.....
end
== Receiving emails
To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes an
email object as its single parameter. The Action Mailer framework has a corresponding class method,
To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes a
tmail object as its single parameter. The Action Mailer framework has a corresponding class method,
which is also called <tt>receive</tt>, that accepts a raw, unprocessed email as a string, which it then turns
into the email object and calls the receive instance method.
into the tmail object and calls the receive instance method.
Example:
@@ -104,7 +89,7 @@ Example:
)
if email.has_attachments?
email.attachments.each do |attachment|
for attachment in email.attachments
page.attachments.create({
:file => attachment, :description => email.subject
})
@@ -119,7 +104,7 @@ trivial case like this:
rails runner 'Mailman.receive(STDIN.read)'
However, invoking Rails in the runner for each mail to be received is very resource intensive. A single
instance of Rails should be run within a daemon, if it is going to be utilized to process more than just
instance of Rails should be run within a daemon if it is going to be utilized to process more than just
a limited number of email.
== Configuration
@@ -143,7 +128,7 @@ The latest version of Action Mailer can be installed with Rubygems:
Source code can be downloaded as part of the Rails project on GitHub
* https://github.com/rails/rails/tree/master/actionmailer
* http://github.com/rails/rails/tree/master/actionmailer/
== License
@@ -159,5 +144,4 @@ API documentation is at
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
* https://github.com/rails/rails/issues
* https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets

8
actionmailer/Rakefile Executable file → Normal file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env rake
require 'rake'
require 'rake/testtask'
require 'rake/packagetask'
require 'rubygems/package_task'
require 'rake/gempackagetask'
desc "Default Task"
task :default => [ :test ]
@@ -17,14 +17,14 @@ namespace :test do
task :isolated do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/**/*_test.rb").all? do |file|
sh(ruby, '-Ilib:test', file)
system(ruby, '-Ilib:test', file)
end or raise "Failures"
end
end
spec = eval(File.read('actionmailer.gemspec'))
Gem::PackageTask.new(spec) do |p|
Rake::GemPackageTask.new(spec) do |p|
p.gem_spec = spec
end

View File

@@ -11,11 +11,14 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'actionmailer'
s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.files = Dir['CHANGELOG', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.require_path = 'lib'
s.requirements << 'none'
s.has_rdoc = true
s.add_dependency('actionpack', version)
s.add_dependency('mail', '~> 2.5')
s.add_dependency('mail', '~> 2.2.5')
end

View File

@@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2011 David Heinemeier Hansson
# Copyright (c) 2004-2010 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -26,7 +26,6 @@ $:.unshift(actionpack_path) if File.directory?(actionpack_path) && !$:.include?(
require 'abstract_controller'
require 'action_view'
require 'action_mailer/version'
# Common Active Support usage in Action Mailer
require 'active_support/core_ext/class'
@@ -44,6 +43,7 @@ module ActionMailer
autoload :Collector
autoload :Base
autoload :DeliveryMethods
autoload :DeprecatedApi
autoload :MailHelper
autoload :OldApi
autoload :TestCase

View File

@@ -1,28 +1,26 @@
module ActionMailer
module AdvAttrAccessor #:nodoc:
def adv_attr_accessor(name, deprecation=nil)
ivar = "@#{name}"
deprecation ||= "Please pass :#{name} as hash key to mail() instead"
def adv_attr_accessor(*names)
names.each do |name|
ivar = "@#{name}"
class_eval <<-ACCESSORS, __FILE__, __LINE__ + 1
def #{name}=(value)
ActiveSupport::Deprecation.warn "#{name}= is deprecated. #{deprecation}"
#{ivar} = value
end
def #{name}(*args)
raise ArgumentError, "expected 0 or 1 parameters" unless args.length <= 1
if args.empty?
ActiveSupport::Deprecation.warn "#{name}() is deprecated and will be removed in future versions."
#{ivar} if instance_variable_names.include?(#{ivar.inspect})
else
ActiveSupport::Deprecation.warn "#{name}(value) is deprecated. #{deprecation}"
#{ivar} = args.first
class_eval <<-ACCESSORS, __FILE__, __LINE__ + 1
def #{name}=(value)
#{ivar} = value
end
end
ACCESSORS
self.protected_instance_variables << ivar if self.respond_to?(:protected_instance_variables)
def #{name}(*args)
raise ArgumentError, "expected 0 or 1 parameters" unless args.length <= 1
if args.empty?
#{ivar} if instance_variable_names.include?(#{ivar.inspect})
else
#{ivar} = args.first
end
end
ACCESSORS
self.protected_instance_variables << ivar if self.respond_to?(:protected_instance_variables)
end
end
end
end

View File

@@ -4,8 +4,6 @@ require 'action_mailer/collector'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/proc'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/hash/except'
require 'action_mailer/log_subscriber'
module ActionMailer #:nodoc:
@@ -58,7 +56,7 @@ module ActionMailer #:nodoc:
# will accept (any valid Email header including optional fields).
#
# The mail method, if not passed a block, will inspect your views and send all the views with
# the same name as the method, so the above action would send the +welcome.text.erb+ view
# the same name as the method, so the above action would send the +welcome.text.plain.erb+ view
# file as well as the +welcome.text.html.erb+ view file in a +multipart/alternative+ email.
#
# If you want to explicitly render only certain templates, pass a block:
@@ -89,7 +87,7 @@ module ActionMailer #:nodoc:
#
# To define a template to be used with a mailing, create an <tt>.erb</tt> file with the same
# name as the method in your mailer model. For example, in the mailer defined above, the template at
# <tt>app/views/notifier/welcome.text.erb</tt> would be used to generate the email.
# <tt>app/views/notifier/signup_notification.text.plain.erb</tt> would be used to generate the email.
#
# Variables defined in the model are accessible as instance variables in the view.
#
@@ -101,12 +99,12 @@ module ActionMailer #:nodoc:
# You can even use Action Pack helpers in these views. For example:
#
# You got a new note!
# <%= truncate(@note.body, :length => 25) %>
# <%= truncate(@note.body, 25) %>
#
# If you need to access the subject, from or the recipients in the view, you can do that through message object:
#
# You got a new note from <%= message.from %>!
# <%= truncate(@note.body, :length => 25) %>
# <%= truncate(@note.body, 25) %>
#
#
# = Generating URLs
@@ -123,9 +121,8 @@ module ActionMailer #:nodoc:
#
# <%= users_url(:host => "example.com") %>
#
# You should use the <tt>named_route_url</tt> style (which generates absolute URLs) and avoid using the
# <tt>named_route_path</tt> style (which generates relative URLs), since clients reading the mail will
# have no concept of a current URL from which to determine a relative path.
# You want to avoid using the <tt>name_of_route_path</tt> form of named routes because it doesn't
# make sense to generate relative URLs in email messages.
#
# It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt>
# option as a configuration option in <tt>config/application.rb</tt>:
@@ -153,12 +150,12 @@ module ActionMailer #:nodoc:
#
# = Multipart Emails
#
# Multipart messages can also be used implicitly because Action Mailer will automatically detect and use
# multipart templates, where each template is named after the name of the action, followed by the content
# type. Each such detected template will be added as a separate part to the message.
# Multipart messages can also be used implicitly because Action Mailer will automatically
# detect and use multipart templates, where each template is named after the name of the action, followed
# by the content type. Each such detected template will be added as separate part to the message.
#
# For example, if the following templates exist:
# * signup_notification.text.erb
# * signup_notification.text.plain.erb
# * signup_notification.text.html.erb
# * signup_notification.text.xml.builder
# * signup_notification.text.yaml.erb
@@ -183,7 +180,7 @@ module ActionMailer #:nodoc:
# end
# end
#
# Which will (if it had both a <tt>welcome.text.erb</tt> and <tt>welcome.text.html.erb</tt>
# Which will (if it had both a <tt>welcome.text.plain.erb</tt> and <tt>welcome.text.html.erb</tt>
# template in the view directory), send a complete <tt>multipart/mixed</tt> email with two parts,
# the first part being a <tt>multipart/alternative</tt> with the text and HTML email parts inside,
# and the second being a <tt>application/pdf</tt> with a Base64 encoded copy of the file.pdf book
@@ -225,7 +222,7 @@ module ActionMailer #:nodoc:
#
# An interceptor object must implement the <tt>:delivering_email(message)</tt> method which will be
# called before the email is sent, allowing you to make modifications to the email before it hits
# the delivery agents. Your object should make any needed modifications directly to the passed
# the delivery agents. Your object should make and needed modifications directly to the passed
# in Mail::Message instance.
#
# = Default Hash
@@ -237,8 +234,8 @@ module ActionMailer #:nodoc:
# default :sender => 'system@example.com'
# end
#
# You can pass in any header value that a <tt>Mail::Message</tt> accepts. Out of the box,
# <tt>ActionMailer::Base</tt> sets the following:
# You can pass in any header value that a <tt>Mail::Message</tt>, out of the box, <tt>ActionMailer::Base</tt>
# sets the following:
#
# * <tt>:mime_version => "1.0"</tt>
# * <tt>:charset => "UTF-8",</tt>
@@ -249,7 +246,7 @@ module ActionMailer #:nodoc:
# but Action Mailer translates them appropriately and sets the correct values.
#
# As you can pass in any header, you need to either quote the header as a string, or pass it in as
# an underscored symbol, so the following will work:
# an underscorised symbol, so the following will work:
#
# class Notifier < ActionMailer::Base
# default 'Content-Transfer-Encoding' => '7bit',
@@ -276,7 +273,7 @@ module ActionMailer #:nodoc:
# = Configuration options
#
# These options are specified on the class level, like
# <tt>ActionMailer::Base.raise_delivery_errors = true</tt>
# <tt>ActionMailer::Base.template_root = "/my/templates"</tt>
#
# * <tt>default</tt> - You can pass this in at a class level as well as within the class itself as
# per the above section.
@@ -293,19 +290,13 @@ module ActionMailer #:nodoc:
# * <tt>:password</tt> - If your mail server requires authentication, set the password in this setting.
# * <tt>:authentication</tt> - If your mail server requires authentication, you need to specify the
# authentication type here.
# This is a symbol and one of <tt>:plain</tt> (will send the password in the clear), <tt>:login</tt> (will
# send password Base64 encoded) or <tt>:cram_md5</tt> (combines a Challenge/Response mechanism to exchange
# information and a cryptographic Message Digest 5 algorithm to hash important information)
# This is a symbol and one of <tt>:plain</tt>, <tt>:login</tt>, <tt>:cram_md5</tt>.
# * <tt>:enable_starttls_auto</tt> - When set to true, detects if STARTTLS is enabled in your SMTP server
# and starts to use it.
# * <tt>:openssl_verify_mode</tt> - When using TLS, you can set how OpenSSL checks the certificate. This is
# really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name
# of an OpenSSL verify constant ('none', 'peer', 'client_once','fail_if_no_peer_cert') or directly the
# constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER,...).
#
# * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method.
# * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
# * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i -t</tt> with <tt>-f sender@address</tt>
# * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i -t</tt> with <tt>-f sender@addres</tt>
# added automatically before the message is sent.
#
# * <tt>file_settings</tt> - Allows you to override options for the <tt>:file</tt> delivery method.
@@ -350,10 +341,13 @@ module ActionMailer #:nodoc:
include AbstractController::Translation
include AbstractController::AssetPaths
self.protected_instance_variables = %w(@_action_has_layout)
helper ActionMailer::MailHelper
include ActionMailer::OldApi
include ActionMailer::DeprecatedApi
delegate :register_observer, :to => Mail
delegate :register_interceptor, :to => Mail
private_class_method :new #:nodoc:
@@ -366,31 +360,6 @@ module ActionMailer #:nodoc:
}.freeze
class << self
# Register one or more Observers which will be notified when mail is delivered.
def register_observers(*observers)
observers.flatten.compact.each { |observer| register_observer(observer) }
end
# Register one or more Interceptors which will be called before mail is sent.
def register_interceptors(*interceptors)
interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
end
# Register an Observer which will be notified when mail is delivered.
# Either a class or a string can be passed in as the Observer. If a string is passed in
# it will be <tt>constantize</tt>d.
def register_observer(observer)
delivery_observer = (observer.is_a?(String) ? observer.constantize : observer)
Mail.register_observer(delivery_observer)
end
# Register an Interceptor which will be called before mail is sent.
# Either a class or a string can be passed in as the Interceptor. If a string is passed in
# it will be <tt>constantize</tt>d.
def register_interceptor(interceptor)
delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor)
Mail.register_interceptor(delivery_interceptor)
end
def mailer_name
@mailer_name ||= name.underscore
@@ -433,14 +402,14 @@ module ActionMailer #:nodoc:
end
end
def respond_to?(method, include_private = false) #:nodoc:
def respond_to?(method, *args) #:nodoc:
super || action_methods.include?(method.to_s)
end
protected
def set_payload_for_mail(payload, mail) #:nodoc:
payload[:mailer] = name
payload[:mailer] = self.name
payload[:message_id] = mail.message_id
payload[:subject] = mail.subject
payload[:to] = mail.to
@@ -452,8 +421,11 @@ module ActionMailer #:nodoc:
end
def method_missing(method, *args) #:nodoc:
return super unless respond_to?(method)
new(method, *args).message
if action_methods.include?(method.to_s)
new(method, *args).message
else
super
end
end
end
@@ -474,8 +446,31 @@ module ActionMailer #:nodoc:
super
end
def mailer_name
self.class.mailer_name
class DeprecatedHeaderProxy < ActiveSupport::BasicObject
def initialize(message)
@message = message
end
def []=(key, value)
unless value.is_a?(::String)
::ActiveSupport::Deprecation.warn("Using a non-String object for a header's value is deprecated. " \
"You specified #{value.inspect} (a #{value.class}) for #{key}", caller)
value = value.to_s
end
@message[key] = value
end
def headers(hash = {})
hash.each_pair do |k,v|
self[k] = v
end
end
def method_missing(meth, *args, &block)
@message.send(meth, *args, &block)
end
end
# Allows you to pass random and unusual headers to the new +Mail::Message+ object
@@ -494,9 +489,9 @@ module ActionMailer #:nodoc:
# X-Special-Domain-Specific-Header: SecretValue
def headers(args=nil)
if args
@_message.headers(args)
DeprecatedHeaderProxy.new(@_message).headers(args)
else
@_message
DeprecatedHeaderProxy.new(@_message)
end
end
@@ -686,9 +681,6 @@ module ActionMailer #:nodoc:
end
end
# Translates the +subject+ using Rails I18n class under <tt>[:actionmailer, mailer_scope, action_name]</tt> scope.
# If it does not find a translation for the +subject+ under the specified scope it will default to a
# humanized version of the <tt>action_name</tt>.
def default_i18n_subject #:nodoc:
mailer_scope = self.class.mailer_name.gsub('/', '.')
I18n.t(:subject, :scope => [mailer_scope, action_name], :default => action_name.humanize)
@@ -725,8 +717,15 @@ module ActionMailer #:nodoc:
end
def each_template(paths, name, &block) #:nodoc:
templates = lookup_context.find_all(name, Array.wrap(paths))
templates.uniq_by { |t| t.formats }.each(&block)
Array.wrap(paths).each do |path|
templates = lookup_context.find_all(name, path)
templates = templates.uniq_by { |t| t.formats }
unless templates.empty?
templates.each(&block)
return
end
end
end
def create_parts_from_responses(m, responses) #:nodoc:
@@ -748,6 +747,28 @@ module ActionMailer #:nodoc:
container.add_part(part)
end
module DeprecatedUrlOptions
def default_url_options
deprecated_url_options
end
def default_url_options=(val)
deprecated_url_options
end
def deprecated_url_options
raise "You can no longer call ActionMailer::Base.default_url_options " \
"directly. You need to set config.action_mailer.default_url_options. " \
"If you are using ActionMailer standalone, you need to include the " \
"routing url_helpers directly."
end
end
# This module will complain if the user tries to set default_url_options
# directly instead of through the config object. In Action Mailer's Railtie,
# we include the router's url_helpers, which will override this module.
extend DeprecatedUrlOptions
ActiveSupport.run_load_hooks(:action_mailer, self)
end
end

View File

@@ -1,7 +1,7 @@
require 'tmpdir'
module ActionMailer
# This module handles everything related to mail delivery, from registering new
# This modules handles everything related to the delivery, from registering new
# delivery methods to configuring the mail object to be sent.
module DeliveryMethods
extend ActiveSupport::Concern

View File

@@ -0,0 +1,147 @@
require 'active_support/core_ext/object/try'
module ActionMailer
# This is the API which is deprecated and is going to be removed on Rails 3.1 release.
# Part of the old API will be deprecated after 3.1, for a smoother deprecation process.
# Check those in OldApi instead.
module DeprecatedApi #:nodoc:
extend ActiveSupport::Concern
included do
[:charset, :content_type, :mime_version, :implicit_parts_order].each do |method|
class_eval <<-FILE, __FILE__, __LINE__ + 1
def self.default_#{method}
@@default_#{method}
end
def self.default_#{method}=(value)
ActiveSupport::Deprecation.warn "ActionMailer::Base.default_#{method}=value is deprecated, " <<
"use default :#{method} => value instead"
@@default_#{method} = value
end
@@default_#{method} = nil
FILE
end
end
module ClassMethods
# Deliver the given mail object directly. This can be used to deliver
# a preconstructed mail object, like:
#
# email = MyMailer.create_some_mail(parameters)
# email.set_some_obscure_header "frobnicate"
# MyMailer.deliver(email)
def deliver(mail, show_warning=true)
if show_warning
ActiveSupport::Deprecation.warn "#{self}.deliver is deprecated, call " <<
"deliver in the mailer instance instead", caller[0,2]
end
raise "no mail object available for delivery!" unless mail
wrap_delivery_behavior(mail)
mail.deliver
mail
end
def template_root
self.view_paths && self.view_paths.first
end
def template_root=(root)
ActiveSupport::Deprecation.warn "template_root= is deprecated, use prepend_view_path instead", caller[0,2]
self.view_paths = ActionView::Base.process_view_paths(root)
end
def respond_to?(method_symbol, include_private = false)
matches_dynamic_method?(method_symbol) || super
end
def method_missing(method_symbol, *parameters)
if match = matches_dynamic_method?(method_symbol)
case match[1]
when 'create'
ActiveSupport::Deprecation.warn "#{self}.create_#{match[2]} is deprecated, " <<
"use #{self}.#{match[2]} instead", caller[0,2]
new(match[2], *parameters).message
when 'deliver'
ActiveSupport::Deprecation.warn "#{self}.deliver_#{match[2]} is deprecated, " <<
"use #{self}.#{match[2]}.deliver instead", caller[0,2]
new(match[2], *parameters).message.deliver
else super
end
else
super
end
end
private
def matches_dynamic_method?(method_name)
method_name = method_name.to_s
/^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
end
end
# Delivers a Mail object. By default, it delivers the cached mail
# object (from the <tt>create!</tt> method). If no cached mail object exists, and
# no alternate has been given as the parameter, this will fail.
def deliver!(mail = @_message)
ActiveSupport::Deprecation.warn "Calling deliver in the AM::Base object is deprecated, " <<
"please call deliver in the Mail instance", caller[0,2]
self.class.deliver(mail, false)
end
alias :deliver :deliver!
def render(*args)
options = args.last.is_a?(Hash) ? args.last : {}
if file = options[:file] and !file.index("/")
ActiveSupport::Deprecation.warn("render :file is deprecated except for absolute paths. " \
"Please use render :template instead")
options[:prefix] = _prefix
end
if options[:body].is_a?(Hash)
ActiveSupport::Deprecation.warn(':body in render deprecated. Please use instance ' <<
'variables as assigns instead', caller[0,1])
options[:body].each { |k,v| instance_variable_set(:"@#{k}", v) }
end
super
end
# Render a message but does not set it as mail body. Useful for rendering
# data for part and attachments.
#
# Examples:
#
# render_message "special_message"
# render_message :template => "special_message"
# render_message :inline => "<%= 'Hi!' %>"
#
def render_message(*args)
ActiveSupport::Deprecation.warn "render_message is deprecated, use render instead", caller[0,2]
render(*args)
end
private
def initialize_defaults(*)
@charset ||= self.class.default_charset.try(:dup)
@content_type ||= self.class.default_content_type.try(:dup)
@implicit_parts_order ||= self.class.default_implicit_parts_order.try(:dup)
@mime_version ||= self.class.default_mime_version.try(:dup)
super
end
def create_parts
if @body.is_a?(Hash) && !@body.empty?
ActiveSupport::Deprecation.warn "Giving a hash to body is deprecated, please use instance variables instead", caller[0,2]
@body.each { |k, v| instance_variable_set(:"@#{k}", v) }
end
super
end
end
end

View File

@@ -3,8 +3,17 @@ module ActionMailer
# Uses Text::Format to take the text and format it, indented two spaces for
# each line, and wrapped at 72 columns.
def block_format(text)
begin
require 'text/format'
rescue LoadError => e
$stderr.puts "You don't have text-format installed in your application. Please add it to your Gemfile and run bundle install"
raise e
end unless defined?(Text::Format)
formatted = text.split(/\n\r\n/).collect { |paragraph|
format_paragraph(paragraph)
Text::Format.new(
:columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
).format
}.join("\n")
# Make list points stand on their own line
@@ -28,29 +37,5 @@ module ActionMailer
def attachments
@_message.attachments
end
# Returns +text+ wrapped at +len+ columns and indented +indent+ spaces.
#
# === Examples
#
# my_text = "Here is a sample text with more than 40 characters"
#
# format_paragraph(my_text, 25, 4)
# # => " Here is a sample text with\n more than 40 characters"
def format_paragraph(text, len = 72, indent = 2)
sentences = [[]]
text.split.each do |word|
if (sentences.last + [word]).join(' ').length > len
sentences << [word]
else
sentences.last << word
end
end
sentences.map { |sentence|
"#{" " * indent}#{sentence.join(' ')}"
}.join "\n"
end
end
end

View File

@@ -8,7 +8,9 @@ module ActionMailer
included do
extend ActionMailer::AdvAttrAccessor
self.protected_instance_variables.concat %w(@parts @mail_was_called @headers)
@@protected_instance_variables = %w(@parts)
cattr_reader :protected_instance_variables
# Specify the BCC addresses for the message
adv_attr_accessor :bcc
@@ -40,11 +42,11 @@ module ActionMailer
# The recipient addresses for the message, either as a string (for a single
# address) or an array (for multiple addresses).
adv_attr_accessor :recipients, "Please pass :to as hash key to mail() instead"
adv_attr_accessor :recipients
# The date on which the message was sent. If not set (the default), the
# header will be set by the delivery agent.
adv_attr_accessor :sent_on, "Please pass :date as hash key to mail() instead"
adv_attr_accessor :sent_on
# Specify the subject of the message.
adv_attr_accessor :subject
@@ -52,12 +54,20 @@ module ActionMailer
# Specify the template name to use for current message. This is the "base"
# template name, without the extension or directory, and may be used to
# have multiple mailer methods share the same template.
adv_attr_accessor :template, "Please pass :template_name or :template_path as hash key to mail() instead"
adv_attr_accessor :template
# Override the mailer name, which defaults to an inflected version of the
# mailer's class name. If you want to use a template in a non-standard
# location, you can use this to specify that location.
adv_attr_accessor :mailer_name
# Define the body of the message. This is either a Hash (in which case it
# specifies the variables to pass to the template when it is rendered),
# or a string, in which case it specifies the actual text of the message.
adv_attr_accessor :body
# Alias controller_path to mailer_name so render :partial in views work.
alias :controller_path :mailer_name
end
def process(method_name, *args)
@@ -74,8 +84,6 @@ module ActionMailer
# part itself is yielded to the block so that other properties (charset,
# body, headers, etc.) can be set on it.
def part(params)
ActiveSupport::Deprecation.warn "part() is deprecated and will be removed in future versions. " <<
"Please pass a block to mail() instead."
params = {:content_type => params} if String === params
if custom_headers = params.delete(:headers)
@@ -91,8 +99,6 @@ module ActionMailer
# Add an attachment to a multipart message. This is simply a part with the
# content-disposition set to "attachment".
def attachment(params, &block)
ActiveSupport::Deprecation.warn "attachment() is deprecated and will be removed in future versions. " <<
"Please use the attachments[] API instead."
params = { :content_type => params } if String === params
params[:content] ||= params.delete(:data) || params.delete(:body)
@@ -142,11 +148,11 @@ module ActionMailer
def create_mail
m = @_message
set_fields!({:subject => @subject, :to => @recipients, :from => @from,
:bcc => @bcc, :cc => @cc, :reply_to => @reply_to}, @charset)
set_fields!({:subject => subject, :to => recipients, :from => from,
:bcc => bcc, :cc => cc, :reply_to => reply_to}, charset)
m.mime_version = @mime_version if @mime_version
m.date = @sent_on.to_time rescue @sent_on if @sent_on
m.mime_version = mime_version unless mime_version.nil?
m.date = sent_on.to_time rescue sent_on if sent_on
@headers.each { |k, v| m[k] = v }
@@ -185,8 +191,6 @@ module ActionMailer
@implicit_parts_order ||= self.class.default[:parts_order].try(:dup)
@mime_version ||= self.class.default[:mime_version].try(:dup)
@cc, @bcc, @reply_to, @subject, @from, @recipients = nil, nil, nil, nil, nil, nil
@mailer_name ||= self.class.mailer_name.dup
@template ||= method_name
@mail_was_called = false
@@ -201,7 +205,7 @@ module ActionMailer
if String === @body
@parts.unshift create_inline_part(@body)
elsif @parts.empty? || @parts.all? { |p| p.content_disposition =~ /^attachment/ }
lookup_context.find_all(@template, [@mailer_name]).each do |template|
lookup_context.find_all(@template, @mailer_name).each do |template|
self.formats = template.formats
@parts << create_inline_part(render(:template => template), template.mime_type)
end
@@ -212,7 +216,7 @@ module ActionMailer
# If this is a multipart e-mail add the mime_version if it is not
# already set.
@mime_version ||= "1.0" unless @parts.empty?
@mime_version ||= "1.0" if !@parts.empty?
end
end
@@ -242,13 +246,13 @@ module ActionMailer
ct.to_s.split("/")
end
def parse_content_type
def parse_content_type(defaults=nil)
if @content_type.blank?
[ nil, {} ]
else
ctype, *attrs = @content_type.split(/;\s*/)
attrs = Hash[attrs.map { |attr| attr.split(/=/, 2) }]
[ctype, {"charset" => @charset}.merge!(attrs)]
attrs = attrs.inject({}) { |h,s| k,v = s.split(/\=/, 2); h[k] = v; h }
[ctype, {"charset" => @charset}.merge(attrs)]
end
end
end

View File

@@ -1,6 +1,5 @@
require "action_mailer"
require "rails"
require "abstract_controller/railties/routes_helpers"
module ActionMailer
class Railtie < Rails::Railtie
@@ -14,30 +13,14 @@ module ActionMailer
paths = app.config.paths
options = app.config.action_mailer
options.assets_dir ||= paths["public"].first
options.javascripts_dir ||= paths["public/javascripts"].first
options.stylesheets_dir ||= paths["public/stylesheets"].first
# make sure readers methods get compiled
options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.assets_dir ||= paths.public.to_a.first
options.javascripts_dir ||= paths.public.javascripts.to_a.first
options.stylesheets_dir ||= paths.public.stylesheets.to_a.first
ActiveSupport.on_load(:action_mailer) do
include AbstractController::UrlFor
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
include app.routes.mounted_helpers
register_interceptors(options.delete(:interceptors))
register_observers(options.delete(:observers))
include app.routes.url_helpers
options.each { |k,v| send("#{k}=", v) }
end
end
initializer "action_mailer.compile_config_methods" do
ActiveSupport.on_load(:action_mailer) do
config.compile_methods! if config.respond_to?(:compile_methods!)
end
end
end
end
end

View File

@@ -1,5 +1,3 @@
require 'active_support/core_ext/class/attribute'
module ActionMailer
class NonInferrableMailerError < ::StandardError
def initialize(name)
@@ -17,11 +15,11 @@ module ActionMailer
module ClassMethods
def tests(mailer)
self._mailer_class = mailer
write_inheritable_attribute(:mailer_class, mailer)
end
def mailer_class
if mailer = self._mailer_class
if mailer = read_inheritable_attribute(:mailer_class)
mailer
else
tests determine_default_mailer(name)
@@ -67,7 +65,6 @@ module ActionMailer
end
included do
class_attribute :_mailer_class
setup :initialize_test_deliveries
setup :set_expected_mail
end

View File

@@ -2,18 +2,16 @@ module Mail
class Message
def set_content_type(*args)
message = 'Message#set_content_type is deprecated, please just call ' <<
'Message#content_type with the same arguments'
ActiveSupport::Deprecation.warn(message, caller[0,2])
ActiveSupport::Deprecation.warn('Message#set_content_type is deprecated, please just call ' <<
'Message#content_type with the same arguments', caller[0,2])
content_type(*args)
end
alias :old_transfer_encoding :transfer_encoding
def transfer_encoding(value = nil)
if value
message = 'Message#transfer_encoding is deprecated, ' <<
'please call Message#content_transfer_encoding with the same arguments'
ActiveSupport::Deprecation.warn(message, caller[0,2])
ActiveSupport::Deprecation.warn('Message#transfer_encoding is deprecated, please call ' <<
'Message#content_transfer_encoding with the same arguments', caller[0,2])
content_transfer_encoding(value)
else
old_transfer_encoding
@@ -21,17 +19,16 @@ module Mail
end
def transfer_encoding=(value)
message = 'Message#transfer_encoding= is deprecated, ' <<
'please call Message#content_transfer_encoding= with the same arguments'
ActiveSupport::Deprecation.warn(message, caller[0,2])
ActiveSupport::Deprecation.warn('Message#transfer_encoding= is deprecated, please call ' <<
'Message#content_transfer_encoding= with the same arguments', caller[0,2])
self.content_transfer_encoding = value
end
def original_filename
message = 'Message#original_filename is deprecated, please call Message#filename'
ActiveSupport::Deprecation.warn(message, caller[0,2])
ActiveSupport::Deprecation.warn('Message#original_filename is deprecated, ' <<
'please call Message#filename', caller[0,2])
filename
end
end
end
end

View File

@@ -1,10 +1,9 @@
module ActionMailer
module VERSION #:nodoc:
MAJOR = 3
MINOR = 1
TINY = 8
PRE = nil
MINOR = 0
TINY = 0
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
STRING = [MAJOR, MINOR, TINY].join('.')
end
end

View File

@@ -1,5 +1,4 @@
Description:
============
Stubs out a new mailer and its views. Pass the mailer name, either
CamelCased or under_scored, and an optional list of emails as arguments.
@@ -7,12 +6,10 @@ Description:
engine and test framework generators.
Example:
========
rails generate mailer Notifications signup forgot_password invoice
`rails generate mailer Notifications signup forgot_password invoice`
creates a Notifications mailer class, views, test, and fixtures:
Mailer: app/mailers/notifications.rb
Views: app/views/notifications/signup.erb [...]
Test: test/functional/notifications_test.rb
Fixtures: test/fixtures/notifications/signup [...]

View File

@@ -1,18 +1,16 @@
<% module_namespacing do -%>
class <%= class_name %> < ActionMailer::Base
default <%= key_value :from, '"from@example.com"' %>
<% actions.each do |action| -%>
default :from => "from@example.com"
<% for action in actions -%>
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.<%= file_path.gsub("/",".") %>.<%= action %>.subject
# en.<%= file_name %>.<%= action %>.subject
#
def <%= action %>
@greeting = "Hi"
mail <%= key_value :to, '"to@example.org"' %>
mail :to => "to@example.org"
end
<% end -%>
end
<% end -%>

View File

@@ -23,6 +23,12 @@ if "ruby".encoding_aware?
end
end
silence_warnings do
# These external dependencies have warnings :/
require 'text/format'
require 'mail'
end
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
@@ -30,11 +36,6 @@ require 'test/unit'
require 'action_mailer'
require 'action_mailer/test_case'
silence_warnings do
# These external dependencies have warnings :/
require 'mail'
end
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
@@ -77,5 +78,3 @@ end
def restore_delivery_method
ActionMailer::Base.delivery_method = @old_delivery_method
end
ActiveSupport::Deprecation.silenced = true

View File

@@ -7,6 +7,9 @@ require 'mailers/proc_mailer'
require 'mailers/asset_mailer'
class BaseTest < ActiveSupport::TestCase
# TODO Add some tests for implicity layout render and url helpers
# so we can get rid of old base tests altogether with old base.
def teardown
ActionMailer::Base.asset_host = nil
ActionMailer::Base.assets_dir = nil
@@ -32,21 +35,21 @@ class BaseTest < ActiveSupport::TestCase
end
test "mail() with bcc, cc, content_type, charset, mime_version, reply_to and date" do
time = Time.now.beginning_of_day.to_datetime
@time = Time.now.beginning_of_day.to_datetime
email = BaseMailer.welcome(:bcc => 'bcc@test.lindsaar.net',
:cc => 'cc@test.lindsaar.net',
:content_type => 'multipart/mixed',
:charset => 'iso-8559-1',
:mime_version => '2.0',
:reply_to => 'reply-to@test.lindsaar.net',
:date => time)
:date => @time)
assert_equal(['bcc@test.lindsaar.net'], email.bcc)
assert_equal(['cc@test.lindsaar.net'], email.cc)
assert_equal('multipart/mixed; charset=iso-8559-1', email.content_type)
assert_equal('iso-8559-1', email.charset)
assert_equal('2.0', email.mime_version)
assert_equal(['reply-to@test.lindsaar.net'], email.reply_to)
assert_equal(time, email.date)
assert_equal(@time, email.date)
end
test "mail() renders the template using the method being processed" do
@@ -73,6 +76,11 @@ class BaseTest < ActiveSupport::TestCase
assert_equal("Not SPAM", email['X-SPAM'].decoded)
end
test "deprecated non-String custom headers" do
email = assert_deprecated { BaseMailer.welcome_with_fixnum_header }
assert_equal("2", email['X-SPAM-COUNT'].decoded)
end
test "can pass random headers in as a hash to mail" do
hash = {'X-Special-Domain-Specific-Header' => "SecretValue",
'In-Reply-To' => '1234@mikel.me.com' }
@@ -153,8 +161,8 @@ class BaseTest < ActiveSupport::TestCase
assert_equal(2, email.parts.length)
assert_equal("multipart/related", email.mime_type)
assert_equal("multipart/alternative", email.parts[0].mime_type)
assert_equal("text/plain", email.parts[0].parts[0].mime_type)
assert_equal("text/html", email.parts[0].parts[1].mime_type)
assert_equal("text/plain", email.parts[0].parts[0].mime_type)
assert_equal("text/html", email.parts[0].parts[1].mime_type)
assert_equal("logo.png", email.parts[1].filename)
end
@@ -431,6 +439,13 @@ class BaseTest < ActiveSupport::TestCase
assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded)
end
test "render :file uses render :template semantics and is deprecated" do
mail = nil
assert_deprecated { mail = BaseMailer.implicit_different_template_with_file('implicit_multipart').deliver }
assert_equal("HTML Implicit Multipart", mail.html_part.body.decoded)
assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded)
end
test "you can specify a different template for explicit render" do
mail = BaseMailer.explicit_different_template('explicit_multipart_templates').deliver
assert_equal("HTML Explicit Multipart Templates", mail.html_part.body.decoded)
@@ -478,11 +493,6 @@ class BaseTest < ActiveSupport::TestCase
end
end
class MySecondObserver
def self.delivered_email(mail)
end
end
test "you can register an observer to the mail object that gets informed on email delivery" do
ActionMailer::Base.register_observer(MyObserver)
mail = BaseMailer.welcome
@@ -490,31 +500,11 @@ class BaseTest < ActiveSupport::TestCase
mail.deliver
end
test "you can register an observer using its stringified name to the mail object that gets informed on email delivery" do
ActionMailer::Base.register_observer("BaseTest::MyObserver")
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
mail.deliver
end
test "you can register multiple observers to the mail object that both get informed on email delivery" do
ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver)
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
MySecondObserver.expects(:delivered_email).with(mail)
mail.deliver
end
class MyInterceptor
def self.delivering_email(mail)
end
end
class MySecondInterceptor
def self.delivering_email(mail)
end
end
test "you can register an interceptor to the mail object that gets passed the mail object before delivery" do
ActionMailer::Base.register_interceptor(MyInterceptor)
mail = BaseMailer.welcome
@@ -522,21 +512,6 @@ class BaseTest < ActiveSupport::TestCase
mail.deliver
end
test "you can register an interceptor using its stringified name to the mail object that gets passed the mail object before delivery" do
ActionMailer::Base.register_interceptor("BaseTest::MyInterceptor")
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end
test "you can register multiple interceptors to the mail object that both get passed the mail object before delivery" do
ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor)
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
MySecondInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end
test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do
mail1 = ProcMailer.welcome
yesterday = 1.day.ago

View File

@@ -1,4 +0,0 @@
Hello there,
Mr. <%= @recipient %>. Be greeted, new member!

View File

@@ -1,46 +0,0 @@
require 'abstract_unit'
require 'action_controller'
class I18nTestMailer < ActionMailer::Base
configure do |c|
c.assets_dir = ''
end
def mail_with_i18n_subject(recipient)
@recipient = recipient
I18n.locale = :de
mail(:to => recipient, :subject => "#{I18n.t :email_subject} #{recipient}",
:from => "system@loudthinking.com", :date => Time.local(2004, 12, 12))
end
end
class TestController < ActionController::Base
def send_mail
I18nTestMailer.mail_with_i18n_subject("test@localhost").deliver
render :text => 'Mail sent'
end
end
class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new
Routes.draw do
match ':controller(/:action(/:id))'
end
def app
Routes
end
def setup
I18n.backend.store_translations('de', :email_subject => '[Signed up] Welcome')
end
def teardown
I18n.locale = :en
end
def test_send_mail
get '/test/send_mail'
assert_equal "Mail sent", @response.body
end
end

View File

@@ -14,14 +14,6 @@ class HelperMailer < ActionMailer::Base
end
end
def use_format_paragraph
@text = "But soft! What light through yonder window breaks?"
mail_with_defaults do |format|
format.html { render(:inline => "<%= format_paragraph @text, 15, 1 %>") }
end
end
def use_mailer
mail_with_defaults do |format|
format.html { render(:inline => "<%= mailer.message.subject %>") }
@@ -58,10 +50,5 @@ class MailerHelperTest < ActionMailer::TestCase
mail = HelperMailer.use_message
assert_match "using helpers", mail.body.encoded
end
def test_use_format_paragraph
mail = HelperMailer.use_format_paragraph
assert_match " But soft! What\r\n light through\r\n yonder window\r\n breaks?", mail.body.encoded
end
end

View File

@@ -10,6 +10,11 @@ class BaseMailer < ActionMailer::Base
mail({:subject => "The first email on new API!"}.merge!(hash))
end
def welcome_with_fixnum_header(hash = {})
headers['X-SPAM-COUNT'] = 2
mail({:template_name => "welcome", :subject => "The first email on new API!"}.merge!(hash))
end
def welcome_with_headers(hash = {})
headers hash
mail
@@ -98,6 +103,13 @@ class BaseMailer < ActionMailer::Base
mail(:template_name => template_name)
end
def implicit_different_template_with_file(template_name='')
mail do |format|
format.text { render :file => template_name }
format.html { render :file => template_name }
end
end
def explicit_different_template(template_name='')
mail do |format|
format.text { render :template => "#{mailer_name}/#{template_name}" }
@@ -113,6 +125,6 @@ class BaseMailer < ActionMailer::Base
end
def email_with_translations
mail :body => render("email_with_translations.html")
body render("email_with_translations.html")
end
end

View File

@@ -11,14 +11,9 @@ class AdvAttrTest < ActiveSupport::TestCase
end
def setup
ActiveSupport::Deprecation.silenced = true
@person = Person.new
end
def teardown
ActiveSupport::Deprecation.silenced = false
end
def test_adv_attr
assert_nil @person.name
@person.name 'Bob'

View File

@@ -3,9 +3,9 @@ require 'action_controller'
class AssetHostMailer < ActionMailer::Base
def email_with_asset
mail :to => 'test@localhost',
:subject => 'testing email containing asset path while asset_host is set',
:from => 'tester@example.com'
recipients 'test@localhost'
subject "testing email containing asset path while asset_host is set"
from "tester@example.com"
end
end
@@ -29,7 +29,7 @@ class AssetHostTest < Test::Unit::TestCase
assert_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
def test_asset_host_as_one_argument_proc
def test_asset_host_as_one_arguement_proc
AssetHostMailer.config.asset_host = Proc.new { |source|
if source.starts_with?('/images')
"http://images.example.com"
@@ -41,7 +41,7 @@ class AssetHostTest < Test::Unit::TestCase
assert_equal %Q{<img alt="Somelogo" src="http://images.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
def test_asset_host_as_two_argument_proc
def test_asset_host_as_two_arguement_proc
ActionController::Base.config.asset_host = Proc.new {|source,request|
if request && request.ssl?
"https://www.example.com"

View File

@@ -1,45 +1,53 @@
require 'abstract_unit'
class AutoLayoutMailer < ActionMailer::Base
default :to => 'test@localhost',
:subject => "You have a mail",
:from => "tester@example.com"
def hello
mail()
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
end
def spam
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
@world = "Earth"
mail(:body => render(:inline => "Hello, <%= @world %>", :layout => 'spam'))
body render(:inline => "Hello, <%= @world %>", :layout => 'spam')
end
def nolayout
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
@world = "Earth"
mail(:body => render(:inline => "Hello, <%= @world %>", :layout => false))
body render(:inline => "Hello, <%= @world %>", :layout => false)
end
def multipart(type = nil)
mail(:content_type => type) do |format|
format.text { render }
format.html { render }
end
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
content_type(type) if type
end
end
class ExplicitLayoutMailer < ActionMailer::Base
layout 'spam', :except => [:logout]
default :to => 'test@localhost',
:subject => "You have a mail",
:from => "tester@example.com"
def signup
mail()
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
end
def logout
mail()
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
end
end
@@ -83,6 +91,19 @@ class LayoutMailerTest < Test::Unit::TestCase
assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s
end
def test_should_fix_multipart_layout
mail = AutoLayoutMailer.multipart("text/plain")
assert_equal "multipart/alternative", mail.mime_type
assert_equal 2, mail.parts.size
assert_equal 'text/plain', mail.parts.first.mime_type
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s
assert_equal 'text/html', mail.parts.last.mime_type
assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s
end
def test_should_pickup_layout_given_to_render
mail = AutoLayoutMailer.spam
assert_equal "Spammer layout Hello, Earth", mail.body.to_s.strip

View File

@@ -19,6 +19,18 @@ class RenderMailer < ActionMailer::Base
body render(:file => "templates/signed_up")
end
def rxml_template
recipients 'test@localhost'
subject "rendering rxml template"
from "tester@example.com"
end
def included_subtemplate
recipients 'test@localhost'
subject "Including another template in the one being rendered"
from "tester@example.com"
end
def no_instance_variable
recipients 'test@localhost'
subject "No Instance Variable"
@@ -29,6 +41,11 @@ class RenderMailer < ActionMailer::Base
end
end
def initialize_defaults(method_name)
super
mailer_name "test_mailer"
end
def multipart_alternative
recipients 'test@localhost'
subject 'multipart/alternative'
@@ -80,13 +97,11 @@ class RenderHelperTest < Test::Unit::TestCase
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries.clear
ActiveSupport::Deprecation.silenced = true
@recipient = 'test@localhost'
end
def teardown
ActiveSupport::Deprecation.silenced = false
restore_delivery_method
end
@@ -100,16 +115,35 @@ class RenderHelperTest < Test::Unit::TestCase
assert_equal "Hello there,\n\nMr. test@localhost", mail.body.to_s.strip
end
def test_rxml_template
mail = RenderMailer.rxml_template.deliver
assert_equal %(<?xml version="1.0" encoding="UTF-8"?>\n<test/>), mail.body.to_s.strip
end
def test_included_subtemplate
mail = RenderMailer.included_subtemplate.deliver
assert_equal "Hey Ho, let's go!", mail.body.to_s.strip
end
def test_no_instance_variable
mail = RenderMailer.no_instance_variable.deliver
assert_equal "Look, subject.nil? is true!", mail.body.to_s.strip
end
def test_legacy_multipart_alternative
mail = RenderMailer.multipart_alternative.deliver
assert_equal(2, mail.parts.size)
assert_equal("multipart/alternative", mail.mime_type)
assert_equal("text/plain", mail.parts[0].mime_type)
assert_equal("foo: bar", mail.parts[0].body.encoded)
assert_equal("text/html", mail.parts[1].mime_type)
assert_equal("<strong>foo</strong> bar", mail.parts[1].body.encoded)
end
end
class FirstSecondHelperTest < Test::Unit::TestCase
def setup
set_delivery_method :test
ActiveSupport::Deprecation.silenced = true
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries.clear
@@ -117,7 +151,6 @@ class FirstSecondHelperTest < Test::Unit::TestCase
end
def teardown
ActiveSupport::Deprecation.silenced = false
restore_delivery_method
end

View File

@@ -328,20 +328,21 @@ class ActionMailerTest < Test::Unit::TestCase
mail
end
# Replacing logger work around for mocha bug. Should be fixed in mocha 0.3.3
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.deliveries.clear
ActiveSupport::Deprecation.silenced = true
@original_logger = TestMailer.logger
@recipient = 'test@localhost'
TestMailer.delivery_method = :test
end
def teardown
ActiveSupport::Deprecation.silenced = false
TestMailer.logger = @original_logger
restore_delivery_method
end
@@ -514,8 +515,7 @@ class ActionMailerTest < Test::Unit::TestCase
assert_not_nil mail
mail, from, to = mail
assert_equal ['root@loudthinking.com'], to
assert_equal 'system@loudthinking.com', from
assert_equal 'system@loudthinking.com', from.to_s
end
def test_from_with_name_for_smtp
@@ -526,7 +526,6 @@ class ActionMailerTest < Test::Unit::TestCase
assert_not_nil mail
mail, from, to = mail
assert_equal ['root@loudthinking.com'], to
assert_equal 'system@loudthinking.com', from
end
@@ -981,7 +980,7 @@ EOF
TestMailer.delivery_method = :file
tmp_location = TestMailer.file_settings[:location]
TestMailer.cc_bcc(@recipient).deliver
result = TestMailer.cc_bcc(@recipient).deliver
assert File.exists?(tmp_location)
assert File.directory?(tmp_location)
assert File.exists?(File.join(tmp_location, @recipient))
@@ -1097,3 +1096,111 @@ EOF
TestMailer.smtp_settings.merge!(:enable_starttls_auto => true)
end
end
class InheritableTemplateRootTest < ActiveSupport::TestCase
def test_attr
expected = File.expand_path("#{File.dirname(__FILE__)}/../fixtures/path.with.dots")
assert_equal expected, FunkyPathMailer.template_root.to_s
sub = Class.new(FunkyPathMailer)
assert_deprecated do
sub.template_root = 'test/path'
end
assert_equal File.expand_path('test/path'), sub.template_root.to_s
assert_equal expected, FunkyPathMailer.template_root.to_s
end
end
class MethodNamingTest < ActiveSupport::TestCase
include ActionMailer::TestHelper
class TestMailer < ActionMailer::Base
def send
body 'foo'
end
end
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries.clear
end
def teardown
restore_delivery_method
end
def test_send_method
assert_nothing_raised do
assert_emails 1 do
assert_deprecated do
TestMailer.deliver_send
end
end
end
end
end
class RespondToTest < Test::Unit::TestCase
class RespondToMailer < ActionMailer::Base; end
def setup
set_delivery_method :test
end
def teardown
restore_delivery_method
end
def test_should_respond_to_new
assert_respond_to RespondToMailer, :new
end
def test_should_respond_to_create_with_template_suffix
assert_respond_to RespondToMailer, :create_any_old_template
end
def test_should_respond_to_deliver_with_template_suffix
assert_respond_to RespondToMailer, :deliver_any_old_template
end
def test_should_not_respond_to_new_with_template_suffix
assert !RespondToMailer.respond_to?(:new_any_old_template)
end
def test_should_not_respond_to_create_with_template_suffix_unless_it_is_separated_by_an_underscore
assert !RespondToMailer.respond_to?(:createany_old_template)
end
def test_should_not_respond_to_deliver_with_template_suffix_unless_it_is_separated_by_an_underscore
assert !RespondToMailer.respond_to?(:deliverany_old_template)
end
def test_should_not_respond_to_create_with_template_suffix_if_it_begins_with_a_uppercase_letter
assert !RespondToMailer.respond_to?(:create_Any_old_template)
end
def test_should_not_respond_to_deliver_with_template_suffix_if_it_begins_with_a_uppercase_letter
assert !RespondToMailer.respond_to?(:deliver_Any_old_template)
end
def test_should_not_respond_to_create_with_template_suffix_if_it_begins_with_a_digit
assert !RespondToMailer.respond_to?(:create_1_template)
end
def test_should_not_respond_to_deliver_with_template_suffix_if_it_begins_with_a_digit
assert !RespondToMailer.respond_to?(:deliver_1_template)
end
def test_should_not_respond_to_method_where_deliver_is_not_a_suffix
assert !RespondToMailer.respond_to?(:foo_deliver_template)
end
def test_should_still_raise_exception_with_expected_message_when_calling_an_undefined_method
error = assert_raise NoMethodError do
RespondToMailer.not_a_method
end
assert_match(/method.*not_a_method/, error.message)
end
end

View File

@@ -1,14 +1,6 @@
require 'abstract_unit'
class TmailCompatTest < ActiveSupport::TestCase
def setup
@silence = ActiveSupport::Deprecation.silenced
ActiveSupport::Deprecation.silenced = false
end
def teardown
ActiveSupport::Deprecation.silenced = @silence
end
def test_set_content_type_raises_deprecation_warning
mail = Mail.new
@@ -39,4 +31,5 @@ class TmailCompatTest < ActiveSupport::TestCase
end
assert_equal mail.content_transfer_encoding, "base64"
end
end

View File

@@ -18,10 +18,13 @@ class UrlTestMailer < ActionMailer::Base
end
def signed_up_with_url(recipient)
@recipients = recipient
@subject = "[Signed up] Welcome #{recipient}"
@from = "system@loudthinking.com"
@sent_on = Time.local(2004, 12, 12)
@recipient = recipient
@welcome_url = url_for :host => "example.com", :controller => "welcome", :action => "greeting"
mail(:to => recipient, :subject => "[Signed up] Welcome #{recipient}",
:from => "system@loudthinking.com", :date => Time.local(2004, 12, 12))
end
end
@@ -44,7 +47,6 @@ class ActionMailerUrlTest < ActionMailer::TestCase
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries.clear
ActiveSupport::Deprecation.silenced = false
@recipient = 'test@localhost'
end
@@ -56,9 +58,11 @@ class ActionMailerUrlTest < ActionMailer::TestCase
def test_signed_up_with_url
UrlTestMailer.delivery_method = :test
AppRoutes.draw do
match ':controller(/:action(/:id))'
match '/welcome' => "foo#bar", :as => "welcome"
assert_deprecated do
AppRoutes.draw do |map|
map.connect ':controller/:action/:id'
map.welcome 'welcome', :controller=>"foo", :action=>"bar"
end
end
expected = new_mail
@@ -67,7 +71,6 @@ class ActionMailerUrlTest < ActionMailer::TestCase
expected.body = "Hello there,\n\nMr. #{@recipient}. Please see our greeting at http://example.com/welcome/greeting http://www.basecamphq.com/welcome\n\n<img alt=\"Somelogo\" src=\"/images/somelogo.png\" />"
expected.from = "system@loudthinking.com"
expected.date = Time.local(2004, 12, 12)
expected.content_type = "text/html"
created = nil
assert_nothing_raised { created = UrlTestMailer.signed_up_with_url(@recipient) }

View File

@@ -2,10 +2,11 @@ require 'abstract_unit'
class TestHelperMailer < ActionMailer::Base
def test
recipients "test@example.com"
from "tester@example.com"
@world = "Earth"
mail :body => render(:inline => "Hello, <%= @world %>"),
:to => "test@example.com",
:from => "tester@example.com"
render(:inline => "Hello, <%= @world %>")
end
end

5319
actionpack/CHANGELOG Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,390 +0,0 @@
## Rails 3.1.8 (Aug 9, 2012)
* There is an XSS vulnerability in the strip_tags helper in Ruby on Rails, the
helper doesn't correctly handle malformed html. As a result an attacker can
execute arbitrary javascript through the use of specially crafted malformed
html.
*Marek from Nethemba (www.nethemba.com) & Santiago Pastorino*
* When a "prompt" value is supplied to the `select_tag` helper, the "prompt" value is not escaped.
If untrusted data is not escaped, and is supplied as the prompt value, there is a potential for XSS attacks.
Vulnerable code will look something like this:
select_tag("name", options, :prompt => UNTRUSTED_INPUT)
*Santiago Pastorino*
## Rails 3.1.7 (Jul 26, 2012)
* Do not convert digest auth strings to symbols. CVE-2012-3424
## Rails 3.1.6 (Jun 12, 2012)
* nil is removed from array parameter values
CVE-2012-2694
## Rails 3.1.5 (May 31, 2012) ##
* Detect optional glob params when adding non-greedy regexp - closes #4817.
* Strip null bytes from Location header
* Return the same session data object when setting session id
* Avoid inspecting the whole route set, closes #1525
* Strip [nil] from parameters hash. Thanks to Ben Murphy for reporting this!
CVE-2012-2660
## Rails 3.1.4 (unreleased) ##
* :subdomain can now be specified with a value of false in url_for,
allowing for subdomain(s) removal from the host during link generation. GH #4083
*Arun Agrawal*
* Skip assets group in Gemfile and all assets configurations options
when the application is generated with --skip-sprockets option.
*Guillermo Iguaran*
* Use ProcessedAsset#pathname in Sprockets helpers when debugging is on. Closes #3333 #3348 #3361.
*Guillermo Iguaran*
* Allow to use asset_path on named_routes aliasing RailsHelper's
asset_path to path_to_asset *Adrian Pike*
* Assets should use the request protocol by default or default to relative if no request is available *Jonathan del Strother*
## Rails 3.1.3 (November 20, 2011) ##
* Downgrade sprockets to ~> 2.0.3. Using 2.1.0 caused regressions.
* Fix using `tranlate` helper with a html translation which uses the `:count` option for
pluralization.
*Jon Leighton*
## Rails 3.1.2 (November 18, 2011) ##
* Fix XSS security vulnerability in the `translate` helper method. When using interpolation
in combination with HTML-safe translations, the interpolated input would not get HTML
escaped. *GH 3664*
Before:
translate('foo_html', :something => '<script>') # => "...<script>..."
After:
translate('foo_html', :something => '<script>') # => "...&lt;script&gt;..."
*Sergey Nartimov*
* Upgrade sprockets dependency to ~> 2.1.0
* Ensure that the format isn't applied twice to the cache key, else it becomes impossible
to target with expire_action.
*Christopher Meiklejohn*
* Swallow error when can't unmarshall object from session.
*Bruno Zanchet*
* Implement a workaround for a bug in ruby-1.9.3p0 where an error would be raised
while attempting to convert a template from one encoding to another.
Please see http://redmine.ruby-lang.org/issues/5564 for details of the bug.
The workaround is to load all conversions into memory ahead of time, and will
only happen if the ruby version is *exactly* 1.9.3p0. The hope is obviously that
the underlying problem will be resolved in the next patchlevel release of
1.9.3.
*Jon Leighton*
* Ensure users upgrading from 3.0.x to 3.1.x will properly upgrade their flash object in session (issues #3298 and #2509)
## Rails 3.1.1 (October 7, 2011) ##
* stylesheet_link_tag('/stylesheets/application') and similar helpers doesn't
throw Sprockets::FileOutsidePaths exception anymore *Santiago Pastorino*
* Ensure default_asset_host_protocol is respected, closes #2980. *José Valim*
Changing rake db:schema:dump to run :environment as well as :load_config,
as running :load_config alone will lead to the dumper being run without
including extensions such as those included in foreigner and
spatial_adapter.
This reverses a change made here:
https://github.com/rails/rails/commit/5df72a238e9fcb18daf6ab6e6dc9051c9106d7bb#L0L324
I'm assuming here that :load_config needs to be invoked
separately from :environment, as it is elsewhere in the
file for db operations, if not the alternative is to go
back to "task :dump => :environment do".
*Ben Woosley*
* Update to rack-cache 1.1.
Versions prior to 1.1 delete the If-Modified-Since and If-Not-Modified
headers when config.action_controller.perform_caching is true. This has two
problems:
* unexpected inconsistent behaviour between development &
production environments
* breaks applications that use of these headers
*Brendan Ribera*
* Ensure that enhancements to assets:precompile task are only run once *Sam Pohlenz*
* TestCase should respect the view_assigns API instead of pulling variables on
its own. *José Valim*
* javascript_path and stylesheet_path now refer to /assets if asset pipelining
is on. *Santiago Pastorino*
* button_to support form option. Now you're able to pass for example
'data-type' => 'json'. *ihower*
* image_path and image_tag should use /assets if asset pipelining is turned
on. Closes #3126 *Santiago Pastorino and christos*
* Avoid use of existing precompiled assets during rake assets:precompile run.
Closes #3119 *Guillermo Iguaran*
* Copy assets to nondigested filenames too *Santiago Pastorino*
* Give precedence to `config.digest = false` over the existence of
manifest.yml asset digests *christos*
* escape options for the stylesheet_link_tag method *Alexey Vakhov*
* Re-launch assets:precompile task using (Rake.)ruby instead of Kernel.exec so
it works on Windows *cablegram*
* env var passed to process shouldn't be modified in process method. [Santiago
Pastorino]
* `rake assets:precompile` loads the application but does not initialize
it.
To the app developer, this means configuration add in
config/initializers/* will not be executed.
Plugins developers need to special case their initializers that are
meant to be run in the assets group by adding :group => :assets. *José Valim*
* Sprockets uses config.assets.prefix for asset_path *asee*
* FileStore key_file_path properly limit filenames to 255 characters. *phuibonhoa*
* Fix Hash#to_query edge case with html_safe strings. *brainopia*
* Allow asset tag helper methods to accept :digest => false option in order to completely avoid the digest generation.
Useful for linking assets from static html files or from emails when the user
could probably look at an older html email with an older asset. *Santiago Pastorino*
* Don't mount Sprockets server at config.assets.prefix if config.assets.compile is false. *Mark J. Titorenko*
* Set relative url root in assets when controller isn't available for Sprockets (eg. Sass files using asset_path). Fixes #2435 *Guillermo Iguaran*
* Fix basic auth credential generation to not make newlines. GH #2882
* Fixed the behavior of asset pipeline when config.assets.digest and config.assets.compile are false and requested asset isn't precompiled.
Before the requested asset were compiled anyway ignoring that the config.assets.compile flag is false. *Guillermo Iguaran*
* CookieJar is now Enumerable. Fixes #2795
* Fixed AssetNotPrecompiled error raised when rake assets:precompile is compiling certain .erb files. See GH #2763 #2765 #2805 *Guillermo Iguaran*
* Manifest is correctly placed in assets path when default assets prefix is changed. Fixes #2776 *Guillermo Iguaran*
* Fixed stylesheet_link_tag and javascript_include_tag to respect additional options passed by the users when debug is on. *Guillermo Iguaran*
* Fix ActiveRecord#exists? when passsed a nil value
* Fix assert_select_email to work on multipart and non-multipart emails as the method stopped working correctly in Rails 3.x due to changes in the new mail gem.
## Rails 3.1.0 (August 30, 2011) ##
* Param values are `paramified` in controller tests. *David Chelimsky*
* x_sendfile_header now defaults to nil and config/environments/production.rb doesn't set a particular value for it. This allows servers to set it through X-Sendfile-Type. *Santiago Pastorino*
* The submit form helper does not generate an id "object_name_id" anymore. *fbrusatti*
* Make sure respond_with with :js tries to render a template in all cases *José Valim*
* json_escape will now return a SafeBuffer string if it receives SafeBuffer string *tenderlove*
* Make sure escape_js returns SafeBuffer string if it receives SafeBuffer string *Prem Sichanugrist*
* Fix escape_js to work correctly with the new SafeBuffer restriction *Paul Gallagher*
* Brought back alternative convention for namespaced models in i18n *thoefer*
Now the key can be either "namespace.model" or "namespace/model" until further deprecation.
* It is prohibited to perform a in-place SafeBuffer mutation *tenderlove*
The old behavior of SafeBuffer allowed you to mutate string in place via
method like `sub!`. These methods can add unsafe strings to a safe buffer,
and the safe buffer will continue to be marked as safe.
An example problem would be something like this:
<%= link_to('hello world', @user).sub!(/hello/, params[:xss]) %>
In the above example, an untrusted string (`params[:xss]`) is added to the
safe buffer returned by `link_to`, and the untrusted content is successfully
sent to the client without being escaped. To prevent this from happening
`sub!` and other similar methods will now raise an exception when they are called on a safe buffer.
In addition to the in-place versions, some of the versions of these methods which return a copy of the string will incorrectly mark strings as safe. For example:
<%= link_to('hello world', @user).sub(/hello/, params[:xss]) %>
The new versions will now ensure that *all* strings returned by these methods on safe buffers are marked unsafe.
You can read more about this change in http://groups.google.com/group/rubyonrails-security/browse_thread/thread/2e516e7acc96c4fb
* Warn if we cannot verify CSRF token authenticity *José Valim*
* Allow AM/PM format in datetime selectors *Aditya Sanghi*
* Only show dump of regular env methods on exception screen (not all the rack crap) *DHH*
* auto_link has been removed with no replacement. If you still use auto_link
please install the rails_autolink gem:
http://github.com/tenderlove/rails_autolink
*tenderlove*
* Added streaming support, you can enable it with: *José Valim*
class PostsController < ActionController::Base
stream :only => :index
end
Please read the docs at `ActionController::Streaming` for more information.
* Added `ActionDispatch::Request.ignore_accept_header` to ignore accept headers and only consider the format given as parameter *José Valim*
* Created `ActionView::Renderer` and specified an API for `ActionView::Context`, check those objects for more information *José Valim*
* Added `ActionController::ParamsWrapper` to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default *Prem Sichanugrist*
This can be customized by setting `ActionController::Base.wrap_parameters` in `config/initializer/wrap_parameters.rb`
* RJS has been extracted out to a gem. *fxn*
* Implicit actions named not_implemented can be rendered. *Santiago Pastorino*
* Wildcard route will always match the optional format segment by default. *Prem Sichanugrist*
For example if you have this route:
map '*pages' => 'pages#show'
by requesting '/foo/bar.json', your `params[:pages]` will be equals to "foo/bar" with the request format of JSON. If you want the old 3.0.x behavior back, you could supply `:format => false` like this:
map '*pages' => 'pages#show', :format => false
* Added Base.http_basic_authenticate_with to do simple http basic authentication with a single class method call *DHH*
class PostsController < ApplicationController
USER_NAME, PASSWORD = "dhh", "secret"
before_filter :authenticate, :except => [ :index ]
def index
render :text => "Everyone can see me!"
end
def edit
render :text => "I'm only accessible if you know the password"
end
private
def authenticate
authenticate_or_request_with_http_basic do |user_name, password|
user_name == USER_NAME && password == PASSWORD
end
end
end
..can now be written as
class PostsController < ApplicationController
http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
def index
render :text => "Everyone can see me!"
end
def edit
render :text => "I'm only accessible if you know the password"
end
end
* Allow you to add `force_ssl` into controller to force browser to transfer data via HTTPS protocol on that particular controller. You can also specify `:only` or `:except` to specific it to particular action. *DHH and Prem Sichanugrist*
* Allow FormHelper#form_for to specify the :method as a direct option instead of through the :html hash *DHH*
form_for(@post, remote: true, method: :delete) instead of form_for(@post, remote: true, html: { method: :delete })
* Make JavaScriptHelper#j() an alias for JavaScriptHelper#escape_javascript() -- note this then supersedes the Object#j() method that the JSON gem adds within templates using the JavaScriptHelper *DHH*
* Sensitive query string parameters (specified in config.filter_parameters) will now be filtered out from the request paths in the log file. *Prem Sichanugrist, fxn*
* URL parameters which return false for to_param now appear in the query string (previously they were removed) *Andrew White*
* URL parameters which return nil for to_param are now removed from the query string *Andrew White*
* ActionDispatch::MiddlewareStack now uses composition over inheritance. It is
no longer an array which means there may be methods missing that were not
tested.
* Add an :authenticity_token option to form_tag for custom handling or to omit the token (pass :authenticity_token => false). *Jakub Kuźma, Igor Wiedler*
* HTML5 button_tag helper. *Rizwan Reza*
* Template lookup now searches further up in the inheritance chain. *Artemave*
* Brought back config.action_view.cache_template_loading, which allows to decide whether templates should be cached or not. *Piotr Sarnacki*
* url_for and named url helpers now accept :subdomain and :domain as options, *Josh Kalderimis*
* The redirect route method now also accepts a hash of options which will only change the parts of the url in question, or an object which responds to call, allowing for redirects to be reused (check the documentation for examples). *Josh Kalderimis*
* Added config.action_controller.include_all_helpers. By default 'helper :all' is done in ActionController::Base, which includes all the helpers by default. Setting include_all_helpers to false will result in including only application_helper and helper corresponding to controller (like foo_helper for foo_controller). *Piotr Sarnacki*
* Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options:
tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)})
# => <div data-name="Stephen" data-city-state="[&quot;Chicago&quot;,&quot;IL&quot;]" />
Keys are dasherized. Values are JSON-encoded, except for strings and symbols. *Stephen Celis*
* Deprecate old template handler API. The new API simply requires a template handler to respond to call. *José Valim*
* :rhtml and :rxml were finally removed as template handlers. *José Valim*
* Moved etag responsibility from ActionDispatch::Response to the middleware stack. *José Valim*
* Rely on Rack::Session stores API for more compatibility across the Ruby world. This is backwards incompatible since Rack::Session expects #get_session to accept 4 arguments and requires #destroy_session instead of simply #destroy. *José Valim*
* file_field automatically adds :multipart => true to the enclosing form. *Santiago Pastorino*
* Renames csrf_meta_tag -> csrf_meta_tags, and aliases csrf_meta_tag for backwards compatibility. *fxn*
* Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used for HTTP caching. Note that Rack::Cache will be used if you use #expires_in, #fresh_when or #stale with :public => true. Otherwise, the caching rules will apply to the browser only. *Yehuda Katz, Carl Lerche*
Please check [3-0-stable](https://github.com/rails/rails/blob/3-0-stable/actionpack/CHANGELOG) for previous changes.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2011 David Heinemeier Hansson
Copyright (c) 2004-2010 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -19,8 +19,9 @@ It consists of several modules:
* Action View, which handles view template lookup and rendering, and provides
view helpers that assist when building HTML forms, Atom feeds and more.
Template formats that Action View handles are ERB (embedded Ruby, typically
used to inline short Ruby snippets inside HTML), and XML Builder.
Template formats that Action View handles are ERb (embedded Ruby, typically
used to inline short Ruby snippets inside HTML), XML Builder and RJS
(dynamically generated JavaScript from Ruby code).
With the Ruby on Rails framework, users only directly interface with the
Action Controller module. Necessary Action Dispatch functionality is activated
@@ -33,7 +34,7 @@ A short rundown of some of the major features:
* Actions grouped in controller as methods instead of separate command objects
and can therefore share helper methods
class CustomersController < ActionController::Base
CustomersController < ActionController::Base
def show
@customer = find_customer
end
@@ -56,9 +57,9 @@ A short rundown of some of the major features:
{Learn more}[link:classes/ActionController/Base.html]
* ERB templates (static content mixed with dynamic output from ruby)
* ERb templates (static content mixed with dynamic output from ruby)
<% @posts.each do |post| %>
<% for post in @posts %>
Title: <%= post.title %>
<% end %>
@@ -81,7 +82,7 @@ A short rundown of some of the major features:
xml.language "en-us"
xml.ttl "40"
@recent_items.each do |item|
for item in @recent_items
xml.item do
xml.title(item_title(item))
xml.description(item_description(item))
@@ -261,7 +262,7 @@ methods:
layout "weblog/layout"
def index
@posts = Post.all
@posts = Post.find(:all)
end
def show
@@ -293,7 +294,7 @@ And the templates look like this:
</body></html>
weblog/index.html.erb:
<% @posts.each do |post| %>
<% for post in @posts %>
<p><%= link_to(post.title, :action => "show", :id => post.id) %></p>
<% end %>
@@ -322,7 +323,7 @@ The latest version of Action Pack can be installed with Rubygems:
Source code can be downloaded as part of the Rails project on GitHub
* https://github.com/rails/rails/tree/master/actionpack
* http://github.com/rails/rails/tree/master/actionpack/
== License
@@ -338,4 +339,4 @@ API documentation is at
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
* https://github.com/rails/rails/issues
* https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets

View File

@@ -8,18 +8,15 @@ Rake can be found at http://rake.rubyforge.org
== Running by hand
To run a single test suite
If you only want to run a single test suite, or don't want to bother with Rake,
you can do so with something like:
rake test TEST=path/to/test.rb
ruby -Itest test/controller/base_tests.rb
which can be further narrowed down to one test:
rake test TEST=path/to/test.rb TESTOPTS="--name=test_something"
== Dependency on Active Record and database setup
== Dependency on ActiveRecord and database setup
Test cases in the test/controller/active_record/ directory depend on having
activerecord and sqlite installed. If Active Record is not in
activerecord and sqlite installed. If ActiveRecord is not in
actionpack/../activerecord directory, or the sqlite rubygem is not installed,
these tests are skipped.

9
actionpack/Rakefile Executable file → Normal file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env rake
require 'rake'
require 'rake/testtask'
require 'rake/packagetask'
require 'rubygems/package_task'
require 'rake/gempackagetask'
desc "Default Task"
task :default => :test
@@ -18,8 +18,7 @@ Rake::TestTask.new(:test_action_pack) do |t|
# this will not happen automatically and the tests (as a whole) will error
t.test_files = Dir.glob('test/{abstract,controller,dispatch,template}/**/*_test.rb').sort
t.warning = true
t.verbose = true
# t.warning = true
end
namespace :test do
@@ -36,7 +35,7 @@ end
spec = eval(File.read('actionpack.gemspec'))
Gem::PackageTask.new(spec) do |p|
Rake::GemPackageTask.new(spec) do |p|
p.gem_spec = spec
end

View File

@@ -11,21 +11,21 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'actionpack'
s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.files = Dir['CHANGELOG', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.require_path = 'lib'
s.requirements << 'none'
s.has_rdoc = true
s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
s.add_dependency('rack-cache', '~> 1.2')
s.add_dependency('builder', '~> 3.2')
s.add_dependency('i18n', '~> 0.6')
s.add_dependency('rack', '~> 1.4.1')
s.add_dependency('rack-test', '~> 0.6.1')
s.add_dependency('rack-mount', '~> 0.8.2')
s.add_dependency('sprockets', '~> 2.10')
s.add_dependency('erubis', '~> 2.7.0')
s.add_development_dependency('tzinfo', '~> 0.3.29')
s.add_dependency('builder', '~> 2.1.2')
s.add_dependency('i18n', '~> 0.4.1')
s.add_dependency('rack', '~> 1.2.1')
s.add_dependency('rack-test', '~> 0.5.4')
s.add_dependency('rack-mount', '~> 0.6.12')
s.add_dependency('tzinfo', '~> 0.3.23')
s.add_dependency('erubis', '~> 2.6.6')
end

View File

@@ -24,5 +24,4 @@ module AbstractController
autoload :Translation
autoload :AssetPaths
autoload :ViewPaths
autoload :UrlFor
end

View File

@@ -3,8 +3,7 @@ module AbstractController
extend ActiveSupport::Concern
included do
config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir,
:stylesheets_dir, :default_asset_host_protocol
config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir
end
end
end
end

View File

@@ -1,4 +1,3 @@
require 'erubis'
require 'active_support/configurable'
require 'active_support/descendants_tracker'
require 'active_support/core_ext/module/anonymous'
@@ -14,12 +13,10 @@ module AbstractController
class Base
attr_internal :response_body
attr_internal :action_name
attr_internal :formats
include ActiveSupport::Configurable
extend ActiveSupport::DescendantsTracker
undef_method :not_implemented
class << self
attr_reader :abstract
alias_method :abstract?, :abstract
@@ -33,9 +30,10 @@ module AbstractController
# A list of all internal methods for a controller. This finds the first
# abstract superclass of a controller, and gets a list of all public
# instance methods on that abstract class. Public instance methods of
# a controller would normally be considered action methods, so methods
# declared on abstract classes are being removed.
# (ActionController::Metal and ActionController::Base are defined as abstract)
# a controller would normally be considered action methods, so we
# are removing those methods on classes declared as abstract
# (ActionController::Metal and ActionController::Base are defined
# as abstract)
def internal_methods
controller = self
controller = controller.superclass until controller.abstract?
@@ -63,13 +61,13 @@ module AbstractController
def action_methods
@action_methods ||= begin
# All public instance methods of this class, including ancestors
methods = (public_instance_methods(true) -
methods = public_instance_methods(true).map { |m| m.to_s }.to_set -
# Except for public instance methods of Base and its ancestors
internal_methods +
internal_methods.map { |m| m.to_s } +
# Be sure to include shadowed public instance methods of this class
public_instance_methods(false)).uniq.map { |x| x.to_s } -
public_instance_methods(false).map { |m| m.to_s } -
# And always exclude explicitly hidden actions
hidden_actions.to_a
hidden_actions
# Clear out AS callback method pollution
methods.reject { |method| method =~ /_one_time_conditions/ }
@@ -130,29 +128,17 @@ module AbstractController
self.class.action_methods
end
# Returns true if a method for the action is available and
# can be dispatched, false otherwise.
#
# Notice that <tt>action_methods.include?("foo")</tt> may return
# false and <tt>available_action?("foo")</tt> returns true because
# available action consider actions that are also available
# through other means, for example, implicit render ones.
def available_action?(action_name)
method_for_action(action_name).present?
end
private
# Returns true if the name can be considered an action because
# it has a method defined in the controller.
# Returns true if the name can be considered an action. This can
# be overridden in subclasses to modify the semantics of what
# can be considered an action.
#
# ==== Parameters
# * <tt>name</tt> - The name of an action to be tested
#
# ==== Returns
# * <tt>TrueClass</tt>, <tt>FalseClass</tt>
#
# :api: private
def action_method?(name)
self.class.action_methods.include?(name)
end
@@ -160,9 +146,6 @@ module AbstractController
# Call the action. Override this in a subclass to modify the
# behavior around processing an action. This, and not #process,
# is the intended way to override action dispatching.
#
# Notice that the first argument is the method to be dispatched
# which is *not* necessarily the same as the action name.
def process_action(method_name, *args)
send_action(method_name, *args)
end
@@ -177,8 +160,8 @@ module AbstractController
# If the action name was not found, but a method called "action_missing"
# was found, #method_for_action will return "_handle_action_missing".
# This method calls #action_missing with the current action name.
def _handle_action_missing(*args)
action_missing(@_action_name, *args)
def _handle_action_missing
action_missing(@_action_name)
end
# Takes an action name and returns the name of the method that will

View File

@@ -13,8 +13,8 @@ module AbstractController
# Override AbstractController::Base's process_action to run the
# process_action callbacks around the normal behavior.
def process_action(*args)
run_callbacks(:process_action, action_name) do
def process_action(method_name)
run_callbacks(:process_action, method_name) do
super
end
end
@@ -29,7 +29,7 @@ module AbstractController
#
# ==== Options
# * <tt>only</tt> - The callback should be run only for this action
# * <tt>except</tt> - The callback should be run for all actions except this action
# * <tt>except<tt> - The callback should be run for all actions except this action
def _normalize_callback_options(options)
if only = options[:only]
only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ")
@@ -81,29 +81,27 @@ module AbstractController
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
# Append a before, after or around filter. See _insert_callbacks
# for details on the allowed parameters.
def #{filter}_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options|
options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after}
set_callback(:process_action, :#{filter}, name, options)
end
end
def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options}
set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before_filter, name, options)
end # end
end # end
# Prepend a before, after or around filter. See _insert_callbacks
# for details on the allowed parameters.
def prepend_#{filter}_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options|
options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after}
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true))
end
end
def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
end # end
end # end
# Skip a before, after or around filter. See _insert_callbacks
# for details on the allowed parameters.
def skip_#{filter}_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options|
skip_callback(:process_action, :#{filter}, name, options)
end
end
def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options)
end # end
end # end
# *_filter is the same as append_*_filter
alias_method :append_#{filter}_filter, :#{filter}_filter

View File

@@ -4,6 +4,8 @@ module AbstractController
module Helpers
extend ActiveSupport::Concern
include Rendering
included do
class_attribute :_helpers
self._helpers = Module.new
@@ -110,6 +112,17 @@ module AbstractController
default_helper_module! unless anonymous?
end
private
# Makes all the (instance) methods in the helper module available to templates
# rendered through this controller.
#
# ==== Parameters
# * <tt>module</tt> - The module to include into the current helper module
# for the class
def add_template_helper(mod)
_helpers.module_eval { include mod }
end
# Returns a list of modules, normalized from the acceptable kinds of
# helpers with the following behavior:
#
@@ -142,17 +155,6 @@ module AbstractController
end
end
private
# Makes all the (instance) methods in the helper module available to templates
# rendered through this controller.
#
# ==== Parameters
# * <tt>module</tt> - The module to include into the current helper module
# for the class
def add_template_helper(mod)
_helpers.module_eval { include mod }
end
def default_helper_module!
module_name = name.sub(/Controller$/, '')
module_path = module_name.underscore

View File

@@ -81,12 +81,11 @@ module AbstractController
# class EmployeeController < BankController
# layout nil
#
# In these examples:
# * The InformationController uses the "bank_standard" layout, inherited from BankController.
# * The TellerController follows convention and uses +app/views/layouts/teller.html.erb+.
# * The TillController inherits the layout from TellerController and uses +teller.html.erb+ as well.
# * The VaultController chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
# * The EmployeeController does not use a layout at all.
# The InformationController uses "bank_standard" inherited from the BankController, the VaultController overwrites
# and picks the layout dynamically, and the EmployeeController doesn't want to use a layout at all.
#
# The TellerController uses +teller.html.erb+, and TillController inherits that layout and
# uses it as well.
#
# == Types of layouts
#
@@ -139,8 +138,8 @@ module AbstractController
#
# end
#
# This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will
# be rendered directly, without wrapping a layout around the rendered view.
# This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout
# around the rendered view.
#
# Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
# #<tt>:except => [ :rss, :text_only ]</tt> is valid, as is <tt>:except => :rss</tt>.
@@ -159,7 +158,7 @@ module AbstractController
# end
# end
#
# This will override the controller-wide "weblog_standard" layout, and will render the help action with the "help" layout instead.
# This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
module Layouts
extend ActiveSupport::Concern
@@ -167,7 +166,6 @@ module AbstractController
included do
class_attribute :_layout_conditions
remove_possible_method :_layout_conditions
delegate :_layout_conditions, :to => :'self.class'
self._layout_conditions = {}
_write_layout_method
@@ -213,7 +211,7 @@ module AbstractController
# true:: raise an ArgumentError
#
# ==== Parameters
# * <tt>layout</tt> - The layout to use.
# * <tt>String, Symbol, false</tt> - The layout to use.
#
# ==== Options (conditions)
# * :only - A list of actions to apply this layout to.
@@ -237,10 +235,13 @@ module AbstractController
controller_path
end
# Creates a _layout method to be called by _default_layout .
# Takes the specified layout and creates a _layout method to be called
# by _default_layout
#
# If a layout is not explicitly mentioned then look for a layout with the controller's name.
# if nothing is found then try same procedure to find super class's layout.
# If there is no explicit layout specified:
# If a layout is found in the view paths with the controller's
# name, return that string. Otherwise, use the superclass'
# layout (which might also be implied)
def _write_layout_method
remove_possible_method(:_layout)
@@ -267,11 +268,11 @@ module AbstractController
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
when nil
if name
_prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
_prefix = "layouts" unless _implied_layout_name =~ /\blayouts/
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def _layout
if template_exists?("#{_implied_layout_name}", #{_prefixes.inspect})
if template_exists?("#{_implied_layout_name}", #{_prefix.inspect})
"#{_implied_layout_name}"
else
super
@@ -294,15 +295,15 @@ module AbstractController
end
end
attr_internal_writer :action_has_layout
attr_writer :action_has_layout
def initialize(*)
@_action_has_layout = true
@action_has_layout = true
super
end
def action_has_layout?
@_action_has_layout
@action_has_layout
end
private
@@ -310,10 +311,14 @@ module AbstractController
# This will be overwritten by _write_layout_method
def _layout; end
# Determine the layout for a given name, taking into account the name type.
# Determine the layout for a given name and details, taking into account
# the name type.
#
# ==== Parameters
# * <tt>name</tt> - The name of the template
# * <tt>details</tt> - A list of details to restrict
# the lookup to. By default, layout lookup is limited to the
# formats specified for the current request.
def _layout_for_option(name)
case name
when String then name
@@ -326,12 +331,15 @@ module AbstractController
end
end
# Returns the default layout for this controller.
# Returns the default layout for this controller and a given set of details.
# Optionally raises an exception if the layout could not be found.
#
# ==== Parameters
# * <tt>require_layout</tt> - If set to true and layout is not found,
# an ArgumentError exception is raised (defaults to false)
# * <tt>details</tt> - A list of details to restrict the search by. This
# might include details like the format or locale of the template.
# * <tt>require_logout</tt> - If this is true, raise an ArgumentError
# with details about the fact that the exception could not be
# found (defaults to false)
#
# ==== Returns
# * <tt>template</tt> - The template object for the default layout (or nil)
@@ -339,7 +347,8 @@ module AbstractController
begin
layout_name = _layout if action_has_layout?
rescue NameError => e
raise e, "Could not render layout: #{e.message}"
raise NoMethodError,
"You specified #{@_layout.inspect} as the layout, but no such method was found"
end
if require_layout && action_has_layout? && !layout_name

View File

@@ -1,18 +0,0 @@
module AbstractController
module Railties
module RoutesHelpers
def self.with(routes)
Module.new do
define_method(:inherited) do |klass|
super(klass)
if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) }
klass.send(:include, namespace._railtie.routes.url_helpers)
else
klass.send(:include, routes.url_helpers)
end
end
end
end
end
end
end

View File

@@ -1,6 +1,5 @@
require "abstract_controller/base"
require "action_view"
require "active_support/core_ext/object/instance_variables"
module AbstractController
class DoubleRenderError < Error
@@ -13,16 +12,16 @@ module AbstractController
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
# it will trigger the lookup_context and consequently expire the cache.
# TODO Add some deprecation warnings to remove I18n.locale from controllers
class I18nProxy < ::I18n::Config #:nodoc:
attr_reader :original_config, :lookup_context
attr_reader :i18n_config, :lookup_context
def initialize(original_config, lookup_context)
original_config = original_config.original_config if original_config.respond_to?(:original_config)
@original_config, @lookup_context = original_config, lookup_context
def initialize(i18n_config, lookup_context)
@i18n_config, @lookup_context = i18n_config, lookup_context
end
def locale
@original_config.locale
@i18n_config.locale
end
def locale=(value)
@@ -32,12 +31,8 @@ module AbstractController
module Rendering
extend ActiveSupport::Concern
include AbstractController::ViewPaths
included do
config_accessor :protected_instance_variables, :instance_reader => false
self.protected_instance_variables = []
end
include AbstractController::ViewPaths
# Overwrite process to setup I18n proxy.
def process(*) #:nodoc:
@@ -50,27 +45,31 @@ module AbstractController
module ClassMethods
def view_context_class
@view_context_class ||= begin
routes = _routes if respond_to?(:_routes)
helpers = _helpers if respond_to?(:_helpers)
ActionView::Base.prepare(routes, helpers)
controller = self
Class.new(ActionView::Base) do
if controller.respond_to?(:_helpers)
include controller._helpers
if controller.respond_to?(:_routes)
include controller._routes.url_helpers
end
# TODO: Fix RJS to not require this
self.helpers = controller._helpers
end
end
end
end
end
attr_internal_writer :view_context_class
# Explicitly define protected_instance_variables so it can be
# inherited and overwritten by other modules if needed.
def protected_instance_variables
config.protected_instance_variables
end
attr_writer :view_context_class
def view_context_class
@_view_context_class || self.class.view_context_class
@view_context_class || self.class.view_context_class
end
def initialize(*)
@_view_context_class = nil
@view_context_class = nil
super
end
@@ -84,26 +83,21 @@ module AbstractController
#
# Override this method in a module to change the default behavior.
def view_context
view_context_class.new(view_renderer, view_assigns, self)
end
# Returns an object that is able to render templates.
def view_renderer
@_view_renderer ||= ActionView::Renderer.new(lookup_context)
view_context_class.new(lookup_context, view_assigns, self)
end
# Normalize arguments, options and then delegates render_to_body and
# sticks the result in self.response_body.
def render(*args, &block)
options = _normalize_render(*args, &block)
self.response_body = render_to_body(options)
self.response_body = render_to_string(*args, &block)
end
# Raw rendering of a template to a string. Just convert the results of
# render_response into a String.
# render_to_body into a String.
# :api: plugin
def render_to_string(*args, &block)
options = _normalize_render(*args, &block)
options = _normalize_args(*args, &block)
_normalize_options(options)
render_to_body(options)
end
@@ -117,13 +111,15 @@ module AbstractController
# Find and renders a template based on the options given.
# :api: private
def _render_template(options) #:nodoc:
view_renderer.render(view_context, options)
view_context.render(options)
end
DEFAULT_PROTECTED_INSTANCE_VARIABLES = %w(
@_action_name @_response_body @_formats @_prefixes @_config
@_view_context_class @_view_renderer @_lookup_context
)
# The prefix used in render "foo" shortcuts.
def _prefix
controller_path
end
private
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
@@ -131,58 +127,42 @@ module AbstractController
def view_assigns
hash = {}
variables = instance_variable_names
variables -= protected_instance_variables
variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES
variables.each { |name| hash[name.to_s[1, name.length]] = instance_variable_get(name) }
variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
variables.each { |name| hash[name.to_s[1..-1]] = instance_variable_get(name) }
hash
end
private
# Normalize args and options.
# :api: private
def _normalize_render(*args, &block)
options = _normalize_args(*args, &block)
_normalize_options(options)
options
end
# Normalize args by converting render "foo" to render :action => "foo" and
# Normalize options by converting render "foo" to render :action => "foo" and
# render "foo/bar" to render :file => "foo/bar".
# :api: plugin
def _normalize_args(action=nil, options={})
case action
when NilClass
when Hash
options = action
options, action = action, nil
when String, Symbol
action = action.to_s
key = action.include?(?/) ? :file : :action
options[key] = action
else
options[:partial] = action
options.merge!(:partial => action)
end
options
end
# Normalize options.
# :api: plugin
def _normalize_options(options)
if options[:partial] == true
options[:partial] = action_name
end
if (options.keys & [:partial, :file, :template]).empty?
options[:prefixes] ||= _prefixes
options[:prefix] ||= _prefix
end
options[:template] ||= (options[:action] || action_name).to_s
options
end
# Process extra options.
# :api: plugin
def _process_options(options)
end
end

View File

@@ -1,33 +0,0 @@
# Includes +url_for+ into the host class (e.g. an abstract controller or mailer). The class
# has to provide a +RouteSet+ by implementing the <tt>_routes</tt> methods. Otherwise, an
# exception will be raised.
#
# Note that this module is completely decoupled from HTTP - the only requirement is a valid
# <tt>_routes</tt> implementation.
module AbstractController
module UrlFor
extend ActiveSupport::Concern
include ActionDispatch::Routing::UrlFor
def _routes
raise "In order to use #url_for, you must include routing helpers explicitly. " \
"For instance, `include Rails.application.routes.url_helpers"
end
module ClassMethods
def _routes
nil
end
def action_methods
@action_methods ||= begin
if _routes
super - _routes.named_routes.helper_names
else
super
end
end
end
end
end
end

View File

@@ -11,36 +11,11 @@ module AbstractController
delegate :find_template, :template_exists?, :view_paths, :formats, :formats=,
:locale, :locale=, :to => :lookup_context
module ClassMethods
def parent_prefixes
@parent_prefixes ||= begin
parent_controller = superclass
prefixes = []
until parent_controller.abstract?
prefixes << parent_controller.controller_path
parent_controller = parent_controller.superclass
end
prefixes
end
end
end
# The prefixes used in render "foo" shortcuts.
def _prefixes
@_prefixes ||= begin
parent_prefixes = self.class.parent_prefixes
parent_prefixes.dup.unshift(controller_path)
end
end
# LookupContext is the object responsible to hold all information required to lookup
# templates, i.e. view paths and details. Check ActionView::LookupContext for more
# information.
def lookup_context
@_lookup_context ||=
ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes)
@lookup_context ||= ActionView::LookupContext.new(self.class._view_paths, details_for_lookup)
end
def details_for_lookup
@@ -61,7 +36,7 @@ module AbstractController
# ==== Parameters
# * <tt>path</tt> - If a String is provided, it gets converted into
# the default view path. You may also provide a custom view path
# (see ActionView::PathSet for more information)
# (see ActionView::ViewPathSet for more information)
def append_view_path(path)
self.view_paths = view_paths.dup + Array(path)
end
@@ -71,7 +46,7 @@ module AbstractController
# ==== Parameters
# * <tt>path</tt> - If a String is provided, it gets converted into
# the default view path. You may also provide a custom view path
# (see ActionView::PathSet for more information)
# (see ActionView::ViewPathSet for more information)
def prepend_view_path(path)
self.view_paths = Array(path) + view_paths.dup
end
@@ -84,12 +59,12 @@ module AbstractController
# Set the view paths.
#
# ==== Parameters
# * <tt>paths</tt> - If a PathSet is provided, use that;
# otherwise, process the parameter into a PathSet.
# * <tt>paths</tt> - If a ViewPathSet is provided, use that;
# otherwise, process the parameter into a ViewPathSet.
def view_paths=(paths)
self._view_paths = ActionView::Base.process_view_paths(paths)
self._view_paths.freeze
end
end
end
end
end

View File

@@ -13,9 +13,7 @@ module ActionController
autoload :Compatibility
autoload :ConditionalGet
autoload :Cookies
autoload :DataStreaming
autoload :Flash
autoload :ForceSSL
autoload :Head
autoload :Helpers
autoload :HideActions
@@ -23,7 +21,6 @@ module ActionController
autoload :ImplicitRender
autoload :Instrumentation
autoload :MimeResponds
autoload :ParamsWrapper
autoload :RackDelegation
autoload :Redirecting
autoload :Renderers
@@ -37,13 +34,14 @@ module ActionController
autoload :UrlFor
end
autoload :Integration, 'action_controller/deprecated/integration_test'
autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
autoload :UrlWriter, 'action_controller/deprecated'
autoload :Routing, 'action_controller/deprecated'
autoload :TestCase, 'action_controller/test_case'
autoload :TemplateAssertions, 'action_controller/test_case'
autoload :Dispatcher, 'action_controller/deprecated/dispatcher'
autoload :UrlWriter, 'action_controller/deprecated/url_writer'
autoload :UrlRewriter, 'action_controller/deprecated/url_writer'
autoload :Integration, 'action_controller/deprecated/integration_test'
autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
autoload :Routing, 'action_controller/deprecated'
autoload :TestCase, 'action_controller/test_case'
eager_autoload do
autoload :RecordIdentifier
@@ -76,5 +74,4 @@ require 'active_support/core_ext/load_error'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/name_error'
require 'active_support/core_ext/uri'
require 'active_support/inflector'

View File

@@ -24,14 +24,14 @@ module ActionController
#
# Actions, by default, render a template in the <tt>app/views</tt> directory corresponding to the name of the controller and action
# after executing code in the action. For example, the +index+ action of the PostsController would render the
# template <tt>app/views/posts/index.html.erb</tt> by default after populating the <tt>@posts</tt> instance variable.
# template <tt>app/views/posts/index.erb</tt> by default after populating the <tt>@posts</tt> instance variable.
#
# Unlike index, the create action will not render a template. After performing its main purpose (creating a
# new post), it initiates a redirect instead. This redirect works by returning an external
# "302 Moved" HTTP response that takes the user to the index action.
#
# These two methods represent the two basic action archetypes used in Action Controllers. Get-and-show and do-and-redirect.
# Most actions are variations on these themes.
# Most actions are variations of these themes.
#
# == Requests
#
@@ -50,7 +50,7 @@ module ActionController
#
# All request parameters, whether they come from a GET or POST request, or from the URL, are available through the params method
# which returns a hash. For example, an action that was performed through <tt>/posts?category=All&limit=5</tt> will include
# <tt>{ "category" => "All", "limit" => "5" }</tt> in params.
# <tt>{ "category" => "All", "limit" => 5 }</tt> in params.
#
# It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:
#
@@ -63,7 +63,7 @@ module ActionController
#
# == Sessions
#
# Sessions allow you to store objects in between requests. This is useful for objects that are not yet ready to be persisted,
# Sessions allows you to store objects in between requests. This is useful for objects that are not yet ready to be persisted,
# such as a Signup object constructed in a multi-paged process, or objects that don't change much and are needed all the time, such
# as a User object for a system that requires login. The session should not be used, however, as a cache for objects where it's likely
# they could be changed unknowingly. It's usually too much work to keep it all synchronized -- something databases already excel at.
@@ -93,9 +93,9 @@ module ActionController
# * ActiveRecord::SessionStore - Sessions are stored in your database, which works better than PStore with multiple app servers and,
# unlike CookieStore, hides your session contents from the user. To use ActiveRecord::SessionStore, set
#
# MyApplication::Application.config.session_store :active_record_store
# config.action_controller.session_store = :active_record_store
#
# in your <tt>config/initializers/session_store.rb</tt> and run <tt>script/rails g session_migration</tt>.
# in your <tt>config/environment.rb</tt> and run <tt>rake db:sessions:create</tt>.
#
# == Responses
#
@@ -105,7 +105,7 @@ module ActionController
# == Renders
#
# Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering
# of a template. Included in the Action Pack is the Action View, which enables rendering of ERB templates. It's automatically configured.
# of a template. Included in the Action Pack is the Action View, which enables rendering of ERb templates. It's automatically configured.
# The controller passes objects to the view by assigning instance variables:
#
# def show
@@ -116,8 +116,8 @@ module ActionController
#
# Title: <%= @post.title %>
#
# You don't have to rely on the automated rendering. For example, actions that could result in the rendering of different templates
# will use the manual rendering methods:
# You don't have to rely on the automated rendering. Especially actions that could result in the rendering of different templates will use
# the manual rendering methods:
#
# def search
# @results = Search.find(params[:query])
@@ -128,13 +128,13 @@ module ActionController
# end
# end
#
# Read more about writing ERB and Builder templates in ActionView::Base.
# Read more about writing ERb and Builder templates in ActionView::Base.
#
# == Redirects
#
# Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to the
# database, we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're
# going to reuse (and redirect to) a <tt>show</tt> action that we'll assume has already been created. The code might look like this:
# Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to a database,
# we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're going to reuse (and redirect to)
# a <tt>show</tt> action that we'll assume has already been created. The code might look like this:
#
# def create
# @entry = Entry.new(params[:entry])
@@ -146,11 +146,7 @@ module ActionController
# end
# end
#
# In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method, which is then executed.
# Note that this is an external HTTP-level redirection which will cause the browser to make a second request (a GET to the show action),
# and not some internal re-routing which calls both "create" and then "show" within one request.
#
# Learn more about <tt>redirect_to</tt> and what options you have in ActionController::Redirecting.
# In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed.
#
# == Calling multiple redirects or renders
#
@@ -200,28 +196,22 @@ module ActionController
Cookies,
Flash,
RequestForgeryProtection,
ForceSSL,
Streaming,
DataStreaming,
RecordIdentifier,
HttpAuthentication::Basic::ControllerMethods,
HttpAuthentication::Digest::ControllerMethods,
HttpAuthentication::Token::ControllerMethods,
# Before callbacks should also be executed the earliest as possible, so
# also include them at the bottom.
AbstractController::Callbacks,
# Append rescue at the bottom to wrap as much as possible.
Rescue,
# Add instrumentations hooks at the bottom, to ensure they instrument
# all the methods properly.
Instrumentation,
# Params wrapper should come before instrumentation so they are
# properly showed in logs
ParamsWrapper
# Before callbacks should also be executed the earliest as possible, so
# also include them at the bottom.
AbstractController::Callbacks,
# The same with rescue, append it at the end to wrap as much as possible.
Rescue
]
MODULES.each do |mod|
@@ -231,6 +221,13 @@ module ActionController
# Rails 2.x compatibility
include ActionController::Compatibility
def self.inherited(klass)
super
klass.helper :all if klass.superclass == ActionController::Base
end
require "action_controller/deprecated/base"
ActiveSupport.run_load_hooks(:action_controller, self)
end
end

View File

@@ -3,7 +3,7 @@ require 'uri'
require 'set'
module ActionController #:nodoc:
# \Caching is a cheap way of speeding up slow applications by keeping the result of
# Caching is a cheap way of speeding up slow applications by keeping the result of
# calculations, renderings, and database calls around for subsequent requests.
# Action Controller affords you three approaches in varying levels of granularity:
# Page, Action, Fragment.
@@ -14,7 +14,7 @@ module ActionController #:nodoc:
# Note: To turn off all caching and sweeping, set
# config.action_controller.perform_caching = false.
#
# == \Caching stores
# == Caching stores
#
# All the caching stores from ActiveSupport::Cache are available to be used as backends
# for Action Controller caching. This setting only affects action and fragment caching

View File

@@ -4,86 +4,73 @@ module ActionController #:nodoc:
module Caching
# Action caching is similar to page caching by the fact that the entire
# output of the response is cached, but unlike page caching, every
# request still goes through Action Pack. The key benefit of this is
# that filters run before the cache is served, which allows for
# authentication and other restrictions on whether someone is allowed
# to execute such action. Example:
# request still goes through the Action Pack. The key benefit
# of this is that filters are run before the cache is served, which
# allows for authentication and other restrictions on whether someone
# is allowed to see the cache. Example:
#
# class ListsController < ApplicationController
# before_filter :authenticate, :except => :public
#
# caches_page :public
# caches_action :index, :show
# caches_action :index, :show, :feed
# end
#
# In this example, the +public+ action doesn't require authentication
# so it's possible to use the faster page caching. On the other hand
# +index+ and +show+ require authentication. They can still be cached,
# but we need action caching for them.
# In this example, the public action doesn't require authentication,
# so it's possible to use the faster page caching method. But both
# the show and feed action are to be shielded behind the authenticate
# filter, so we need to implement those as action caches.
#
# Action caching uses fragment caching internally and an around
# filter to do the job. The fragment cache is named according to
# the host and path of the request. A page that is accessed at
# <tt>http://david.example.com/lists/show/1</tt> will result in a fragment named
# <tt>david.example.com/lists/show/1</tt>. This allows the cacher to
# differentiate between <tt>david.example.com/lists/</tt> and
# <tt>jamis.example.com/lists/</tt> -- which is a helpful way of assisting
# Action caching internally uses the fragment caching and an around
# filter to do the job. The fragment cache is named according to both
# the current host and the path. So a page that is accessed at
# http://david.somewhere.com/lists/show/1 will result in a fragment named
# "david.somewhere.com/lists/show/1". This allows the cacher to
# differentiate between "david.somewhere.com/lists/" and
# "jamis.somewhere.com/lists/" -- which is a helpful way of assisting
# the subdomain-as-account-key pattern.
#
# Different representations of the same resource, e.g.
# <tt>http://david.example.com/lists</tt> and
# <tt>http://david.example.com/lists.xml</tt>
# <tt>http://david.somewhere.com/lists</tt> and
# <tt>http://david.somewhere.com/lists.xml</tt>
# are treated like separate requests and so are cached separately.
# Keep in mind when expiring an action cache that
# <tt>:action => 'lists'</tt> is not the same as
# <tt>:action => 'list', :format => :xml</tt>.
#
# You can set modify the default action cache path by passing a
# <tt>:cache_path</tt> option. This will be passed directly to
# <tt>ActionCachePath.path_for</tt>. This is handy for actions with
# multiple possible routes that should be cached differently. If a
# block is given, it is called with the current controller instance.
# :cache_path option. This will be passed directly to
# ActionCachePath.path_for. This is handy for actions with multiple
# possible routes that should be cached differently. If a block is
# given, it is called with the current controller instance.
#
# And you can also use <tt>:if</tt> (or <tt>:unless</tt>) to pass a
# proc that specifies when the action should be cached.
# And you can also use :if (or :unless) to pass a Proc that
# specifies when the action should be cached.
#
# Finally, if you are using memcached, you can also pass <tt>:expires_in</tt>.
#
# The following example depicts some of the points made above:
# Finally, if you are using memcached, you can also pass :expires_in.
#
# class ListsController < ApplicationController
# before_filter :authenticate, :except => :public
#
# caches_page :public
#
# caches_action :index, :if => proc do
# !request.format.json? # cache if is not a JSON request
# caches_page :public
# caches_action :index, :if => proc do |c|
# !c.request.format.json? # cache if is not a JSON request
# end
#
# caches_action :show, :cache_path => { :project => 1 },
# :expires_in => 1.hour
#
# caches_action :feed, :cache_path => proc do
# if params[:user_id]
# user_list_url(params[:user_id, params[:id])
# caches_action :feed, :cache_path => proc do |controller|
# if controller.params[:user_id]
# controller.send(:user_list_url,
# controller.params[:user_id], controller.params[:id])
# else
# list_url(params[:id])
# controller.send(:list_url, controller.params[:id])
# end
# end
# end
#
# If you pass <tt>:layout => false</tt>, it will only cache your action
# content. That's useful when your layout has dynamic information.
# If you pass :layout => false, it will only cache your action
# content. It is useful when your layout has dynamic information.
#
# Warning: If the format of the request is determined by the Accept HTTP
# header the Content-Type of the cached response could be wrong because
# no information about the MIME type is stored in the cache key. So, if
# you first ask for MIME type M in the Accept header, a cache entry is
# created, and then perform a second request to the same resource asking
# for a different MIME type, you'd get the content cached for M.
#
# The <tt>:format</tt> parameter is taken into account though. The safest
# way to cache by MIME type is to pass the format in the route.
module Actions
extend ActiveSupport::Concern
@@ -102,14 +89,12 @@ module ActionController #:nodoc:
end
def _save_fragment(name, options)
return unless caching_allowed?
content = response_body
content = content.join if content.is_a?(Array)
if caching_allowed?
write_fragment(name, content, options)
else
content
end
write_fragment(name, content, options)
end
protected
@@ -159,7 +144,7 @@ module ActionController #:nodoc:
attr_reader :path, :extension
# If +infer_extension+ is true, the cache path extension is looked up from the request's
# path and format. This is desirable when reading and writing the cache, but not when
# path & format. This is desirable when reading and writing the cache, but not when
# expiring the cache - expire_action should expire the same files regardless of the
# request format.
def initialize(controller, options = {}, infer_extension = true)
@@ -175,8 +160,8 @@ module ActionController #:nodoc:
private
def normalize!(path)
path << 'index' if path[-1] == ?/
path << ".#{extension}" if extension and !path.split('?').first.ends_with?(".#{extension}")
URI.parser.unescape(path)
path << ".#{extension}" if extension and !path.ends_with?(extension)
URI.unescape(path)
end
end
end

View File

@@ -1,72 +1,52 @@
module ActionController #:nodoc:
module Caching
# Fragment caching is used for caching various blocks within
# views without caching the entire action as a whole. This is
# useful when certain elements of an action change frequently or
# depend on complicated state while other parts rarely change or
# can be shared amongst multiple parties. The caching is done using
# the <tt>cache</tt> helper available in the Action View. A
# template with fragment caching might look like:
# Fragment caching is used for caching various blocks within templates without caching the entire action as a whole. This is useful when
# certain elements of an action change frequently or depend on complicated state while other parts rarely change or can be shared amongst multiple
# parties. The caching is done using the cache helper available in the Action View. A template with caching might look something like:
#
# <b>Hello <%= @name %></b>
#
# <% cache do %>
# All the topics in the system:
# <%= render :partial => "topic", :collection => Topic.find(:all) %>
# <% end %>
#
# This cache will bind the name of the action that called it, so if
# this code was part of the view for the topics/list action, you
# would be able to invalidate it using:
#
# expire_fragment(:controller => "topics", :action => "list")
# This cache will bind to the name of the action that called it, so if this code was part of the view for the topics/list action, you would
# be able to invalidate it using <tt>expire_fragment(:controller => "topics", :action => "list")</tt>.
#
# This default behavior is limited if you need to cache multiple
# fragments per action or if the action itself is cached using
# <tt>caches_action</tt>. To remedy this, there is an option to
# qualify the name of the cached fragment by using the
# <tt>:action_suffix</tt> option:
# This default behavior is of limited use if you need to cache multiple fragments per action or if the action itself is cached using
# <tt>caches_action</tt>, so we also have the option to qualify the name of the cached fragment with something like:
#
# <% cache(:action => "list", :action_suffix => "all_topics") do %>
#
# That would result in a name such as
# <tt>/topics/list/all_topics</tt>, avoiding conflicts with the
# action cache and with any fragments that use a different suffix.
# Note that the URL doesn't have to really exist or be callable
# - the url_for system is just used to generate unique cache names
# that we can refer to when we need to expire the cache.
# That would result in a name such as "/topics/list/all_topics", avoiding conflicts with the action cache and with any fragments that use a
# different suffix. Note that the URL doesn't have to really exist or be callable - the url_for system is just used to generate unique
# cache names that we can refer to when we need to expire the cache.
#
# The expiration call for this example is:
#
# expire_fragment(:controller => "topics",
# :action => "list",
# :action_suffix => "all_topics")
# expire_fragment(:controller => "topics", :action => "list", :action_suffix => "all_topics")
module Fragments
# Given a key (as described in <tt>expire_fragment</tt>), returns
# a key suitable for use in reading, writing, or expiring a
# cached fragment. If the key is a hash, the generated key is the
# return value of url_for on that hash (without the protocol).
# All keys are prefixed with <tt>views/</tt> and uses
# Given a key (as described in <tt>expire_fragment</tt>), returns a key suitable for use in reading,
# writing, or expiring a cached fragment. If the key is a hash, the generated key is the return
# value of url_for on that hash (without the protocol). All keys are prefixed with "views/" and uses
# ActiveSupport::Cache.expand_cache_key for the expansion.
def fragment_cache_key(key)
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
end
# Writes <tt>content</tt> to the location signified by
# <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats).
# Writes <tt>content</tt> to the location signified by <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats)
def write_fragment(key, content, options = nil)
return content unless cache_configured?
key = fragment_cache_key(key)
instrument_fragment_cache :write_fragment, key do
content = content.to_str
content = content.html_safe.to_str if content.respond_to?(:html_safe)
cache_store.write(key, content, options)
end
content
end
# Reads a cached fragment from the location signified by <tt>key</tt>
# (see <tt>expire_fragment</tt> for acceptable formats).
# Reads a cached fragment from the location signified by <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats)
def read_fragment(key, options = nil)
return unless cache_configured?
@@ -77,8 +57,7 @@ module ActionController #:nodoc:
end
end
# Check if a cached fragment from the location signified by
# <tt>key</tt> exists (see <tt>expire_fragment</tt> for acceptable formats)
# Check if a cached fragment from the location signified by <tt>key</tt> exists (see <tt>expire_fragment</tt> for acceptable formats)
def fragment_exist?(key, options = nil)
return unless cache_configured?
key = fragment_cache_key(key)
@@ -91,9 +70,8 @@ module ActionController #:nodoc:
# Removes fragments from the cache.
#
# +key+ can take one of three forms:
#
# * String - This would normally take the form of a path, like
# <tt>pages/45/notes</tt>.
# <tt>"pages/45/notes"</tt>.
# * Hash - Treated as an implicit call to +url_for+, like
# <tt>{:controller => "pages", :action => "notes", :id => 45}</tt>
# * Regexp - Will remove any fragment that matches, so

View File

@@ -1,4 +1,5 @@
require 'fileutils'
require 'uri'
require 'active_support/core_ext/class/attribute_accessors'
module ActionController #:nodoc:
@@ -70,9 +71,9 @@ module ActionController #:nodoc:
# Manually cache the +content+ in the key determined by +path+. Example:
# cache_page "I'm the cached content", "/lists/show"
def cache_page(content, path, extension = nil)
def cache_page(content, path)
return unless perform_caching
path = page_cache_path(path, extension)
path = page_cache_path(path)
instrument_page_cache :write_page, path do
FileUtils.makedirs(File.dirname(path))
@@ -97,16 +98,14 @@ module ActionController #:nodoc:
end
private
def page_cache_file(path, extension)
name = (path.empty? || path == "/") ? "/index" : URI.parser.unescape(path.chomp('/'))
unless (name.split('/').last || name).include? '.'
name << (extension || self.page_cache_extension)
end
def page_cache_file(path)
name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/'))
name << page_cache_extension unless (name.split('/').last || name).include? '.'
return name
end
def page_cache_path(path, extension = nil)
page_cache_directory.to_s + page_cache_file(path, extension)
def page_cache_path(path)
page_cache_directory + page_cache_file(path)
end
def instrument_page_cache(name, path)
@@ -136,7 +135,7 @@ module ActionController #:nodoc:
# If no options are provided, the requested url is used. Example:
# cache_page "I'm the cached content", :controller => "lists", :action => "show"
def cache_page(content = nil, options = nil)
return unless self.class.perform_caching && caching_allowed?
return unless self.class.perform_caching && caching_allowed
path = case options
when Hash
@@ -147,13 +146,13 @@ module ActionController #:nodoc:
request.path
end
if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present?
extension = ".#{type_symbol}"
end
self.class.cache_page(content || response.body, path, extension)
self.class.cache_page(content || response.body, path)
end
private
def caching_allowed
request.get? && response.status.to_i == 200
end
end
end
end

View File

@@ -61,7 +61,6 @@ module ActionController #:nodoc:
end
def after(controller)
self.controller = controller
callback(:after) if controller.perform_caching
# Clean up, so that the controller can be collected after this request
self.controller = nil

View File

@@ -1,3 +1,3 @@
ActionController::AbstractRequest = ActionController::Request = ActionDispatch::Request
ActionController::AbstractResponse = ActionController::Response = ActionDispatch::Response
ActionController::Routing = ActionDispatch::Routing
ActionController::Routing = ActionDispatch::Routing

View File

@@ -0,0 +1,143 @@
module ActionController
class Base
# Deprecated methods. Wrap them in a module so they can be overwritten by plugins
# (like the verify method.)
module DeprecatedBehavior #:nodoc:
def relative_url_root
ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root is ineffective. " <<
"Please stop using it.", caller
end
def relative_url_root=
ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root= is ineffective. " <<
"Please stop using it.", caller
end
def consider_all_requests_local
ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local is deprecated, " <<
"use Rails.application.config.consider_all_requests_local instead", caller
Rails.application.config.consider_all_requests_local
end
def consider_all_requests_local=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local= is deprecated. " <<
"Please configure it on your application with config.consider_all_requests_local=", caller
Rails.application.config.consider_all_requests_local = value
end
def allow_concurrency
ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency is deprecated, " <<
"use Rails.application.config.allow_concurrency instead", caller
Rails.application.config.allow_concurrency
end
def allow_concurrency=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency= is deprecated. " <<
"Please configure it on your application with config.allow_concurrency=", caller
Rails.application.config.allow_concurrency = value
end
def ip_spoofing_check=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.ip_spoofing_check= is deprecated. " <<
"Please configure it on your application with config.action_dispatch.ip_spoofing_check=", caller
Rails.application.config.action_dispatch.ip_spoofing_check = value
end
def ip_spoofing_check
ActiveSupport::Deprecation.warn "ActionController::Base.ip_spoofing_check is deprecated. " <<
"Configuring ip_spoofing_check on the application configures a middleware.", caller
Rails.application.config.action_dispatch.ip_spoofing_check
end
def cookie_verifier_secret=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret= is deprecated. " <<
"Please configure it on your application with config.secret_token=", caller
end
def cookie_verifier_secret
ActiveSupport::Deprecation.warn "ActionController::Base.cookie_verifier_secret is deprecated.", caller
end
def trusted_proxies=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.trusted_proxies= is deprecated. " <<
"Please configure it on your application with config.action_dispatch.trusted_proxies=", caller
Rails.application.config.action_dispatch.ip_spoofing_check = value
end
def trusted_proxies
ActiveSupport::Deprecation.warn "ActionController::Base.trusted_proxies is deprecated. " <<
"Configuring trusted_proxies on the application configures a middleware.", caller
Rails.application.config.action_dispatch.ip_spoofing_check = value
end
def session(*args)
ActiveSupport::Deprecation.warn(
"Disabling sessions for a single controller has been deprecated. " +
"Sessions are now lazy loaded. So if you don't access them, " +
"consider them off. You can still modify the session cookie " +
"options with request.session_options.", caller)
end
def session=(value)
ActiveSupport::Deprecation.warn "ActionController::Base.session= is deprecated. " <<
"Please configure it on your application with config.session_store :cookie_store, :key => '....'", caller
if secret = value.delete(:secret)
Rails.application.config.secret_token = secret
end
if value.delete(:disabled)
Rails.application.config.session_store :disabled
else
store = Rails.application.config.session_store
Rails.application.config.session_store store, value
end
end
# Controls the resource action separator
def resource_action_separator
@resource_action_separator ||= "/"
end
def resource_action_separator=(val)
ActiveSupport::Deprecation.warn "ActionController::Base.resource_action_separator is deprecated and only " \
"works with the deprecated router DSL."
@resource_action_separator = val
end
def use_accept_header
ActiveSupport::Deprecation.warn "ActionController::Base.use_accept_header doesn't do anything anymore. " \
"The accept header is always taken into account."
end
def use_accept_header=(val)
use_accept_header
end
# This method has been moved to ActionDispatch::Request.filter_parameters
def filter_parameter_logging(*args, &block)
ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller)
filter = Rails.application.config.filter_parameters
filter.concat(args)
filter << block if block
filter
end
# This was moved to a plugin
def verify(*args)
ActiveSupport::Deprecation.warn "verify was removed from Rails and is now available as a plugin. " \
"Please install it with `rails plugin install git://github.com/rails/verification.git`.", caller
end
def exempt_from_layout(*)
ActiveSupport::Deprecation.warn "exempt_from_layout is no longer needed, because layouts in Rails 3 " \
"are restricted to the content-type of the template that was rendered.", caller
end
end
extend DeprecatedBehavior
delegate :consider_all_requests_local, :consider_all_requests_local=,
:allow_concurrency, :allow_concurrency=, :to => :"self.class"
end
end

View File

@@ -0,0 +1,28 @@
module ActionController
class Dispatcher
class << self
def before_dispatch(*args, &block)
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.before_dispatch is deprecated. " <<
"Please use ActionDispatch::Callbacks.before instead.", caller
ActionDispatch::Callbacks.before(*args, &block)
end
def after_dispatch(*args, &block)
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.after_dispatch is deprecated. " <<
"Please use ActionDispatch::Callbacks.after instead.", caller
ActionDispatch::Callbacks.after(*args, &block)
end
def to_prepare(*args, &block)
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.to_prepare is deprecated. " <<
"Please use config.to_prepare instead", caller
ActionDispatch::Callbacks.after(*args, &block)
end
def new
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.new is deprecated, use Rails.application instead."
Rails.application
end
end
end
end

View File

@@ -0,0 +1,14 @@
module ActionController
module UrlWriter
def self.included(klass)
ActiveSupport::Deprecation.warn "include ActionController::UrlWriter is deprecated. Instead, " \
"include Rails.application.routes.url_helpers"
klass.class_eval { include Rails.application.routes.url_helpers }
end
end
class UrlRewriter
def initialize(*)
end
end
end

View File

@@ -7,10 +7,8 @@ module ActionController
def start_processing(event)
payload = event.payload
params = payload[:params].except(*INTERNAL_PARAMS)
format = payload[:format]
format = format.to_s.upcase if format.is_a?(Symbol)
info " Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
info " Processing by #{payload[:controller]}##{payload[:action]} as #{payload[:formats].first.to_s.upcase}"
info " Parameters: #{params.inspect}" unless params.empty?
end
@@ -18,11 +16,7 @@ module ActionController
payload = event.payload
additions = ActionController::Base.log_process_action(payload)
status = payload[:status]
if status.nil? && payload[:exception].present?
status = Rack::Utils.status_code(ActionDispatch::ShowExceptions.rescue_responses[payload[:exception].first]) rescue nil
end
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in %.0fms" % event.duration
message = "Completed #{payload[:status]} #{Rack::Utils::HTTP_STATUS_CODES[payload[:status]]} in %.0fms" % event.duration
message << " (#{additions.join(" | ")})" unless additions.blank?
info(message)
@@ -48,7 +42,7 @@ module ActionController
def #{method}(event)
key_or_path = event.payload[:key] || event.payload[:path]
human_name = #{method.to_s.humanize.inspect}
info("\#{human_name} \#{key_or_path} \#{"(%.1fms)" % event.duration}")
info("\#{human_name} \#{key_or_path} (%.1fms)" % event.duration)
end
METHOD
end

View File

@@ -12,7 +12,7 @@ module ActionController
#
class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
def initialize(klass, *args, &block)
def initialize(klass, *args)
options = args.extract_options!
@only = Array(options.delete(:only)).map(&:to_s)
@except = Array(options.delete(:except)).map(&:to_s)
@@ -36,88 +36,35 @@ module ActionController
action = action.to_s
raise "MiddlewareStack#build requires an app" unless app
middlewares.reverse.inject(app) do |a, middleware|
reverse.inject(app) do |a, middleware|
middleware.valid?(action) ?
middleware.build(a) : a
end
end
end
# <tt>ActionController::Metal</tt> is the simplest possible controller, providing a
# valid Rack interface without the additional niceties provided by
# <tt>ActionController::Base</tt>.
#
# A sample metal controller might look like this:
#
# class HelloController < ActionController::Metal
# def index
# self.response_body = "Hello World!"
# end
# end
#
# And then to route requests to your metal controller, you would add
# something like this to <tt>config/routes.rb</tt>:
#
# match 'hello', :to => HelloController.action(:index)
#
# The +action+ method returns a valid Rack application for the \Rails
# router to dispatch to.
#
# == Rendering Helpers
#
# <tt>ActionController::Metal</tt> by default provides no utilities for rendering
# views, partials, or other responses aside from explicitly calling of
# <tt>response_body=</tt>, <tt>content_type=</tt>, and <tt>status=</tt>. To
# add the render helpers you're used to having in a normal controller, you
# can do the following:
#
# class HelloController < ActionController::Metal
# include ActionController::Rendering
# append_view_path "#{Rails.root}/app/views"
#
# def index
# render "hello/index"
# end
# end
#
# == Redirection Helpers
#
# To add redirection helpers to your metal controller, do the following:
#
# class HelloController < ActionController::Metal
# include ActionController::Redirecting
# include Rails.application.routes.url_helpers
#
# def index
# redirect_to root_url
# end
# end
#
# == Other Helpers
#
# You can refer to the modules included in <tt>ActionController::Base</tt> to see
# other features you can bring into your metal controller.
# ActionController::Metal provides a way to get a valid Rack application from a controller.
#
# In AbstractController, dispatching is triggered directly by calling #process on a new controller.
# ActionController::Metal provides an #action method that returns a valid Rack application for a
# given action. Other rack builders, such as Rack::Builder, Rack::URLMap, and the Rails router,
# can dispatch directly to the action returned by FooController.action(:index).
class Metal < AbstractController::Base
abstract!
attr_internal_writer :env
def env
@_env ||= {}
end
attr_internal :env
# Returns the last part of the controller's name, underscored, without the ending
# <tt>Controller</tt>. For instance, PostsController returns <tt>posts</tt>.
# Namespaces are left out, so Admin::PostsController returns <tt>posts</tt> as well.
# "Controller". For instance, MyApp::MyPostsController would return "my_posts" for
# controller_name
#
# ==== Returns
# * <tt>string</tt>
# String
def self.controller_name
@controller_name ||= self.name.demodulize.sub(/Controller$/, '').underscore
end
# Delegates to the class' <tt>controller_name</tt>
# Delegates to the class' #controller_name
def controller_name
self.class.controller_name
end
@@ -131,12 +78,9 @@ module ActionController
attr_internal :headers, :response, :request
delegate :session, :to => "@_request"
def initialize
def initialize(*)
@_headers = {"Content-Type" => "text/html"}
@_status = 200
@_request = nil
@_response = nil
@_routes = nil
super
end
@@ -168,11 +112,6 @@ module ActionController
headers["Location"] = url
end
# basic url_for that can be overridden for more robust functionality
def url_for(string)
string
end
def status
@_status
end
@@ -182,11 +121,12 @@ module ActionController
end
def response_body=(val)
body = val.nil? ? nil : (val.respond_to?(:each) ? val : [val])
body = val.respond_to?(:each) ? val : [val]
super body
end
def dispatch(name, request) #:nodoc:
# :api: private
def dispatch(name, request)
@_request = request
@_env = request.env
@_env['action_controller.instance'] = self
@@ -194,30 +134,27 @@ module ActionController
to_a
end
def to_a #:nodoc:
# :api: private
def to_a
response ? response.to_a : [status, headers, response_body]
end
class_attribute :middleware_stack
self.middleware_stack = ActionController::MiddlewareStack.new
def self.inherited(base) #nodoc:
def self.inherited(base)
base.middleware_stack = self.middleware_stack.dup
super
end
# Adds given middleware class and its args to bottom of middleware_stack
def self.use(*args, &block)
middleware_stack.use(*args, &block)
def self.use(*args)
middleware_stack.use(*args)
end
# Alias for middleware_stack
def self.middleware
middleware_stack
end
# Makes the controller a rack endpoint that points to the action in
# the given env's action_dispatch.request.path_parameters key.
def self.call(env)
action(env['action_dispatch.request.path_parameters'][:action]).call(env)
end
@@ -227,10 +164,10 @@ module ActionController
# for the same action.
#
# ==== Parameters
# * <tt>action</tt> - An action name
# action<#to_s>:: An action name
#
# ==== Returns
# * <tt>proc</tt> - A rack application
# Proc:: A rack application
def self.action(name, klass = ActionDispatch::Request)
middleware_stack.build(name.to_s) do |env|
new.dispatch(name, klass.new(env))

View File

@@ -5,6 +5,9 @@ module ActionController
class ::ActionController::ActionControllerError < StandardError #:nodoc:
end
module ClassMethods
end
# Temporary hax
included do
::ActionController::UnknownAction = ::AbstractController::ActionNotFound
@@ -18,10 +21,13 @@ module ActionController
delegate :default_charset=, :to => "ActionDispatch::Response"
end
self.protected_instance_variables = %w(
@_status @_headers @_params @_env @_response @_request
@_view_runtime @_stream @_url_options @_action_has_layout
)
# TODO: Update protected instance variables list
config_accessor :protected_instance_variables
self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render
@variables_added @request_origin @url
@parent_controller @action_name
@before_filter_chain_aborted @_headers @_params
@_response)
def rescue_action(env)
raise env["action_dispatch.rescue.exception"]
@@ -33,6 +39,12 @@ module ActionController
def assign_shortcuts(*) end
def _normalize_options(options)
if options[:action] && options[:action].to_s.include?(?/)
ActiveSupport::Deprecation.warn "Giving a path to render :action is deprecated. " <<
"Please use render :template instead", caller
options[:template] = options.delete(:action)
end
options[:text] = nil if options.delete(:nothing) == true
options[:text] = " " if options.key?(:text) && options[:text].nil?
super

View File

@@ -6,7 +6,7 @@ module ActionController
include Head
# Sets the etag, last_modified, or both on the response and renders a
# <tt>304 Not Modified</tt> response if the request is already fresh.
# "304 Not Modified" response if the request is already fresh.
#
# Parameters:
# * <tt>:etag</tt>
@@ -17,11 +17,11 @@ module ActionController
#
# def show
# @article = Article.find(params[:id])
# fresh_when(:etag => @article, :last_modified => @article.created_at, :public => true)
# fresh_when(:etag => @article, :last_modified => @article.created_at.utc, :public => true)
# end
#
# This will render the show template if the request isn't sending a matching etag or
# If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
# If-Modified-Since header and just a "304 Not Modified" response if there's a match.
#
def fresh_when(options)
options.assert_valid_keys(:etag, :last_modified, :public)
@@ -36,7 +36,7 @@ module ActionController
# Sets the etag and/or last_modified on the response and checks it against
# the client request. If the request doesn't match the options provided, the
# request is considered stale and should be generated from scratch. Otherwise,
# it's fresh and we don't need to generate anything and a reply of <tt>304 Not Modified</tt> is sent.
# it's fresh and we don't need to generate anything and a reply of "304 Not Modified" is sent.
#
# Parameters:
# * <tt>:etag</tt>
@@ -48,7 +48,7 @@ module ActionController
# def show
# @article = Article.find(params[:id])
#
# if stale?(:etag => @article, :last_modified => @article.created_at)
# if stale?(:etag => @article, :last_modified => @article.created_at.utc)
# @statistics = @article.really_expensive_call
# respond_to do |format|
# # all the supported formats
@@ -60,13 +60,13 @@ module ActionController
!request.fresh?(response)
end
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a <tt>private</tt> instruction, so that
# intermediate caches must not cache the response.
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that
# intermediate caches shouldn't cache the response.
#
# Examples:
# expires_in 20.minutes
# expires_in 3.hours, :public => true
# expires_in 3.hours, 'max-stale' => 5.hours, :public => true
# expires in 3.hours, 'max-stale' => 5.hours, :public => true
#
# This method will overwrite an existing Cache-Control header.
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
@@ -77,7 +77,7 @@ module ActionController
response.cache_control[:extras] = options.map {|k,v| "#{k}=#{v}"}
end
# Sets a HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should occur by the browser or
# Sets a HTTP 1.1 Cache-Control header of "no-cache" so no caching should occur by the browser or
# intermediate caches (like caching proxy servers).
def expires_now #:doc:
response.cache_control.replace(:no_cache => true)

View File

@@ -1,145 +0,0 @@
require 'active_support/core_ext/file/path'
module ActionController #:nodoc:
# Methods for sending arbitrary data and for streaming files to the browser,
# instead of rendering.
module DataStreaming
extend ActiveSupport::Concern
include ActionController::Rendering
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
:disposition => 'attachment'.freeze,
}.freeze
protected
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
# via the Rack::Sendfile middleware. The header to use is set via
# config.action_dispatch.x_sendfile_header.
# Your server can also configure this for you by setting the X-Sendfile-Type header.
#
# Be careful to sanitize the path parameter if it is coming from a web
# page. <tt>send_file(params[:path])</tt> allows a malicious user to
# download any file on your server.
#
# Options:
# * <tt>:filename</tt> - suggests a filename for the browser to use.
# Defaults to <tt>File.basename(path)</tt>.
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
# Valid values are 'inline' and 'attachment' (default).
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
# the URL, which is necessary for i18n filenames on certain browsers
# (setting <tt>:filename</tt> overrides this option).
#
# The default Content-Type and Content-Disposition headers are
# set to download arbitrary binary files in as many browsers as
# possible. IE versions 4, 5, 5.5, and 6 are all known to have
# a variety of quirks (especially when downloading over SSL).
#
# Simple download:
#
# send_file '/path/to.zip'
#
# Show a JPEG in the browser:
#
# send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
#
# Show a 404 page in the browser:
#
# send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
#
# Read about the other Content-* HTTP headers if you'd like to
# provide the user with more information (such as Content-Description) in
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
#
# Also be aware that the document may be cached by proxies and browsers.
# The Pragma and Cache-Control headers declare how the file may be cached
# by intermediaries. They default to require clients to validate with
# the server before releasing cached responses. See
# http://www.mnot.net/cache_docs/ for an overview of web caching and
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
# for the Cache-Control header spec.
def send_file(path, options = {}) #:doc:
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
send_file_headers! options
self.status = options[:status] || 200
self.content_type = options[:content_type] if options.key?(:content_type)
self.response_body = File.open(path, "rb")
end
# Sends the given binary data to the browser. This method is similar to
# <tt>render :text => data</tt>, but also allows you to specify whether
# the browser should display the response as a file attachment (i.e. in a
# download dialog) or as inline data. You may also set the content type,
# the apparent file name, and other things.
#
# Options:
# * <tt>:filename</tt> - suggests a filename for the browser to use.
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
# Valid values are 'inline' and 'attachment' (default).
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
#
# Generic data download:
#
# send_data buffer
#
# Download a dynamically-generated tarball:
#
# send_data generate_tgz('dir'), :filename => 'dir.tgz'
#
# Display an image Active Record in the browser:
#
# send_data image.data, :type => image.content_type, :disposition => 'inline'
#
# See +send_file+ for more information on HTTP Content-* headers and caching.
def send_data(data, options = {}) #:doc:
send_file_headers! options.dup
render options.slice(:status, :content_type).merge(:text => data)
end
private
def send_file_headers!(options)
options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options))
[:type, :disposition].each do |arg|
raise ArgumentError, ":#{arg} option required" if options[arg].nil?
end
disposition = options[:disposition]
disposition += %(; filename="#{options[:filename]}") if options[:filename]
content_type = options[:type]
if content_type.is_a?(Symbol)
extension = Mime[content_type]
raise ArgumentError, "Unknown MIME type #{options[:type]}" unless extension
self.content_type = extension
else
self.content_type = content_type
end
headers.merge!(
'Content-Disposition' => disposition,
'Content-Transfer-Encoding' => 'binary'
)
response.sending_file = true
# Fix a problem with IE 6.0 on opening downloaded files:
# If Cache-Control: no-cache is set (which Rails does by default),
# IE removes the file it just downloaded from its cache immediately
# after it displays the "open/save" dialog, which means that if you
# hit "open" the file isn't there anymore when the application that
# is called for handling the download is run, so let's workaround that
response.cache_control[:public] ||= false
end
end
end

View File

@@ -1,35 +0,0 @@
module ActionController
# This module provides a method which will redirects browser to use HTTPS
# protocol. This will ensure that user's sensitive information will be
# transferred safely over the internet. You _should_ always force browser
# to use HTTPS when you're transferring sensitive information such as
# user authentication, account information, or credit card information.
#
# Note that if you really concern about your application safety, you might
# consider using +config.force_ssl+ in your configuration config file instead.
# That will ensure all the data transferred via HTTPS protocol and prevent
# user from getting session hijacked when accessing the site under unsecured
# HTTP protocol.
module ForceSSL
extend ActiveSupport::Concern
include AbstractController::Callbacks
module ClassMethods
# Force the request to this particular controller or specified actions to be
# under HTTPS protocol.
#
# Note that this method will not be effective on development environment.
#
# ==== Options
# * <tt>only</tt> - The callback should be run only for this action
# * <tt>except<tt> - The callback should be run for all actions except this action
def force_ssl(options = {})
before_filter(options) do
if !request.ssl? && !Rails.env.development?
redirect_to :protocol => 'https://', :status => :moved_permanently
end
end
end
end
end
end

View File

@@ -2,6 +2,8 @@ module ActionController
module Head
extend ActiveSupport::Concern
include ActionController::UrlFor
# Return a response that has no content (merely headers). The options
# argument is interpreted to be a hash of header names and values.
# This allows you to easily return a response that consists only of
@@ -9,8 +11,6 @@ module ActionController
#
# head :created, :location => person_path(@person)
#
# head :created, :location => @person
#
# It can also be used to return exceptional conditions:
#
# return head(:method_not_allowed) unless request.post?
@@ -22,13 +22,13 @@ module ActionController
location = options.delete(:location)
options.each do |key, value|
headers[key.to_s.dasherize.split('-').each { |v| v[0] = v[0].chr.upcase }.join('-')] = value.to_s
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
end
self.status = status
self.location = url_for(location) if location
self.content_type = Mime[formats.first] if formats
self.content_type = Mime[formats.first]
self.response_body = " "
end
end
end
end

View File

@@ -2,21 +2,21 @@ require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/attribute'
module ActionController
# The \Rails framework provides a large number of helpers for working with assets, dates, forms,
# numbers and model objects, to name a few. These helpers are available to all templates
# The Rails framework provides a large number of helpers for working with +assets+, +dates+, +forms+,
# +numbers+ and model objects, to name a few. These helpers are available to all templates
# by default.
#
# In addition to using the standard template helpers provided, creating custom helpers to
# In addition to using the standard template helpers provided in the Rails framework, creating custom helpers to
# extract complicated logic or reusable functionality is strongly encouraged. By default, the controller will
# include a helper whose name matches that of the controller, e.g., <tt>MyController</tt> will automatically
# include <tt>MyHelper</tt>.
#
# Additional helpers can be specified using the +helper+ class method in ActionController::Base or any
# Additional helpers can be specified using the +helper+ class method in <tt>ActionController::Base</tt> or any
# controller which inherits from it.
#
# ==== Examples
# The +to_s+ method from the \Time class can be wrapped in a helper method to display a custom message if
# a \Time object is blank:
# The +to_s+ method from the Time class can be wrapped in a helper method to display a custom message if
# the Time object is blank:
#
# module FormattedTimeHelper
# def format_time(time, format=:long, blank_message="&nbsp;")
@@ -53,20 +53,30 @@ module ActionController
include AbstractController::Helpers
included do
config_accessor :helpers_path, :include_all_helpers
config_accessor :helpers_path
self.helpers_path ||= []
self.include_all_helpers = true
end
module ClassMethods
def helpers_dir
ActiveSupport::Deprecation.warn "helpers_dir is deprecated, use helpers_path instead", caller
self.helpers_path
end
def helpers_dir=(value)
ActiveSupport::Deprecation.warn "helpers_dir= is deprecated, use helpers_path= instead", caller
self.helpers_path = Array.wrap(value)
end
# Declares helper accessors for controller attributes. For example, the
# following adds new +name+ and <tt>name=</tt> instance methods to a
# controller and makes them available to the view:
# attr_accessor :name
# helper_attr :name
# attr_accessor :name
#
# ==== Parameters
# * <tt>attrs</tt> - Names of attributes to be converted into helpers.
# *attrs<Array[String, Symbol]>:: Names of attributes to be converted
# into helpers.
def helper_attr(*attrs)
attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
end
@@ -76,35 +86,32 @@ module ActionController
@helper_proxy ||= ActionView::Base.new.extend(_helpers)
end
# Overwrite modules_for_helpers to accept :all as argument, which loads
# all helpers in helpers_path.
#
# ==== Parameters
# * <tt>args</tt> - A list of helpers
#
# ==== Returns
# * <tt>array</tt> - A normalized list of modules for the list of helpers provided.
def modules_for_helpers(args)
args += all_application_helpers if args.delete(:all)
super(args)
end
def all_helpers_from_path(path)
helpers = []
Array.wrap(path).each do |_path|
extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
helpers += Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
end
helpers.sort!
helpers.uniq!
helpers
end
private
# Extract helper names from files in <tt>app/helpers/**/*_helper.rb</tt>
def all_application_helpers
all_helpers_from_path(helpers_path)
end
# Overwrite modules_for_helpers to accept :all as argument, which loads
# all helpers in helpers_dir.
#
# ==== Parameters
# args<Array[String, Symbol, Module, all]>:: A list of helpers
#
# ==== Returns
# Array[Module]:: A normalized list of modules for the list of
# helpers provided.
def modules_for_helpers(args)
args += all_application_helpers if args.delete(:all)
super(args)
end
# Extract helper names from files in app/helpers/**/*_helper.rb
def all_application_helpers
helpers = []
Array.wrap(helpers_path).each do |path|
extract = /^#{Regexp.quote(path.to_s)}\/?(.*)_helper.rb$/
helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
end
helpers.sort!
helpers.uniq!
helpers
end
end
end
end

View File

@@ -1,7 +1,8 @@
require 'active_support/core_ext/class/attribute'
module ActionController
# Adds the ability to prevent public methods on a controller to be called as actions.
# ActionController::HideActions adds the ability to prevent public methods on a controller
# to be called as actions.
module HideActions
extend ActiveSupport::Concern
@@ -22,7 +23,7 @@ module ActionController
# Sets all of the actions passed in as hidden actions.
#
# ==== Parameters
# * <tt>args</tt> - A list of actions
# *args<#to_s>:: A list of actions
def hide_action(*args)
self.hidden_actions = hidden_actions.dup.merge(args.map(&:to_s)).freeze
end

View File

@@ -3,12 +3,14 @@ require 'active_support/core_ext/object/blank'
module ActionController
module HttpAuthentication
# Makes it dead easy to do HTTP \Basic and \Digest authentication.
# Makes it dead easy to do HTTP Basic authentication.
#
# === Simple \Basic example
# Simple Basic example:
#
# class PostsController < ApplicationController
# http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
# USER_NAME, PASSWORD = "dhh", "secret"
#
# before_filter :authenticate, :except => [ :index ]
#
# def index
# render :text => "Everyone can see me!"
@@ -17,11 +19,17 @@ module ActionController
# def edit
# render :text => "I'm only accessible if you know the password"
# end
# end
#
# === Advanced \Basic example
# private
# def authenticate
# authenticate_or_request_with_http_basic do |user_name, password|
# user_name == USER_NAME && password == PASSWORD
# end
# end
# end
#
# Here is a more advanced \Basic example where only Atom feeds and the XML API is protected by HTTP authentication,
#
# Here is a more advanced Basic example where only Atom feeds and the XML API is protected by HTTP authentication,
# the regular HTML interface is protected by a session approach:
#
# class ApplicationController < ActionController::Base
@@ -61,13 +69,13 @@ module ActionController
# assert_equal 200, status
# end
#
# === Simple \Digest example
# Simple Digest example:
#
# require 'digest/md5'
# class PostsController < ApplicationController
# REALM = "SuperSecret"
# USERS = {"dhh" => "secret", #plain text password
# "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
# "dap" => Digest:MD5::hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
#
# before_filter :authenticate, :except => [:index]
#
@@ -87,36 +95,22 @@ module ActionController
# end
# end
#
# === Notes
# NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password or the ha1 digest hash so the framework can appropriately
# hash to check the user's credentials. Returning +nil+ will cause authentication to fail.
# Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
# the password file or database is compromised, the attacker would be able to use the ha1 hash to
# authenticate as the user at this +realm+, but would not have the user's password to try using at
# other sites.
#
# The +authenticate_or_request_with_http_digest+ block must return the user's password
# or the ha1 digest hash so the framework can appropriately hash to check the user's
# credentials. Returning +nil+ will cause authentication to fail.
# On shared hosts, Apache sometimes doesn't pass authentication headers to
# FCGI instances. If your environment matches this description and you cannot
# authenticate, try this rule in your Apache setup:
#
# Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
# the password file or database is compromised, the attacker would be able to use the ha1 hash to
# authenticate as the user at this +realm+, but would not have the user's password to try using at
# other sites.
#
# In rare instances, web servers or front proxies strip authorization headers before
# they reach your application. You can debug this situation by logging all environment
# variables, and check for HTTP_AUTHORIZATION, amongst others.
# RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
module Basic
extend self
module ControllerMethods
extend ActiveSupport::Concern
module ClassMethods
def http_basic_authenticate_with(options = {})
before_filter(options.except(:name, :password, :realm)) do
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
name == options[:name] && password == options[:password]
end
end
end
end
def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
end
@@ -145,7 +139,7 @@ module ActionController
end
def encode_credentials(user_name, password)
"Basic #{ActiveSupport::Base64.encode64s("#{user_name}:#{password}")}"
"Basic #{ActiveSupport::Base64.encode64("#{user_name}:#{password}")}"
end
def authentication_request(controller, realm)
@@ -192,15 +186,12 @@ module ActionController
return false unless password
method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
uri = credentials[:uri][0,1] == '/' ? request.original_fullpath : request.original_url
uri = credentials[:uri][0,1] == '/' ? request.fullpath : request.url
[true, false].any? do |trailing_question_mark|
[true, false].any? do |password_is_ha1|
_uri = trailing_question_mark ? uri + "?" : uri
expected = expected_response(method, _uri, credentials, password, password_is_ha1)
expected == credentials[:response]
end
end
[true, false].any? do |password_is_ha1|
expected = expected_response(method, uri, credentials, password, password_is_ha1)
expected == credentials[:response]
end
end
end
@@ -219,7 +210,7 @@ module ActionController
def encode_credentials(http_method, credentials, password, password_is_ha1)
credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password, password_is_ha1)
"Digest " + credentials.sort_by {|x| x[0].to_s }.map {|v| "#{v[0]}='#{v[1]}'" }.join(', ')
"Digest " + credentials.sort_by {|x| x[0].to_s }.inject([]) {|a, v| a << "#{v[0]}='#{v[1]}'" }.join(', ')
end
def decode_credentials_header(request)
@@ -227,10 +218,11 @@ module ActionController
end
def decode_credentials(header)
HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}) do |hash, pair|
key, value = pair.split('=', 2)
[key.strip, value.to_s.gsub(/^"|"$/,'').delete('\'')]
end]
hash[key.strip.to_sym] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')
hash
end
end
def authentication_header(controller, realm)
@@ -383,6 +375,7 @@ module ActionController
#
# RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
module Token
extend self
module ControllerMethods
@@ -411,7 +404,7 @@ module ActionController
# Returns nil if no token is found.
def authenticate(controller, &login_procedure)
token, options = token_and_options(controller.request)
unless token.blank?
if !token.blank?
login_procedure.call(token, options)
end
end
@@ -421,19 +414,20 @@ module ActionController
# Authorization: Token token="abc", nonce="def"
# Then the returned token is "abc", and the options is {:nonce => "def"}
#
# request - ActionDispatch::Request instance with the current headers.
# request - ActionController::Request instance with the current headers.
#
# Returns an Array of [String, Hash] if a token is present.
# Returns nil if no token is found.
def token_and_options(request)
if header = request.authorization.to_s[/^Token (.*)/]
values = Hash[$1.split(',').map do |value|
value.strip! # remove any spaces between commas and values
key, value = value.split(/\=\"?/) # split key=value pairs
value.chomp!('"') # chomp trailing " in value
value.gsub!(/\\\"/, '"') # unescape remaining quotes
[key, value]
end]
values = $1.split(',').
inject({}) do |memo, value|
value.strip! # remove any spaces between commas and values
key, value = value.split(/\=\"?/) # split key=value pairs
value.chomp!('"') # chomp trailing " in value
value.gsub!(/\\\"/, '"') # unescape remaining quotes
memo.update(key => value)
end
[values.delete("token"), values.with_indifferent_access]
end
end
@@ -445,8 +439,9 @@ module ActionController
#
# Returns String.
def encode_credentials(token, options = {})
values = ["token=#{token.to_s.inspect}"] + options.map do |key, value|
"#{key}=#{value.to_s.inspect}"
values = ["token=#{token.to_s.inspect}"]
options.each do |key, value|
values << "#{key}=#{value.to_s.inspect}"
end
"Token #{values * ", "}"
end
@@ -462,5 +457,6 @@ module ActionController
controller.__send__ :render, :text => "HTTP Token: Access denied.\n", :status => :unauthorized
end
end
end
end

View File

@@ -1,19 +1,21 @@
module ActionController
module ImplicitRender
def send_action(method, *args)
def send_action(*)
ret = super
default_render unless response_body
ret
end
def default_render(*args)
render(*args)
def default_render
render
end
def method_for_action(action_name)
super || if template_exists?(action_name.to_s, _prefixes)
"default_render"
super || begin
if template_exists?(action_name.to_s, _prefix)
"default_render"
end
end
end
end
end
end

View File

@@ -14,12 +14,12 @@ module ActionController
attr_internal :view_runtime
def process_action(*args)
def process_action(action, *args)
raw_payload = {
:controller => self.class.name,
:action => self.action_name,
:params => request.filtered_parameters,
:format => request.format.try(:ref),
:formats => request.formats.map(&:to_sym),
:method => request.method,
:path => (request.fullpath rescue "unknown")
}
@@ -78,7 +78,7 @@ module ActionController
yield
end
# Every time after an action is processed, this method is invoked
# Everytime after an action is processed, this method is invoked
# with the payload, so you can add more information.
# :api: plugin
def append_info_to_payload(payload) #:nodoc:

View File

@@ -1,13 +1,10 @@
require 'abstract_controller/collector'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/object/inclusion'
module ActionController #:nodoc:
module MimeResponds
module MimeResponds #:nodoc:
extend ActiveSupport::Concern
include ActionController::ImplicitRender
included do
class_attribute :responder, :mimes_for_respond_to
self.responder = ActionController::Responder
@@ -35,10 +32,10 @@ module ActionController #:nodoc:
# and all actions except <tt>:edit</tt> respond to <tt>:xml</tt> and
# <tt>:json</tt>.
#
# respond_to :json, :only => :create
# respond_to :rjs, :only => :create
#
# This specifies that the <tt>:create</tt> action and no other responds
# to <tt>:json</tt>.
# to <tt>:rjs</tt>.
def respond_to(*mimes)
options = mimes.extract_options!
@@ -66,13 +63,13 @@ module ActionController #:nodoc:
# might look something like this:
#
# def index
# @people = Person.all
# @people = Person.find(:all)
# end
#
# Here's the same action, with web-service support baked in:
#
# def index
# @people = Person.all
# @people = Person.find(:all)
#
# respond_to do |format|
# format.html
@@ -108,8 +105,8 @@ module ActionController #:nodoc:
# end
# end
#
# If the client wants HTML, we just redirect them back to the person list. If they want JavaScript,
# then it is an Ajax request and we render the JavaScript template associated with this action.
# If the client wants HTML, we just redirect them back to the person list. If they want Javascript
# (format.js), then it is an RJS request and we render the RJS template associated with this action.
# Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
# include the person's company in the rendered XML, so you get something like this:
#
@@ -158,7 +155,7 @@ module ActionController #:nodoc:
# Respond to also allows you to specify a common block for different formats by using any:
#
# def index
# @people = Person.all
# @people = Person.find(:all)
#
# respond_to do |format|
# format.html
@@ -181,7 +178,7 @@ module ActionController #:nodoc:
# respond_to :html, :xml, :json
#
# def index
# @people = Person.all
# @people = Person.find(:all)
# respond_with(@person)
# end
# end
@@ -192,7 +189,7 @@ module ActionController #:nodoc:
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
if response = retrieve_response_from_mimes(mimes, &block)
response.call(nil)
response.call
end
end
@@ -211,8 +208,8 @@ module ActionController #:nodoc:
# It also accepts a block to be given. It's used to overwrite a default
# response:
#
# def create
# @user = User.new(params[:user])
# def destroy
# @user = User.find(params[:id])
# flash[:notice] = "User was successfully created." if @user.save
#
# respond_with(@user) do |format|
@@ -225,15 +222,12 @@ module ActionController #:nodoc:
# is quite simple (it just needs to respond to call), you can even give
# a proc to it.
#
# In order to use respond_with, first you need to declare the formats your
# controller responds to in the class level with a call to <tt>respond_to</tt>.
#
def respond_with(*resources, &block)
raise "In order to use respond_with, first you need to declare the formats your " <<
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
if response = retrieve_response_from_mimes(&block)
options = resources.size == 1 ? {} : resources.extract_options!
options = resources.extract_options!
options.merge!(:default_response => response)
(options.delete(:responder) || self.class.responder).call(self, resources, options)
end
@@ -251,9 +245,9 @@ module ActionController #:nodoc:
config = self.class.mimes_for_respond_to[mime]
if config[:except]
!action.in?(config[:except])
!config[:except].include?(action)
elsif config[:only]
action.in?(config[:only])
config[:only].include?(action)
else
true
end
@@ -263,9 +257,10 @@ module ActionController #:nodoc:
# Collects mimes and return the response for the negotiated format. Returns
# nil if :not_acceptable was sent to the client.
#
def retrieve_response_from_mimes(mimes=nil, &block) #:nodoc:
def retrieve_response_from_mimes(mimes=nil, &block)
collector = Collector.new { default_render }
mimes ||= collect_mimes_from_class_level
collector = Collector.new(mimes) { |options| default_render(options || {}) }
mimes.each { |mime| collector.send(mime) }
block.call(collector) if block_given?
if format = request.negotiate_mime(collector.order)
@@ -282,9 +277,8 @@ module ActionController #:nodoc:
include AbstractController::Collector
attr_accessor :order
def initialize(mimes, &block)
def initialize(&block)
@order, @responses, @default_response = [], {}, block
mimes.each { |mime| send(mime) }
end
def any(*args, &block)
@@ -297,7 +291,7 @@ module ActionController #:nodoc:
alias :all :any
def custom(mime_type, &block)
mime_type = Mime::Type.lookup(mime_type.to_s) unless mime_type.is_a?(Mime::Type)
mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
@order << mime_type
@responses[mime_type] ||= block
end

View File

@@ -1,234 +0,0 @@
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/module/anonymous'
require 'action_dispatch/http/mime_types'
module ActionController
# Wraps the parameters hash into a nested hash. This will allow clients to submit
# POST requests without having to specify any root elements.
#
# This functionality is enabled in +config/initializers/wrap_parameters.rb+
# and can be customized. If you are upgrading to \Rails 3.1, this file will
# need to be created for the functionality to be enabled.
#
# You could also turn it on per controller by setting the format array to
# a non-empty array:
#
# class UsersController < ApplicationController
# wrap_parameters :format => [:json, :xml]
# end
#
# If you enable +ParamsWrapper+ for +:json+ format, instead of having to
# send JSON parameters like this:
#
# {"user": {"name": "Konata"}}
#
# You can send parameters like this:
#
# {"name": "Konata"}
#
# And it will be wrapped into a nested hash with the key name matching the
# controller's name. For example, if you're posting to +UsersController+,
# your new +params+ hash will look like this:
#
# {"name" => "Konata", "user" => {"name" => "Konata"}}
#
# You can also specify the key in which the parameters should be wrapped to,
# and also the list of attributes it should wrap by using either +:include+ or
# +:exclude+ options like this:
#
# class UsersController < ApplicationController
# wrap_parameters :person, :include => [:username, :password]
# end
#
# If you're going to pass the parameters to an +ActiveModel+ object (such as
# +User.new(params[:user])+), you might consider passing the model class to
# the method instead. The +ParamsWrapper+ will actually try to determine the
# list of attribute names from the model and only wrap those attributes:
#
# class UsersController < ApplicationController
# wrap_parameters Person
# end
#
# You still could pass +:include+ and +:exclude+ to set the list of attributes
# you want to wrap.
#
# By default, if you don't specify the key in which the parameters would be
# wrapped to, +ParamsWrapper+ will actually try to determine if there's
# a model related to it or not. This controller, for example:
#
# class Admin::UsersController < ApplicationController
# end
#
# will try to check if +Admin::User+ or +User+ model exists, and use it to
# determine the wrapper key respectively. If both models don't exist,
# it will then fallback to use +user+ as the key.
module ParamsWrapper
extend ActiveSupport::Concern
EXCLUDE_PARAMETERS = %w(authenticity_token _method utf8)
included do
class_attribute :_wrapper_options
self._wrapper_options = { :format => [] }
end
module ClassMethods
# Sets the name of the wrapper key, or the model which +ParamsWrapper+
# would use to determine the attribute names from.
#
# ==== Examples
# wrap_parameters :format => :xml
# # enables the parameter wrapper for XML format
#
# wrap_parameters :person
# # wraps parameters into +params[:person]+ hash
#
# wrap_parameters Person
# # wraps parameters by determining the wrapper key from Person class
# (+person+, in this case) and the list of attribute names
#
# wrap_parameters :include => [:username, :title]
# # wraps only +:username+ and +:title+ attributes from parameters.
#
# wrap_parameters false
# # disables parameters wrapping for this controller altogether.
#
# ==== Options
# * <tt>:format</tt> - The list of formats in which the parameters wrapper
# will be enabled.
# * <tt>:include</tt> - The list of attribute names which parameters wrapper
# will wrap into a nested hash.
# * <tt>:exclude</tt> - The list of attribute names which parameters wrapper
# will exclude from a nested hash.
def wrap_parameters(name_or_model_or_options, options = {})
model = nil
case name_or_model_or_options
when Hash
options = name_or_model_or_options
when false
options = options.merge(:format => [])
when Symbol, String
options = options.merge(:name => name_or_model_or_options)
else
model = name_or_model_or_options
end
_set_wrapper_defaults(_wrapper_options.slice(:format).merge(options), model)
end
# Sets the default wrapper key or model which will be used to determine
# wrapper key and attribute names. Will be called automatically when the
# module is inherited.
def inherited(klass)
if klass._wrapper_options[:format].present?
klass._set_wrapper_defaults(klass._wrapper_options.slice(:format))
end
super
end
protected
# Determine the wrapper model from the controller's name. By convention,
# this could be done by trying to find the defined model that has the
# same singularize name as the controller. For example, +UsersController+
# will try to find if the +User+ model exists.
#
# This method also does namespace lookup. Foo::Bar::UsersController will
# try to find Foo::Bar::User, Foo::User and finally User.
def _default_wrap_model #:nodoc:
return nil if self.anonymous?
model_name = self.name.sub(/Controller$/, '').singularize
begin
model_klass = model_name.constantize
rescue NameError, ArgumentError => e
if e.message =~ /is not missing constant|uninitialized constant #{model_name}/
namespaces = model_name.split("::")
namespaces.delete_at(-2)
break if namespaces.last == model_name
model_name = namespaces.join("::")
else
raise
end
end until model_klass
model_klass
end
def _set_wrapper_defaults(options, model=nil)
options = options.dup
unless options[:include] || options[:exclude]
model ||= _default_wrap_model
if model.respond_to?(:attribute_names) && model.attribute_names.present?
options[:include] = model.attribute_names
end
end
unless options[:name] || self.anonymous?
model ||= _default_wrap_model
options[:name] = model ? model.to_s.demodulize.underscore :
controller_name.singularize
end
options[:include] = Array.wrap(options[:include]).collect(&:to_s) if options[:include]
options[:exclude] = Array.wrap(options[:exclude]).collect(&:to_s) if options[:exclude]
options[:format] = Array.wrap(options[:format])
self._wrapper_options = options
end
end
# Performs parameters wrapping upon the request. Will be called automatically
# by the metal call stack.
def process_action(*args)
if _wrapper_enabled?
wrapped_hash = _wrap_parameters request.request_parameters
wrapped_filtered_hash = _wrap_parameters request.filtered_parameters
# This will make the wrapped hash accessible from controller and view
request.parameters.merge! wrapped_hash
request.request_parameters.merge! wrapped_hash
# This will make the wrapped hash displayed in the log file
request.filtered_parameters.merge! wrapped_filtered_hash
end
super
end
private
# Returns the wrapper key which will use to stored wrapped parameters.
def _wrapper_key
_wrapper_options[:name]
end
# Returns the list of enabled formats.
def _wrapper_formats
_wrapper_options[:format]
end
# Returns the list of parameters which will be selected for wrapped.
def _wrap_parameters(parameters)
value = if include_only = _wrapper_options[:include]
parameters.slice(*include_only)
else
exclude = _wrapper_options[:exclude] || []
parameters.except(*(exclude + EXCLUDE_PARAMETERS))
end
{ _wrapper_key => value }
end
# Checks if we should perform parameters wrapping.
def _wrapper_enabled?
ref = request.content_mime_type.try(:ref)
_wrapper_formats.include?(ref) && _wrapper_key && !request.request_parameters[_wrapper_key]
end
end
end

View File

@@ -20,7 +20,6 @@ module ActionController
# * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
# * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
# * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
# * <tt>Proc</tt> - A block that will be executed in the controller's context. Should return any option accepted by +redirect_to+.
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
@@ -31,7 +30,6 @@ module ActionController
# redirect_to "/images/screenshot.jpg"
# redirect_to articles_url
# redirect_to :back
# redirect_to proc { edit_post_url(@post) }
#
# The redirection happens as a "302 Moved" header unless otherwise specified.
#
@@ -41,11 +39,7 @@ module ActionController
# redirect_to post_url(@post), :status => 301
# redirect_to :action=>'atom', :status => 302
#
# The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an
# integer, or a symbol representing the downcased, underscored and symbolized description.
# Note that the status code must be a 3xx HTTP code, or redirection will not occur.
#
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
#
# Examples:
@@ -54,7 +48,8 @@ module ActionController
# redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
# redirect_to { :action=>'atom' }, :alert => "Something serious happened"
#
# When using <tt>redirect_to :back</tt>, if there is no referrer, RedirectBackError will be raised. You may specify some fallback
# When using <tt>redirect_to :back</tt>, if there is no referrer,
# RedirectBackError will be raised. You may specify some fallback
# behavior for this case by rescuing RedirectBackError.
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
@@ -88,11 +83,9 @@ module ActionController
when :back
raise RedirectBackError unless refer = request.headers["Referer"]
refer
when Proc
_compute_redirect_to_location options.call
else
url_for(options)
end.gsub(/[\0\r\n]/, '')
end.gsub(/[\r\n]/, '')
end
end
end

View File

@@ -2,7 +2,6 @@ require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/object/blank'
module ActionController
# See <tt>Renderers.add</tt>
def self.add_renderer(key, &block)
Renderers.add(key, &block)
end
@@ -16,12 +15,30 @@ module ActionController
end
module ClassMethods
def _write_render_options
renderers = _renderers.map do |name, value|
<<-RUBY_EVAL
if options.key?(:#{name})
_process_options(options)
return _render_option_#{name}(options.delete(:#{name}), options)
end
RUBY_EVAL
end
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def _handle_render_options(options)
#{renderers.join}
end
RUBY_EVAL
end
def use_renderers(*args)
new = _renderers.dup
args.each do |key|
new[key] = RENDERERS[key]
end
self._renderers = new.freeze
_write_render_options
end
alias use_renderer use_renderers
end
@@ -30,82 +47,51 @@ module ActionController
_handle_render_options(options) || super
end
def _handle_render_options(options)
_renderers.each do |name, value|
if options.key?(name.to_sym)
_process_options(options)
return send("_render_option_#{name}", options.delete(name.to_sym), options)
end
end
nil
end
# Hash of available renderers, mapping a renderer name to its proc.
# Default keys are :json, :js, :xml.
RENDERERS = {}
# Adds a new renderer to call within controller actions.
# A renderer is invoked by passing its name as an option to
# <tt>AbstractController::Rendering#render</tt>. To create a renderer
# pass it a name and a block. The block takes two arguments, the first
# is the value paired with its key and the second is the remaining
# hash of options passed to +render+.
#
# === Example
# Create a csv renderer:
#
# ActionController::Renderers.add :csv do |obj, options|
# filename = options[:filename] || 'data'
# str = obj.respond_to?(:to_csv) ? obj.to_csv : obj.to_s
# send_data str, :type => Mime::CSV,
# :disposition => "attachment; filename=#{filename}.csv"
# end
#
# Note that we used Mime::CSV for the csv mime type as it comes with Rails.
# For a custom renderer, you'll need to register a mime type with
# <tt>Mime::Type.register</tt>.
#
# To use the csv renderer in a controller action:
#
# def show
# @csvable = Csvable.find(params[:id])
# respond_to do |format|
# format.html
# format.csv { render :csv => @csvable, :filename => @csvable.name }
# }
# end
# To use renderers and their mime types in more concise ways, see
# <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt> and
# <tt>ActionController::MimeResponds#respond_with</tt>
def self.add(key, &block)
define_method("_render_option_#{key}", &block)
RENDERERS[key] = block
All._write_render_options
end
module All
extend ActiveSupport::Concern
include Renderers
INCLUDED = []
included do
self._renderers = RENDERERS
_write_render_options
INCLUDED << self
end
def self._write_render_options
INCLUDED.each(&:_write_render_options)
end
end
add :json do |json, options|
json = json.to_json(options) unless json.kind_of?(String)
json = ActiveSupport::JSON.encode(json, options) unless json.respond_to?(:to_str)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
self.content_type ||= Mime::JSON
json
self.response_body = json
end
add :js do |js, options|
self.content_type ||= Mime::JS
js.respond_to?(:to_js) ? js.to_js(options) : js
self.response_body = js.respond_to?(:to_js) ? js.to_js(options) : js
end
add :xml do |xml, options|
self.content_type ||= Mime::XML
xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
end
add :update do |proc, options|
view_context = self.view_context
generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc)
self.content_type = Mime::JS
self.response_body = generator.to_s
end
end
end

View File

@@ -2,11 +2,12 @@ module ActionController
module Rendering
extend ActiveSupport::Concern
include ActionController::RackDelegation
include AbstractController::Rendering
# Before processing, set the request formats in current controller formats.
def process_action(*) #:nodoc:
self.formats = request.formats.map { |x| x.ref }
self.formats = request.formats.map { |x| x.to_sym }
super
end
@@ -18,48 +19,38 @@ module ActionController
response_body
end
# Overwrite render_to_string because body can now be set to a rack body.
def render_to_string(*)
if self.response_body = super
string = ""
response_body.each { |r| string << r }
string
end
ensure
self.response_body = nil
end
private
# Normalize arguments by catching blocks and setting them on :update.
def _normalize_args(action=nil, options={}, &blk) #:nodoc:
options = super
options[:update] = blk if block_given?
options
end
# Normalize both text and status options.
def _normalize_options(options) #:nodoc:
if options.key?(:text) && options[:text].respond_to?(:to_text)
options[:text] = options[:text].to_text
# Normalize arguments by catching blocks and setting them on :update.
def _normalize_args(action=nil, options={}, &blk) #:nodoc:
options = super
options[:update] = blk if block_given?
options
end
if options[:status]
options[:status] = Rack::Utils.status_code(options[:status])
# Normalize both text and status options.
def _normalize_options(options) #:nodoc:
if options.key?(:text) && options[:text].respond_to?(:to_text)
options[:text] = options[:text].to_text
end
if options[:status]
options[:status] = Rack::Utils.status_code(options[:status])
end
super
end
super
end
# Process controller specific options, as status, content-type and location.
def _process_options(options) #:nodoc:
status, content_type, location = options.values_at(:status, :content_type, :location)
# Process controller specific options, as status, content-type and location.
def _process_options(options) #:nodoc:
status, content_type, location = options.values_at(:status, :content_type, :location)
self.status = status if status
self.content_type = content_type if content_type
self.headers["Location"] = url_for(location) if location
self.status = status if status
self.content_type = content_type if content_type
self.headers["Location"] = url_for(location) if location
super
end
super
end
end
end

View File

@@ -4,26 +4,45 @@ module ActionController #:nodoc:
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
end
# Controller actions are protected from Cross-Site Request Forgery (CSRF) attacks
# by including a token in the rendered html for your application. This token is
# stored as a random string in the session, to which an attacker does not have
# access. When a request reaches your application, \Rails verifies the received
# token with the token in the session. Only HTML and JavaScript requests are checked,
# so this will not protect your XML API (presumably you'll have a different
# authentication scheme there anyway). Also, GET requests are not protected as these
# should be idempotent.
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
# web application, not a forged link from another site, is done by embedding a token based on a random
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
# by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
# requests are checked, so this will not protect your XML API (presumably you'll have a different
# authentication scheme there anyway). Also, GET requests are not protected as these should be
# idempotent anyway.
#
# CSRF protection is turned on with the <tt>protect_from_forgery</tt> method,
# which checks the token and resets the session if it doesn't match what was expected.
# A call to this method is generated for new \Rails applications by default.
# You can customize the error message by editing public/422.html.
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
# ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
# error message in production by editing public/422.html. A call to this method in ApplicationController is
# generated by default in post-Rails 2.0 applications.
#
# The token parameter is named <tt>authenticity_token</tt> by default. The name and
# value of this token must be added to every layout that renders forms by including
# <tt>csrf_meta_tags</tt> in the html +head+.
# The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
# manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
# include a hidden field named like that and set its value to what is returned by
# <tt>form_authenticity_token</tt>.
#
# Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
# 1.x, add this to config/environments/test.rb:
#
# # Disable request forgery protection in test environment
# config.action_controller.allow_forgery_protection = false
#
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
#
# Here are some resources:
# * http://isc.sans.org/diary.html?storyid=1750
# * http://en.wikipedia.org/wiki/Cross-site_request_forgery
#
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
# There are a few guidelines you should follow:
#
# * Keep your GET requests safe and idempotent. More reading material:
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
# * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
# for "Expires: at end of session"
#
# Learn more about CSRF attacks and securing your application in the
# {Ruby on Rails Security Guide}[http://guides.rubyonrails.org/security.html].
module RequestForgeryProtection
extend ActiveSupport::Concern
@@ -52,52 +71,44 @@ module ActionController #:nodoc:
# class FooController < ApplicationController
# protect_from_forgery :except => :index
#
# You can disable csrf protection on controller-by-controller basis:
#
# skip_before_filter :verify_authenticity_token
#
# It can also be disabled for specific controller actions:
#
# skip_before_filter :verify_authenticity_token, :except => [:create]
# # you can disable csrf protection on controller-by-controller basis:
# skip_before_filter :verify_authenticity_token
# end
#
# Valid Options:
#
# * <tt>:only/:except</tt> - Passed to the <tt>before_filter</tt> call. Set which actions are verified.
# * <tt>:only/:except</tt> - Passed to the <tt>before_filter</tt> call. Set which actions are verified.
def protect_from_forgery(options = {})
self.request_forgery_protection_token ||= :authenticity_token
prepend_before_filter :verify_authenticity_token, options
before_filter :verify_authenticity_token, options
end
end
protected
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def protect_from_forgery(options = {})
self.request_forgery_protection_token ||= :authenticity_token
before_filter :verify_authenticity_token, options
end
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
unless verified_request?
logger.debug "WARNING: Can't verify CSRF token authenticity" if logger
handle_unverified_request
end
verified_request? || raise(ActionController::InvalidAuthenticityToken)
end
# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
reset_session
end
# Returns true or false if a request is verified. Checks:
# Returns true or false if a request is verified. Checks:
#
# * is the format restricted? By default, only HTML requests are checked.
# * is it a GET request? Gets should be safe and idempotent
# * Does the form_authenticity_token match the given token value from the params?
# * Does the X-CSRF-Token header match the form_authenticity_token
def verified_request?
!protect_against_forgery? || request.get? ||
form_authenticity_token == params[request_forgery_protection_token] ||
form_authenticity_token == request.headers['X-CSRF-Token']
!protect_against_forgery? || request.forgery_whitelisted? ||
form_authenticity_token == params[request_forgery_protection_token]
end
# Sets the token value for the current session.
def form_authenticity_token
session[:_csrf_token] ||= SecureRandom.base64(32)
session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32)
end
# The form's authenticity parameter. Override to provide your own.

View File

@@ -1,7 +1,7 @@
require 'active_support/json'
module ActionController #:nodoc:
# Responsible for exposing a resource to different mime requests,
# Responder is responsible for exposing a resource to different mime requests,
# usually depending on the HTTP verb. The responder is triggered when
# <code>respond_with</code> is called. The simplest case to study is a GET request:
#
@@ -24,10 +24,10 @@ module ActionController #:nodoc:
#
# === Builtin HTTP verb semantics
#
# The default \Rails responder holds semantics for each HTTP verb. Depending on the
# The default Rails responder holds semantics for each HTTP verb. Depending on the
# content type, verb and the resource status, it will behave differently.
#
# Using \Rails default responder, a POST request for creating an object could
# Using Rails default responder, a POST request for creating an object could
# be written as:
#
# def create
@@ -68,7 +68,7 @@ module ActionController #:nodoc:
# respond_with(@project, @task)
# end
#
# Giving several resources ensures that the responder will redirect to
# Giving an array of resources, you ensure that the responder will redirect to
# <code>project_task_url</code> instead of <code>task_url</code>.
#
# Namespaced and singleton resources require a symbol to be given, as in
@@ -77,42 +77,8 @@ module ActionController #:nodoc:
#
# respond_with(@project, :manager, @task)
#
# Note that if you give an array, it will be treated as a collection,
# so the following is not equivalent:
# Check <code>polymorphic_url</code> documentation for more examples.
#
# respond_with [@project, :manager, @task]
#
# === Custom options
#
# <code>respond_with</code> also allow you to pass options that are forwarded
# to the underlying render call. Those options are only applied success
# scenarios. For instance, you can do the following in the create method above:
#
# def create
# @project = Project.find(params[:project_id])
# @task = @project.comments.build(params[:task])
# flash[:notice] = 'Task was successfully created.' if @task.save
# respond_with(@project, @task, :status => 201)
# end
#
# This will return status 201 if the task was saved with success. If not,
# it will simply ignore the given options and return status 422 and the
# resource errors. To customize the failure scenario, you can pass a
# a block to <code>respond_with</code>:
#
# def create
# @project = Project.find(params[:project_id])
# @task = @project.comments.build(params[:task])
# respond_with(@project, @task, :status => 201) do |format|
# if @task.save
# flash[:notice] = 'Task was successfully created.'
# else
# format.html { render "some_special_template" }
# end
# end
# end
#
# Using <code>respond_with</code> with a block follows the same syntax as <code>respond_to</code>.
class Responder
attr_reader :controller, :request, :format, :resource, :resources, :options
@@ -149,7 +115,7 @@ module ActionController #:nodoc:
# Main entry point for responder responsible to dispatch to the proper format.
#
def respond
method = "to_#{format}"
method = :"to_#{format}"
respond_to?(method) ? send(method) : to_format
end
@@ -162,28 +128,19 @@ module ActionController #:nodoc:
navigation_behavior(e)
end
# to_js simply tries to render a template. If no template is found, raises the error.
def to_js
default_render
end
# All other formats follow the procedure below. First we try to render a
# template, if the template is not available, we verify if the resource
# responds to :to_format and display it.
#
def to_format
if get? || !has_errors?
default_render
else
display_errors
end
default_render
rescue ActionView::MissingTemplate => e
api_behavior(e)
end
protected
# This is the common behavior for formats associated with browsing, like :html, :iphone and so forth.
# This is the common behavior for "navigation" requests, like :html, :iphone and so forth.
def navigation_behavior(error)
if get?
raise error
@@ -194,16 +151,16 @@ module ActionController #:nodoc:
end
end
# This is the common behavior for formats associated with APIs, such as :xml and :json.
# This is the common behavior for "API" requests, like :xml and :json.
def api_behavior(error)
raise error unless resourceful?
if get?
display resource
elsif has_errors?
display resource.errors, :status => :unprocessable_entity
elsif post?
display resource, :status => :created, :location => api_location
elsif has_empty_resource_definition?
display empty_resource, :status => :ok
else
head :ok
end
@@ -212,7 +169,7 @@ module ActionController #:nodoc:
# Checks whether the resource responds to the current format or not.
#
def resourceful?
resource.respond_to?("to_#{format}")
resource.respond_to?(:"to_#{format}")
end
# Returns the resource location by retrieving it from the options or
@@ -228,7 +185,7 @@ module ActionController #:nodoc:
# controller.
#
def default_render
@default_response.call(options)
@default_response.call
end
# Display is just a shortcut to render a resource with the current format.
@@ -252,10 +209,6 @@ module ActionController #:nodoc:
controller.render given_options.merge!(options).merge!(format => resource)
end
def display_errors
controller.render format => resource.errors, :status => :unprocessable_entity
end
# Check whether the resource has errors.
#
def has_errors?
@@ -268,23 +221,5 @@ module ActionController #:nodoc:
def default_action
@action ||= ACTIONS_FOR_VERBS[request.request_method_symbol]
end
# Check whether resource needs a specific definition of empty resource to be valid
#
def has_empty_resource_definition?
respond_to?("empty_#{format}_resource", true)
end
# Delegate to proper empty resource method
#
def empty_resource
send("empty_#{format}_resource")
end
# Return a valid empty JSON resource
#
def empty_json_resource
"{}"
end
end
end

View File

@@ -1,254 +1,157 @@
require 'active_support/core_ext/file/path'
require 'rack/chunked'
module ActionController #:nodoc:
# Allows views to be streamed back to the client as they are rendered.
#
# The default way Rails renders views is by first rendering the template
# and then the layout. The response is sent to the client after the whole
# template is rendered, all queries are made, and the layout is processed.
#
# Streaming inverts the rendering flow by rendering the layout first and
# streaming each part of the layout as they are processed. This allows the
# header of the HTML (which is usually in the layout) to be streamed back
# to client very quickly, allowing JavaScripts and stylesheets to be loaded
# earlier than usual.
#
# This approach was introduced in Rails 3.1 and is still improving. Several
# Rack middlewares may not work and you need to be careful when streaming.
# Those points are going to be addressed soon.
#
# In order to use streaming, you will need to use a Ruby version that
# supports fibers (fibers are supported since version 1.9.2 of the main
# Ruby implementation).
#
# == Examples
#
# Streaming can be added to a given template easily, all you need to do is
# to pass the :stream option.
#
# class PostsController
# def index
# @posts = Post.scoped
# render :stream => true
# end
# end
#
# == When to use streaming
#
# Streaming may be considered to be overkill for lightweight actions like
# +new+ or +edit+. The real benefit of streaming is on expensive actions
# that, for example, do a lot of queries on the database.
#
# In such actions, you want to delay queries execution as much as you can.
# For example, imagine the following +dashboard+ action:
#
# def dashboard
# @posts = Post.all
# @pages = Page.all
# @articles = Article.all
# end
#
# Most of the queries here are happening in the controller. In order to benefit
# from streaming you would want to rewrite it as:
#
# def dashboard
# # Allow lazy execution of the queries
# @posts = Post.scoped
# @pages = Page.scoped
# @articles = Article.scoped
# render :stream => true
# end
#
# Notice that :stream only works with templates. Rendering :json
# or :xml with :stream won't work.
#
# == Communication between layout and template
#
# When streaming, rendering happens top-down instead of inside-out.
# Rails starts with the layout, and the template is rendered later,
# when its +yield+ is reached.
#
# This means that, if your application currently relies on instance
# variables set in the template to be used in the layout, they won't
# work once you move to streaming. The proper way to communicate
# between layout and template, regardless of whether you use streaming
# or not, is by using +content_for+, +provide+ and +yield+.
#
# Take a simple example where the layout expects the template to tell
# which title to use:
#
# <html>
# <head><title><%= yield :title %></title></head>
# <body><%= yield %></body>
# </html>
#
# You would use +content_for+ in your template to specify the title:
#
# <%= content_for :title, "Main" %>
# Hello
#
# And the final result would be:
#
# <html>
# <head><title>Main</title></head>
# <body>Hello</body>
# </html>
#
# However, if +content_for+ is called several times, the final result
# would have all calls concatenated. For instance, if we have the following
# template:
#
# <%= content_for :title, "Main" %>
# Hello
# <%= content_for :title, " page" %>
#
# The final result would be:
#
# <html>
# <head><title>Main page</title></head>
# <body>Hello</body>
# </html>
#
# This means that, if you have <code>yield :title</code> in your layout
# and you want to use streaming, you would have to render the whole template
# (and eventually trigger all queries) before streaming the title and all
# assets, which kills the purpose of streaming. For this reason Rails 3.1
# introduces a new helper called +provide+ that does the same as +content_for+
# but tells the layout to stop searching for other entries and continue rendering.
#
# For instance, the template above using +provide+ would be:
#
# <%= provide :title, "Main" %>
# Hello
# <%= content_for :title, " page" %>
#
# Giving:
#
# <html>
# <head><title>Main</title></head>
# <body>Hello</body>
# </html>
#
# That said, when streaming, you need to properly check your templates
# and choose when to use +provide+ and +content_for+.
#
# == Headers, cookies, session and flash
#
# When streaming, the HTTP headers are sent to the client right before
# it renders the first line. This means that, modifying headers, cookies,
# session or flash after the template starts rendering will not propagate
# to the client.
#
# If you try to modify cookies, session or flash, an +ActionDispatch::ClosedError+
# will be raised, showing those objects are closed for modification.
#
# == Middlewares
#
# Middlewares that need to manipulate the body won't work with streaming.
# You should disable those middlewares whenever streaming in development
# or production. For instance, +Rack::Bug+ won't work when streaming as it
# needs to inject contents in the HTML body.
#
# Also +Rack::Cache+ won't work with streaming as it does not support
# streaming bodies yet. Whenever streaming Cache-Control is automatically
# set to "no-cache".
#
# == Errors
#
# When it comes to streaming, exceptions get a bit more complicated. This
# happens because part of the template was already rendered and streamed to
# the client, making it impossible to render a whole exception page.
#
# Currently, when an exception happens in development or production, Rails
# will automatically stream to the client:
#
# "><script type="text/javascript">window.location = "/500.html"</script></html>
#
# The first two characters (">) are required in case the exception happens
# while rendering attributes for a given tag. You can check the real cause
# for the exception in your logger.
#
# == Web server support
#
# Not all web servers support streaming out-of-the-box. You need to check
# the instructions for each of them.
#
# ==== Unicorn
#
# Unicorn supports streaming but it needs to be configured. For this, you
# need to create a config file as follow:
#
# # unicorn.config.rb
# listen 3000, :tcp_nopush => false
#
# And use it on initialization:
#
# unicorn_rails --config-file unicorn.config.rb
#
# You may also want to configure other parameters like <tt>:tcp_nodelay</tt>.
# Please check its documentation for more information: http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-listen
#
# If you are using Unicorn with Nginx, you may need to tweak Nginx.
# Streaming should work out of the box on Rainbows.
#
# ==== Passenger
#
# To be described.
#
# Methods for sending arbitrary data and for streaming files to the browser,
# instead of rendering.
module Streaming
extend ActiveSupport::Concern
include AbstractController::Rendering
attr_internal :stream
include ActionController::Rendering
module ClassMethods
# Render streaming templates. It accepts :only, :except, :if and :unless as options
# to specify when to stream, as in ActionController filters.
def stream(options={})
ActiveSupport::Deprecation.warn "stream class method is deprecated. Please give the :stream option to render instead"
if defined?(Fiber)
before_filter :_stream_filter, options
else
raise "You cannot use streaming if Fiber is not available."
end
end
end
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
:disposition => 'attachment'.freeze,
}.freeze
protected
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
# via the Rack::Sendfile middleware. The header to use is set via
# config.action_dispatch.x_sendfile_header, and defaults to "X-Sendfile".
# Your server can also configure this for you by setting the X-Sendfile-Type header.
#
# Be careful to sanitize the path parameter if it is coming from a web
# page. <tt>send_file(params[:path])</tt> allows a malicious user to
# download any file on your server.
#
# Options:
# * <tt>:filename</tt> - suggests a filename for the browser to use.
# Defaults to <tt>File.basename(path)</tt>.
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
# Valid values are 'inline' and 'attachment' (default).
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
# the URL, which is necessary for i18n filenames on certain browsers
# (setting <tt>:filename</tt> overrides this option).
#
# The default Content-Type and Content-Disposition headers are
# set to download arbitrary binary files in as many browsers as
# possible. IE versions 4, 5, 5.5, and 6 are all known to have
# a variety of quirks (especially when downloading over SSL).
#
# Simple download:
#
# send_file '/path/to.zip'
#
# Show a JPEG in the browser:
#
# send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
#
# Show a 404 page in the browser:
#
# send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
#
# Read about the other Content-* HTTP headers if you'd like to
# provide the user with more information (such as Content-Description) in
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
#
# Also be aware that the document may be cached by proxies and browsers.
# The Pragma and Cache-Control headers declare how the file may be cached
# by intermediaries. They default to require clients to validate with
# the server before releasing cached responses. See
# http://www.mnot.net/cache_docs/ for an overview of web caching and
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
# for the Cache-Control header spec.
def send_file(path, options = {}) #:doc:
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
# Mark following render calls as streaming.
def _stream_filter #:nodoc:
self.stream = true
end
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
send_file_headers! options
# Consider the stream option when normalazing options.
def _normalize_options(options) #:nodoc:
super
options[:stream] = self.stream unless options.key?(:stream)
end
# Set proper cache control and transfer encoding when streaming
def _process_options(options) #:nodoc:
super
if options[:stream]
if env["HTTP_VERSION"] == "HTTP/1.0"
options.delete(:stream)
else
headers["Cache-Control"] ||= "no-cache"
headers["Transfer-Encoding"] = "chunked"
headers.delete("Content-Length")
if options[:x_sendfile]
ActiveSupport::Deprecation.warn(":x_sendfile is no longer needed in send_file", caller)
end
end
end
# Call render_to_body if we are streaming instead of usual +render+.
def _render_template(options) #:nodoc:
if options.delete(:stream)
Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
else
super
self.status = options[:status] || 200
self.content_type = options[:content_type] if options.key?(:content_type)
self.response_body = File.open(path, "rb")
end
# Sends the given binary data to the browser. This method is similar to
# <tt>render :text => data</tt>, but also allows you to specify whether
# the browser should display the response as a file attachment (i.e. in a
# download dialog) or as inline data. You may also set the content type,
# the apparent file name, and other things.
#
# Options:
# * <tt>:filename</tt> - suggests a filename for the browser to use.
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
# Valid values are 'inline' and 'attachment' (default).
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
#
# Generic data download:
#
# send_data buffer
#
# Download a dynamically-generated tarball:
#
# send_data generate_tgz('dir'), :filename => 'dir.tgz'
#
# Display an image Active Record in the browser:
#
# send_data image.data, :type => image.content_type, :disposition => 'inline'
#
# See +send_file+ for more information on HTTP Content-* headers and caching.
#
# <b>Tip:</b> if you want to stream large amounts of on-the-fly generated
# data to the browser, then use <tt>render :text => proc { ... }</tt>
# instead. See ActionController::Base#render for more information.
def send_data(data, options = {}) #:doc:
send_file_headers! options.dup
render options.slice(:status, :content_type).merge(:text => data)
end
private
def send_file_headers!(options)
options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options))
[:type, :disposition].each do |arg|
raise ArgumentError, ":#{arg} option required" if options[arg].nil?
end
if options.key?(:length)
ActiveSupport::Deprecation.warn("You do not need to provide the file's length", caller)
end
disposition = options[:disposition]
disposition += %(; filename="#{options[:filename]}") if options[:filename]
content_type = options[:type]
if content_type.is_a?(Symbol)
extension = Mime[content_type]
raise ArgumentError, "Unknown MIME type #{options[:type]}" unless extension
self.content_type = extension
else
self.content_type = content_type
end
headers.merge!(
'Content-Disposition' => disposition,
'Content-Transfer-Encoding' => 'binary'
)
response.sending_file = true
# Fix a problem with IE 6.0 on opening downloaded files:
# If Cache-Control: no-cache is set (which Rails does by default),
# IE removes the file it just downloaded from its cache immediately
# after it displays the "open/save" dialog, which means that if you
# hit "open" the file isn't there anymore when the application that
# is called for handling the download is run, so let's workaround that
response.cache_control[:public] ||= false
end
end
end
end

View File

@@ -4,11 +4,6 @@ module ActionController
include RackDelegation
def recycle!
@_url_options = nil
end
# TODO: Clean this up
def process_with_new_base_test(request, response)
@_request = request
@@ -19,9 +14,18 @@ module ActionController
cookies.write(@_response)
end
@_response.prepare!
set_test_assigns
ret
end
def set_test_assigns
@assigns = {}
(instance_variable_names - self.class.protected_instance_variables).each do |var|
name, value = var[1..-1], instance_variable_get(var)
@assigns[name] = value
end
end
# TODO : Rewrite tests using controller.headers= to use Rack env
def headers=(new_headers)
@_response ||= ActionDispatch::Response.new

View File

@@ -1,47 +1,28 @@
# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
# the <tt>_routes</tt> method. Otherwise, an exception will be raised.
#
# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
# url options like the +host+. In order to do so, this module requires the host class
# to implement +env+ and +request+, which need to be a Rack-compatible.
#
# Example:
#
# class RootUrl
# include ActionController::UrlFor
# include Rails.application.routes.url_helpers
#
# delegate :env, :request, :to => :controller
#
# def initialize(controller)
# @controller = controller
# @url = root_path # named route from the application.
# end
# end
#
module ActionController
module UrlFor
extend ActiveSupport::Concern
include AbstractController::UrlFor
include ActionDispatch::Routing::UrlFor
def url_options
@_url_options ||= super.reverse_merge(
:host => request.host,
:port => request.optional_port,
super.reverse_merge(
:host => request.host_with_port,
:protocol => request.protocol,
:_path_segments => request.symbolized_path_parameters
).freeze
if _routes.equal?(env["action_dispatch.routes"])
@_url_options.dup.tap do |options|
options[:script_name] = request.script_name.dup
options.freeze
end
else
@_url_options
end
).merge(:script_name => request.script_name)
end
def _routes
raise "In order to use #url_for, you must include routing helpers explicitly. " \
"For instance, `include Rails.application.routes.url_helpers"
end
module ClassMethods
def action_methods
@action_methods ||= begin
super - _routes.named_routes.helper_names
end
end
end
end
end

View File

@@ -2,13 +2,35 @@ require "rails"
require "action_controller"
require "action_dispatch/railtie"
require "action_view/railtie"
require "abstract_controller/railties/routes_helpers"
require "action_controller/railties/paths"
require "active_support/deprecation/proxy_wrappers"
require "active_support/deprecation"
module ActionController
class Railtie < Rails::Railtie
config.action_controller = ActiveSupport::OrderedOptions.new
config.action_controller.singleton_class.tap do |d|
d.send(:define_method, :session) do
ActiveSupport::Deprecation.warn "config.action_controller.session has been deprecated. " <<
"Please use Rails.application.config.session_store instead.", caller
end
d.send(:define_method, :session=) do |val|
ActiveSupport::Deprecation.warn "config.action_controller.session= has been deprecated. " <<
"Please use config.session_store(name, options) instead.", caller
end
d.send(:define_method, :session_store) do
ActiveSupport::Deprecation.warn "config.action_controller.session_store has been deprecated. " <<
"Please use Rails.application.config.session_store instead.", caller
end
d.send(:define_method, :session_store=) do |val|
ActiveSupport::Deprecation.warn "config.action_controller.session_store= has been deprecated. " <<
"Please use config.session_store(name, options) instead.", caller
end
end
initializer "action_controller.logger" do
ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
end
@@ -21,27 +43,24 @@ module ActionController
paths = app.config.paths
options = app.config.action_controller
options.assets_dir ||= paths["public"].first
options.javascripts_dir ||= paths["public/javascripts"].first
options.stylesheets_dir ||= paths["public/stylesheets"].first
options.page_cache_directory ||= paths["public"].first
# make sure readers methods get compiled
options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.assets_dir ||= paths.public.to_a.first
options.javascripts_dir ||= paths.public.javascripts.to_a.first
options.stylesheets_dir ||= paths.public.stylesheets.to_a.first
options.page_cache_directory ||= paths.public.to_a.first
options.helpers_path ||= paths.app.helpers.to_a
ActiveSupport.on_load(:action_controller) do
include app.routes.mounted_helpers
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
extend ::ActionController::Railties::Paths.with(app)
include app.routes.url_helpers
options.each { |k,v| send("#{k}=", v) }
end
end
initializer "action_controller.compile_config_methods" do
ActiveSupport.on_load(:action_controller) do
config.compile_methods! if config.respond_to?(:compile_methods!)
end
initializer "action_controller.deprecated_routes" do |app|
message = "ActionController::Routing::Routes is deprecated. " \
"Instead, use Rails.application.routes"
proxy = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(app.routes, message)
ActionController::Routing::Routes = proxy
end
end
end
end

View File

@@ -1,24 +0,0 @@
module ActionController
module Railties
module Paths
def self.with(app)
Module.new do
define_method(:inherited) do |klass|
super(klass)
if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) }
paths = namespace._railtie.paths["app/helpers"].existent
else
paths = app.config.helpers_paths
end
klass.helpers_path = paths
if klass.superclass == ActionController::Base && ActionController::Base.include_all_helpers
klass.helper :all
end
end
end
end
end
end
end

View File

@@ -18,12 +18,18 @@ module ActionController
# post = Post.find(params[:id])
# post.destroy
#
# redirect_to(post) # Calls polymorphic_url(post) which in turn calls post_url(post)
# respond_to do |format|
# format.html { redirect_to(post) } # Calls polymorphic_url(post) which in turn calls post_url(post)
# format.js do
# # Calls: new Effect.fade('post_45');
# render(:update) { |page| page[post].visual_effect(:fade) }
# end
# end
# end
#
# As the example above shows, you can stop caring to a large extent what the actual id of the post is.
# You just know that one is being assigned and that the subsequent calls in redirect_to expect that
# same naming convention and allows you to write less code if you follow it.
# As the example above shows, you can stop caring to a large extent what the actual id of the post is. You just know
# that one is being assigned and that the subsequent calls in redirect_to and the RJS expect that same naming
# convention and allows you to write less code if you follow it.
module RecordIdentifier
extend self

View File

@@ -1,8 +1,6 @@
require 'rack/session/abstract/id'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/anonymous'
module ActionController
module TemplateAssertions
@@ -42,13 +40,6 @@ module ActionController
ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
end
def process(*args)
@partials = Hash.new(0)
@templates = Hash.new(0)
@layouts = Hash.new(0)
super
end
# Asserts that the request was rendered with the appropriate template file or partials.
#
# ==== Examples
@@ -130,13 +121,13 @@ module ActionController
super
self.session = TestSession.new
self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => SecureRandom.hex(16))
self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => ActiveSupport::SecureRandom.hex(16))
end
class Result < ::Array #:nodoc:
def to_s() join '/' end
def self.new_escaped(strings)
new strings.collect {|str| uri_parser.unescape str}
new strings.collect {|str| URI.unescape str}
end
end
@@ -145,23 +136,15 @@ module ActionController
extra_keys = routes.extra_keys(parameters)
non_path_parameters = get? ? query_parameters : request_parameters
parameters.each do |key, value|
if value.is_a?(Array) && (value.frozen? || value.any?(&:frozen?))
value = value.map{ |v| v.duplicable? ? v.dup : v }
elsif value.is_a?(Hash) && (value.frozen? || value.any?{ |k,v| v.frozen? })
value = Hash[value.map{ |k,v| [k, v.duplicable? ? v.dup : v] }]
elsif value.frozen? && value.duplicable?
value = value.dup
if value.is_a? Fixnum
value = value.to_s
elsif value.is_a? Array
value = Result.new(value)
end
if extra_keys.include?(key.to_sym)
non_path_parameters[key] = value
else
if value.is_a?(Array)
value = Result.new(value.map(&:to_param))
else
value = value.to_param
end
path_parameters[key.to_s] = value
end
end
@@ -181,16 +164,12 @@ module ActionController
end
def recycle!
write_cookies!
@env.delete('HTTP_COOKIE') if @cookies.blank?
@env.delete('action_dispatch.cookies')
@cookies = nil
@formats = nil
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
@symbolized_path_params = nil
@method = @request_method = nil
@fullpath = @ip = @remote_ip = @protocol = nil
@fullpath = @ip = @remote_ip = nil
@env['action_dispatch.request.query_parameters'] = {}
end
end
@@ -208,23 +187,20 @@ module ActionController
end
end
class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
DEFAULT_OPTIONS = Rack::Session::Abstract::ID::DEFAULT_OPTIONS
class TestSession < ActionDispatch::Session::AbstractStore::SessionHash #:nodoc:
DEFAULT_OPTIONS = ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS
def initialize(session = {})
@env, @by = nil, nil
replace(session.stringify_keys)
@loaded = true
end
def exists?
true
end
def exists?; true; end
end
# Superclass for ActionController functional tests. Functional tests allow you to
# test a single controller action per test method. This should not be confused with
# integration tests (see ActionDispatch::IntegrationTest), which are more like
# integration tests (see ActionController::IntegrationTest), which are more like
# "stories" that can involve multiple controllers and multiple actions (i.e. multiple
# different HTTP requests).
#
@@ -269,7 +245,7 @@ module ActionController
# after calling +post+. If the various assert methods are not sufficient, then you
# may use this object to inspect the HTTP response in detail.
#
# (Earlier versions of \Rails required each functional test to subclass
# (Earlier versions of Rails required each functional test to subclass
# Test::Unit::TestCase and define @controller, @request, @response in +setup+.)
#
# == Controller is automatically inferred
@@ -282,7 +258,7 @@ module ActionController
# tests WidgetController
# end
#
# == \Testing controller internals
# == Testing controller internals
#
# In addition to these specific assertions, you also have easy access to various collections that the regular test/unit assertions
# can be used against. These collections are:
@@ -290,7 +266,7 @@ module ActionController
# * assigns: Instance variables assigned in the action that are available for the view.
# * session: Objects being saved in the session.
# * flash: The flash objects currently in the session.
# * cookies: \Cookies being sent to the user on this request.
# * cookies: Cookies being sent to the user on this request.
#
# These collections can be used just like any other hash:
#
@@ -314,13 +290,9 @@ module ActionController
# and cookies, though. For sessions, you just do:
#
# @request.session[:key] = "value"
# @request.cookies[:key] = "value"
# @request.cookies["key"] = "value"
#
# To clear the cookies for a test just clear the request's cookies hash:
#
# @request.cookies.clear
#
# == \Testing named routes
# == Testing named routes
#
# If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
# Example:
@@ -343,11 +315,11 @@ module ActionController
def controller_class=(new_class)
prepare_controller_class(new_class) if new_class
self._controller_class = new_class
write_inheritable_attribute(:controller_class, new_class)
end
def controller_class
if current_controller_class = self._controller_class
if current_controller_class = read_inheritable_attribute(:controller_class)
current_controller_class
else
self.controller_class = determine_default_controller_class(name)
@@ -401,24 +373,7 @@ module ActionController
end
alias xhr :xml_http_request
def paramify_values(hash_or_array_or_value)
case hash_or_array_or_value
when Hash
Hash[hash_or_array_or_value.map{|key, value| [key, paramify_values(value)] }]
when Array
hash_or_array_or_value.map {|i| paramify_values(i)}
when Rack::Test::UploadedFile
hash_or_array_or_value
else
hash_or_array_or_value.to_param
end
end
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
# Ensure that numbers and symbols passed as params are converted to
# proper params, as is the case when engaging rack.
parameters = paramify_values(parameters) if html_format?(parameters)
# Sanity check for required instance variables so we can give an
# understandable error message.
%w(@routes @controller @request @response).each do |iv_name|
@@ -437,23 +392,18 @@ module ActionController
@request.env['REQUEST_METHOD'] = http_method
parameters ||= {}
controller_class_name = @controller.class.anonymous? ?
"anonymous_controller" :
@controller.class.name.underscore.sub(/_controller$/, '')
@request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
@request.assign_parameters(@routes, controller_class_name, action.to_s, parameters)
@request.session = ActionController::TestSession.new(session) if session
@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = @request.flash.update(flash || {})
@request.session["flash"].sweep
@controller.request = @request
@controller.params.merge!(parameters)
build_request_uri(action, parameters)
@controller.class.class_eval { include Testing }
@controller.recycle!
Base.class_eval { include Testing }
@controller.process_with_new_base_test(@request, @response)
@assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
@request.session.delete('flash') if @request.session['flash'].blank?
@request.cookies.merge!(@response.cookies)
@response
end
@@ -467,7 +417,7 @@ module ActionController
@request.env.delete('PATH_INFO')
if defined?(@controller) && @controller
if @controller
@controller.request = @request
@controller.params = {}
end
@@ -481,7 +431,6 @@ module ActionController
included do
include ActionController::TemplateAssertions
include ActionDispatch::Assertions
class_attribute :_controller_class
setup :setup_controller_request_and_response
end
@@ -489,7 +438,7 @@ module ActionController
def build_request_uri(action, parameters)
unless @request.env["PATH_INFO"]
options = @controller.respond_to?(:url_options) ? @controller.__send__(:url_options).merge(parameters) : parameters
options = @controller.__send__(:url_options).merge(parameters)
options.update(
:only_path => true,
:action => action,
@@ -503,12 +452,6 @@ module ActionController
@request.env["QUERY_STRING"] = query_string || ""
end
end
def html_format?(parameters)
return true unless parameters.is_a?(Hash)
format = Mime[parameters[:format]]
format.nil? || format.html?
end
end
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
@@ -519,11 +462,9 @@ module ActionController
# The exception is stored in the exception accessor for further inspection.
module RaiseActionExceptions
def self.included(base)
unless base.method_defined?(:exception) && base.method_defined?(:exception=)
base.class_eval do
attr_accessor :exception
protected :exception, :exception=
end
base.class_eval do
attr_accessor :exception
protected :exception, :exception=
end
end

View File

@@ -4,7 +4,7 @@ require 'html/selector'
require 'html/sanitizer'
module HTML #:nodoc:
# A top-level HTML document. You give it a body of text, and it will parse that
# A top-level HTMl document. You give it a body of text, and it will parse that
# text into a tree of nodes.
class Document #:nodoc:

View File

@@ -18,14 +18,14 @@ module HTML #:nodoc:
hash[k] = Conditions.new(v)
when :children
hash[k] = v = keys_to_symbols(v)
v.each do |key,value|
case key
v.each do |k,v2|
case k
when :count, :greater_than, :less_than
# keys are valid, and require no further processing
when :only
v[key] = Conditions.new(value)
v[k] = Conditions.new(v2)
else
raise "illegal key #{key.inspect} => #{value.inspect}"
raise "illegal key #{k.inspect} => #{v2.inspect}"
end
end
else
@@ -38,14 +38,18 @@ module HTML #:nodoc:
private
def keys_to_strings(hash)
Hash[hash.keys.map {|k| [k.to_s, hash[k]]}]
hash.keys.inject({}) do |h,k|
h[k.to_s] = hash[k]
h
end
end
def keys_to_symbols(hash)
Hash[hash.keys.map do |k|
hash.keys.inject({}) do |h,k|
raise "illegal key #{k.inspect}" unless k.respond_to?(:to_sym)
[k.to_sym, hash[k]]
end]
h[k.to_sym] = hash[k]
h
end
end
end
@@ -73,7 +77,9 @@ module HTML #:nodoc:
# Return a textual representation of the node.
def to_s
@children.join()
s = ""
@children.each { |child| s << child.to_s }
s
end
# Return false (subclasses must override this to provide specific matching
@@ -156,7 +162,7 @@ module HTML #:nodoc:
end
closing = ( scanner.scan(/\//) ? :close : nil )
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[^\s!>\/]+/)
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[\w:-]+/)
name.downcase!
unless closing

View File

@@ -1,6 +1,5 @@
require 'set'
require 'cgi'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/class/inheritable_attributes'
module HTML
class Sanitizer
@@ -34,7 +33,7 @@ module HTML
result = super
# strip any comments, and if they have a newline at the end (ie. line with
# only a comment) strip that too
result = result.gsub(/<!--(.*?)-->[\n]?/m, "") if (result && result =~ /<!--(.*?)-->[\n]?/m)
result.gsub!(/<!--(.*?)-->[\n]?/m, "") if result
# Recurse - handle all dirty nested tags
result == text ? result : sanitize(result, options)
end
@@ -61,7 +60,7 @@ module HTML
class WhiteListSanitizer < Sanitizer
[:protocol_separator, :uri_attributes, :allowed_attributes, :allowed_tags, :allowed_protocols, :bad_tags,
:allowed_css_properties, :allowed_css_keywords, :shorthand_css_properties].each do |attr|
class_attribute attr, :instance_writer => false
class_inheritable_accessor attr, :instance_writer => false
end
# A regular expression of the valid characters used to separate protocols like
@@ -171,7 +170,7 @@ module HTML
def contains_bad_protocols?(attr_name, value)
uri_attributes.include?(attr_name) &&
(value =~ /(^[^\/:]*):|(&#0*58)|(&#x70)|(%|&#37;)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first.downcase))
(value =~ /(^[^\/:]*):|(&#0*58)|(&#x70)|(%|&#37;)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first))
end
end
end

View File

@@ -128,8 +128,6 @@ module HTML
# (no parent element).
# * <tt>:empty</tt> -- Match the element only if it has no child elements,
# and no text content.
# * <tt>:content(string)</tt> -- Match the element only if it has <tt>string</tt>
# as its text content (ignoring leading and trailing whitespace).
# * <tt>:only-child</tt> -- Match the element if it is the only child (element)
# of its parent element.
# * <tt>:only-of-type</tt> -- Match the element if it is the only child (element)

View File

@@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2011 David Heinemeier Hansson
# Copyright (c) 2004-2010 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -53,14 +53,12 @@ module ActionDispatch
autoload :Flash
autoload :Head
autoload :ParamsParser
autoload :Reloader
autoload :RemoteIp
autoload :Rescue
autoload :ShowExceptions
autoload :Static
end
autoload :ClosedError, 'action_dispatch/middleware/closed_error'
autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
autoload :Routing
@@ -87,7 +85,6 @@ module ActionDispatch
autoload_under 'testing' do
autoload :Assertions
autoload :Integration
autoload :IntegrationTest, 'action_dispatch/testing/integration'
autoload :PerformanceTest
autoload :TestProcess
autoload :TestRequest

View File

@@ -39,8 +39,22 @@ module ActionDispatch
end
module Response
attr_reader :cache_control, :etag
alias :etag? :etag
attr_reader :cache_control
def initialize(*)
status, header, body = super
@cache_control = {}
@etag = self["ETag"]
if cache_control = self["Cache-Control"]
cache_control.split(/,\s*/).each do |segment|
first, last = segment.split("=")
last ||= true
@cache_control[first.to_sym] = last
end
end
end
def last_modified
if last = headers['Last-Modified']
@@ -56,6 +70,14 @@ module ActionDispatch
headers['Last-Modified'] = utc_time.httpdate
end
def etag
@etag
end
def etag?
@etag
end
def etag=(etag)
key = ActiveSupport::Cache.expand_cache_key(etag)
@etag = self["ETag"] = %("#{Digest::MD5.hexdigest(key)}")
@@ -63,24 +85,31 @@ module ActionDispatch
private
def prepare_cache_control!
@cache_control = {}
@etag = self["ETag"]
if cache_control = self["Cache-Control"]
cache_control.split(/,\s*/).each do |segment|
first, last = segment.split("=")
@cache_control[first.to_sym] = last || true
end
end
end
def handle_conditional_get!
if etag? || last_modified? || !@cache_control.empty?
set_conditional_cache_control!
elsif nonempty_ok_response?
self.etag = body
if request && request.etag_matches?(etag)
self.status = 304
self.body = []
end
set_conditional_cache_control!
else
headers["Cache-Control"] = "no-cache"
end
end
def nonempty_ok_response?
@status == 200 && string_body?
end
def string_body?
!@blank && @body.respond_to?(:all?) && @body.all? { |part| part.is_a?(String) }
end
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
def set_conditional_cache_control!
@@ -90,7 +119,7 @@ module ActionDispatch
if control.empty?
headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
elsif control[:no_cache]
elsif @cache_control[:no_cache]
headers["Cache-Control"] = "no-cache"
else
extras = control[:extras]

Some files were not shown because too many files have changed in this diff Show More