Compare commits

...

337 Commits

Author SHA1 Message Date
Michael Koziarski
9c190098e0 Forgot railties changelog
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@8196 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-11-24 00:04:37 +00:00
Michael Koziarski
d421bb96f7 Prepare for 1.2.6
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@8195 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-11-24 00:01:30 +00:00
Michael Koziarski
63e968794a Merge [8176] to stable to fix session fixation attacks. Closes #10048 [theflow, Koz]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@8177 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-11-21 05:00:25 +00:00
Jeremy Kemper
65539c9f4d Merge [8046] from trunk: allow association redefinition in subclasses. References #9346.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@8048 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-27 21:15:17 +00:00
Jeremy Kemper
cf3e9664a4 Missed svn adds for [8042]. References #6466.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@8044 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-27 19:25:23 +00:00
Jeremy Kemper
1117d73787 Fix has_many :through delete with custom foreign keys. References #6466.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@8042 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-27 18:49:52 +00:00
Rick Olson
5285270dde merge [7978] from edge
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7979 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-20 17:35:12 +00:00
Jeremy Kemper
257d8605c9 Fix regression where the association would not construct new finder SQL on save causing bogus queries for "WHERE owner_id = NULL" even after owner was saved. References #8713.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7940 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-16 06:56:07 +00:00
David Heinemeier Hansson
a2f0af273b Mark for release now
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7844 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-12 16:29:23 +00:00
David Heinemeier Hansson
d201969236 Update versions for release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7841 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-12 04:00:21 +00:00
Michael Koziarski
f70b74a5bc Backport fix to allow :controller=>:some_symbol [norbert]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7838 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-11 21:56:19 +00:00
Jeremy Kemper
88f2284b32 Backport: allow array and hash query parameters. Array route parameters are converted/to/a/path as before. Closes #7047.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7834 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-11 05:56:58 +00:00
Jeremy Kemper
e08527014a Correct RAILS_GEM_VERSION regexp. Use =version gem requirement instead of ~>version so you don't get surprised by a beta gem in production. This change means upgrading to 1.2.5 will require a boot.rb upgrade.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7832 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-11 02:01:37 +00:00
Michael Koziarski
a692432d8a Add deprecation warning for calling .create on has_many associations with an unsaved owner.
Fix regression introduced by [7076] by restoring 1.2.3 behaviour for saving associated records [Bryan Helmkamp].  References #8713


git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7823 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-10 05:42:52 +00:00
Michael Koziarski
3397839ac7 Fix tests broken by earlier change
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7821 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-10 02:10:24 +00:00
Michael Koziarski
1d5d050c70 Make sure acts_as_list's remove_from_list and in_list? play nicely with one another. Closes #8822 [mikel]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7815 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-09 05:16:43 +00:00
Jeremy Kemper
5e281e9c1d Fix unescaped test expectations. Closes #9821 [mikel]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7806 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-08 20:34:10 +00:00
Michael Koziarski
52aeab41cc Improve README documentation. Closes #8770 [mikel]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7797 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-08 05:36:04 +00:00
Jeremy Kemper
16fde4c837 Move custom inflections example so available before route generation. Closes #6829.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7786 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-08 01:22:56 +00:00
Jeremy Kemper
0b45b89c6a Create layout dir it's nested. Closes #9272 [alancfrancis]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7785 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-08 01:02:59 +00:00
Jeremy Kemper
d868c9a3da Fix in place editor's setter action with non-string fields. References #7418.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7783 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-08 00:13:34 +00:00
Michael Koziarski
4c458f8105 Ensure json tests run in stable.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7747 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-05 10:07:23 +00:00
David Heinemeier Hansson
ebe8bc3c59 Update versions for release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7740 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-05 03:58:34 +00:00
Michael Koziarski
a134f8f3c8 Actually add the file referenced in [7730]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7737 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-04 04:11:51 +00:00
Michael Koziarski
0a2404f5cc Merge rake routes to stable to help people upgrading.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7730 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-03 21:48:43 +00:00
Michael Koziarski
70a8e6a7d1 Forgotten changelog entry
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7721 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-02 05:52:16 +00:00
Michael Koziarski
6c773706b4 Disable non-cookie sessions to prevent Session Fixation Attacks. Closes #7952 [bradediger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7720 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-02 05:51:51 +00:00
Michael Koziarski
779db44f74 Change the resource seperator from ; to / change the generated routes to use the new-style named routes. e.g. new_group_user_path(@group) instead of group_new_user_path(@group). [pixeltrix] Closes #8558
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7713 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-01 06:44:07 +00:00
Michael Koziarski
a11dc682a9 Merge sqlite test fixes from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7706 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-01 02:14:31 +00:00
Michael Koziarski
fe1ee81d1a Silence mocha warnings
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7703 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-01 01:56:25 +00:00
Jeremy Kemper
8943da41fd Revert [7414] which rearranged stable resource URLs. References #8558.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7600 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-09-23 22:03:09 +00:00
Tobias Lütke
3acd2bd721 Added new new_admin_products_url named route in addition to old admin_new_products_url syntax. latter syntax got a deprecation warning [pixeltrix]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7414 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-09-06 14:26:52 +00:00
Michael Koziarski
19dff14814 Merge 8801 fix to stable. Closes #8801
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7347 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-20 04:26:10 +00:00
Michael Koziarski
1dd0034134 Don't clobber :includes passed to count on has_many association. Closes #9175 [danger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7328 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-16 04:58:45 +00:00
Michael Koziarski
e0fd18b2aa Merge [7235] to stable. References #9167 [danger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7327 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-16 04:58:06 +00:00
Michael Koziarski
2503fd3c3a Ensure TestRequest#request_uri returns the right value when doing multiple GETs. Closes #4867 [alisdair@randomoracle.org, mpalmer]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7320 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-15 05:35:22 +00:00
Michael Koziarski
631bf6b203 Integration tests: introduce methods for other HTTP methods. Closes #6353. Merges [6203]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7319 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-15 03:57:17 +00:00
Michael Koziarski
6cc01c9579 Merge gem freezing fix to stable.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7277 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-05 01:37:43 +00:00
Michael Koziarski
e3670a0e24 Improve performance of action caching. Closes #8231 [skaes]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7185 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-07-14 08:53:32 +00:00
Michael Koziarski
40a188b18e Merge [7177] to release. [skaes] References #8891
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7178 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-07-11 02:39:31 +00:00
Michael Koziarski
d81ac8d6f3 Merge delete-with-options for cookies from trunk to release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7161 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-07-01 23:35:07 +00:00
Jeremy Kemper
b29caa54e6 Merge [7086] to stable: demote Hash#to_xml to use XmlSimple#xml_in_string so it can't read files or stdin. References #8453.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7087 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-23 00:43:11 +00:00
Jeremy Kemper
7d517a145b Merge [7075] to stable: save associated records only if the association is already loaded. References #8713.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7076 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-21 20:50:53 +00:00
Jeremy Kemper
2ba8864782 1-2-stable: changing the :default Date format doesn't break date quoting. Closes #6312.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7012 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-13 01:26:36 +00:00
Jeremy Kemper
5c6a0d57ac Merge [7006] to stable: fix precedence error in failsafe rescue. References #8625.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7007 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-12 16:47:18 +00:00
Jeremy Kemper
74191edb22 Merge [7002] to stable: fix syntax error in dispatcher than wrecked failsafe responses. References #8625.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7003 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-11 18:06:29 +00:00
Jeremy Kemper
9c0e4de88b Deprecate pagination for Rails 1.2.4. Install the classic_pagination plugin for forward compatibility, or move to the superior will_paginate plugin. References #8157.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6993 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-11 01:01:32 +00:00
Michael Koziarski
1f5a26432d Fix template compile tests on windows [skaes] closes #8234
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6895 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-29 09:58:29 +00:00
Rick Olson
d5950cdd57 apply [6879] to stable. Closes #7293.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6880 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-28 15:54:39 +00:00
Jeremy Kemper
fe3fefeeec Add Active Resource to rails:freeze:edge and drop Action Web Service. Closes #8205.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6872 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-27 22:21:20 +00:00
Jeremy Kemper
3ad1a98556 Merge [6804] to stable: belongs_to assignment creates a new proxy rather than modifying its target in-place. References #8412.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6805 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-22 03:41:29 +00:00
Jeremy Kemper
099c206535 Merge [6802] to stable: fix filtered parameter logging with nil parameter values. References #8422.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6803 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 23:04:14 +00:00
Rick Olson
e5590d69e5 forgot binary fixture
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6800 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 19:50:17 +00:00
Rick Olson
b14378cd68 merge [6798] into stable.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6799 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 18:56:44 +00:00
Jeremy Kemper
07f92e8321 Merge [6796] to stable from trunk. Integration tests: alias xhr to xml_http_request and add a request_method argument instead of always using POST. References #7124.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6797 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 09:19:52 +00:00
Jeremy Kemper
788d4b0cc3 Merge [6793] to stable from trunk: document Object#blank?. References #6491.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6794 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-20 23:22:09 +00:00
Jeremy Kemper
6ba8d874a9 Merge [6790] to stable from trunk: document deep eager includes. References #6267.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6791 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-19 22:41:39 +00:00
Jeremy Kemper
75bf71d429 Revert [4706] which added incorrect docs. References #5684.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6789 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-19 22:15:28 +00:00
Jeremy Kemper
bed591c36c Merge [6787] to stable from trunk: document caches_action. References #5419.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6788 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-19 22:10:10 +00:00
Jeremy Kemper
d4c24b6bb4 Merge [6775] to stable from trunk: observe_form always sends the serialized form. References #5271.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6776 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-18 21:39:14 +00:00
Jeremy Kemper
173e2d2726 Merge [6738] to stable: extract Oracle CHAR column length. References #7866.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6739 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-15 19:32:35 +00:00
Michael Koziarski
cfcc188dd1 Stop depending on strange platform specific rounding behaviour in the number helper tests
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6680 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:49:56 +00:00
Michael Koziarski
a74560f8f0 don't depend on the order of hash.inspect in assertions.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6677 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:35:17 +00:00
Michael Koziarski
92caa99eb3 Allow asset tag tests to pass on windows
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6676 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:33:04 +00:00
Michael Koziarski
d137167ca9 fix actionpack tests broken by additional mocha methods
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6675 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:31:31 +00:00
Michael Koziarski
d080638370 Apply prepend_before_filter bugfix from stefan.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6671 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:19:11 +00:00
Rick Olson
0fd9743ae1 apply [6648] to 1.2 stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6651 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-02 21:03:08 +00:00
Rick Olson
cdc26bdec6 apply [6649] to stable, closes #8226 [Stefan Kaes]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6650 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-02 13:28:33 +00:00
David Heinemeier Hansson
f5977b205f Improved performance by relying less on exception raising #8159 [Blaine]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6571 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-04-24 16:58:24 +00:00
Rick Olson
67465f8a98 forgot to save changelog
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6544 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-04-20 21:41:06 +00:00
Rick Olson
e522f75cbc Return the string representation from an Xml Builder when rendering a partial. #5044 [tpope]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6543 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-04-20 21:40:47 +00:00
Rick Olson
b564d7e1e9 documentation project patches, closes #7342, #7319, #7316, #7190 [jeremymcanally]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6471 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-27 14:04:38 +00:00
Jeremy Kemper
24267c4f3f Merge [6455] from trunk. Fix PStore typo. References #7900.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6456 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-23 16:55:31 +00:00
Jeremy Kemper
e05afb1bcc Merge [6449] from trunk. Fixes SQLite binary encoding with utf8 kcode. References #7862.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6450 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-19 12:55:34 +00:00
Jeremy Kemper
98caf444f3 Merge [6446] from trunk. Never return nil from read_params for compatibility with plain CGI query params parser. References #7581.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6448 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-18 13:49:05 +00:00
Jeremy Kemper
53c87f9818 Merge [6445] from trunk. Consistently canonicalizes RAILS_ROOT on Windows and other platforms. References #6755.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6447 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-18 13:47:08 +00:00
Jeremy Kemper
eefa0a22b4 Merge [6431] from trunk. CGI::Session::Pstore performance. References #7583.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6432 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-16 05:55:31 +00:00
Nicholas Seckar
b41920de18 Merge [6426] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6428 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-14 23:40:59 +00:00
Jeremy Kemper
93d7ab48a1 Merge [6422] from trunk. Undeprecates verification with :redirect_to => :named_route. References #7525.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6423 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-14 01:43:14 +00:00
Jeremy Kemper
d10177d0f1 Clarify changelog entries.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6421 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-14 01:25:05 +00:00
David Heinemeier Hansson
91976d7e6d Only auto-push gems
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6418 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 23:20:00 +00:00
David Heinemeier Hansson
8ad39a0a47 Monkey doc around in an attempt to please rdoc
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6417 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 22:41:24 +00:00
David Heinemeier Hansson
1cd825751d Use inline rubyforge automation
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6416 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 22:31:07 +00:00
Rick Olson
30549718ac apply [6408] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6410 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 05:32:55 +00:00
David Heinemeier Hansson
736cca87dc Prepare for release of Rails 1.2.3
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6395 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-12 23:44:05 +00:00
Rick Olson
5552dadbb9 Apply [5709] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6390 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-12 18:01:28 +00:00
Jeremy Kemper
4a8d3d51f7 Merge [6364] from trunk. Consistently quote primary key column names. References #7763.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6365 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-09 03:25:37 +00:00
Jeremy Kemper
243cdde6a8 Merge [6360] from trunk. Fixes YAML Omap fixtures. References #2665.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6361 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-09 02:09:04 +00:00
Jeremy Kemper
a9ed24c2dd Merge [6344] from trunk. Check for MinGW when testing for Windows platform. References #2982.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6345 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-06 09:24:14 +00:00
Jeremy Kemper
b1e1088ab9 Merge [6336] from trunk. References #6466, #7153.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6337 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-05 11:37:18 +00:00
Jeremy Kemper
579daf5b39 Upgrade rake dependency from 0.7.1 to 0.7.2 to pull in its Ruby 1.8.6 compatibility fixes.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6329 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-04 23:37:17 +00:00
Jeremy Kemper
633d7579cf Ruby 1.8.6 compatibility: the bundled mysql.rb had used deprecated Digest::SHA1.new(...).digest instead of Digest::SHA1.digest(...)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6328 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-04 23:23:05 +00:00
Jeremy Kemper
bbe3dea3fa Merge [6099] from trunk. Compatibility with Ruby 1.8.6: make private Time#to_date and #to_datetime public.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6281 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-02 11:08:52 +00:00
Jeremy Kemper
9679cb4d97 Merge [6253] from trunk. References #6680.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6254 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-27 06:37:54 +00:00
Rick Olson
742bee4256 apply [6248] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6250 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-27 03:27:14 +00:00
Jeremy Kemper
ee31d643eb Merge [6241] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6242 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-26 21:42:38 +00:00
Michael Koziarski
f44437454c Stop swallowing errors during rake test [Koz]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6175 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-20 03:10:21 +00:00
Jeremy Kemper
d1b93e7da2 Revert [6086] and [6087] since they caused a major regression with functional tests in 1.2.2. References #7372.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6145 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-10 03:55:12 +00:00
Jeremy Kemper
ae11519df8 Merge [6143] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6144 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-10 03:08:29 +00:00
Jeremy Kemper
e41f4894c4 Merge [6140] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6141 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-08 00:53:32 +00:00
David Heinemeier Hansson
e73bdfc31b Update date
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6131 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-06 02:26:18 +00:00
David Heinemeier Hansson
a422b8ba62 Prepare for release of Rails 1.2.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6124 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 22:12:33 +00:00
David Heinemeier Hansson
ed6509c843 Update release script on stable branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6123 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 22:04:19 +00:00
Michael Koziarski
41108fec89 Merge 5876 to release.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6122 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 21:30:59 +00:00
David Heinemeier Hansson
c4d8d97e9c Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6119 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 20:44:45 +00:00
Rick Olson
0ee158a3b9 Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6118 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 20:11:35 +00:00
Rick Olson
92b00efd70 fix problem with EMPTY_INHERITABLE_ATTRIBUTES being redefined
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6116 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 19:30:33 +00:00
Rick Olson
21fafdd290 apply [6113] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6114 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 19:12:55 +00:00
Rick Olson
86519a6ea8 Optimize Class Inheritable Attributes so that unnecessary hashes are not created. [Bruce Perens]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6112 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 18:38:07 +00:00
Rick Olson
6a04f3599e Don't create instance writer methods for class attributes. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6109 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 18:05:49 +00:00
Rick Olson
58cb43cb53 Added :instance_writer option to #mattr_writer/accessor, #cattr_writer/accessor, and #class_inheritable_writer to skip the creation of the instance writer. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6108 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 17:55:55 +00:00
Rick Olson
ef3ffd101e Add singleton resources from trunk [Rick Olson]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6107 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 17:19:45 +00:00
Michael Koziarski
6744e35b25 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. [Koz]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6094 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-31 02:07:09 +00:00
Jamis Buck
7571380c9c When dealing with SQLite3, use the table_info pragma helper, so that the bindings can do some translation for when sqlite3 breaks incompatibly between point releases.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6092 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-30 16:33:39 +00:00
Jeremy Kemper
454842a1f6 Merge [6086] from trunk. References #7372.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6087 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 18:26:12 +00:00
Jeremy Kemper
57098ad859 Merge [6084] from trunk. References #7083.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6085 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 17:52:25 +00:00
David Heinemeier Hansson
b79c0a05b2 Remove noisy nodoc for Ruby 1.8.4
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6083 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 17:42:44 +00:00
Jeremy Kemper
2bc5e6cd14 Merge [6078] from trunk. References #6977.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6079 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 16:19:03 +00:00
Jeremy Kemper
4dc206c578 Merge [6075] from trunk. References #7228.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6077 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 15:55:32 +00:00
Jeremy Kemper
d6f6a41f1e Merge [6071] from trunk. References #7095.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6072 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 14:53:33 +00:00
Jeremy Kemper
1155252d37 Merge [6067] from trunk. References #6778.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6068 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 09:12:04 +00:00
Jeremy Kemper
9b24e1198b Merge [5434] from trunk. Reference #6495.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6066 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 09:02:09 +00:00
Jeremy Kemper
d4b6671cdb Merge [6064] from trunk. References #6778.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6065 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 08:51:33 +00:00
Jeremy Kemper
11a92b3582 Merge [6062] from trunk. References #7229.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6063 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 08:29:05 +00:00
David Heinemeier Hansson
7e33de46e5 Fixed NumberHelper#number_with_delimiter to use "." always for splitting the original number, not the delimiter parameter (closes #7389) [ceefour]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6045 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-26 21:49:36 +00:00
David Heinemeier Hansson
fe42e6cc1f stable becomes 1-1-stable, 1-2-pre-release becomes 1-2-stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6042 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-26 21:16:51 +00:00
Rick Olson
c28a70c04b Require the dispatcher for Rails::Configuration#to_prepare. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6041 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-26 15:00:28 +00:00
Jeremy Kemper
553c23df82 Merge [5704], [6005], [6034] from trunk. References #7268, #7354.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6035 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-24 19:08:37 +00:00
Jeremy Kemper
c9ed2f64ae Merge [6023] from trunk. References #7330.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6024 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-24 01:33:56 +00:00
Jeremy Kemper
70f4a92c5d Merge [6014] from trunk. References #2928.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6015 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-23 04:25:28 +00:00
David Heinemeier Hansson
a182d85cd9 Bump rails version too
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5989 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 21:29:13 +00:00
Thomas Fuchs
03e763ffc8 Update prototype.js to [5985], fixes content-type issue with simulated HTTP methods
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5987 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 20:27:17 +00:00
David Heinemeier Hansson
3ec808eadb Update versions in preparation for Rails 1.2.1
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5984 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 20:06:27 +00:00
David Heinemeier Hansson
f255db871b Fix nodoc breaking adapters (closes #7161)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5983 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 16:52:47 +00:00
David Heinemeier Hansson
cfb3a80862 Keep the irrelevant stuff out with :nodoc:
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5981 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 06:31:55 +00:00
David Heinemeier Hansson
5c61b17077 Keep the irrelevant stuff out with :nodoc:
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5980 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 06:23:03 +00:00
Rick Olson
025f895415 Modernize cookie testing code, and increase coverage (Heckle++) #7101 [Kevin Clark]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5978 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 06:53:08 +00:00
Rick Olson
e9e86fd134 Heckling ActionController::Resources::Resource revealed that set_prefixes didn't break when :name_prefix was munged. #7081 [Kevin Clark]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5975 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 06:47:51 +00:00
Sam Stephenson
81b94c2f10 Apply [5970] to 1.2 branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5971 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 05:05:17 +00:00
David Heinemeier Hansson
a3dafb07ec Prepare for release of 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5968 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 04:41:02 +00:00
Rick Olson
cc99f3fc18 [DOC] clear up some ambiguity with the way has_and_belongs_to_many creates the default join table name. #7072 [jeremymcanally]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5961 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-16 06:31:53 +00:00
Michael Koziarski
d25ae9b6e1 Merge oracle fixes over to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5959 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-16 01:41:52 +00:00
David Heinemeier Hansson
517628d028 Made sure that connections are only removed for SQLite
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5955 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 22:12:40 +00:00
Jeremy Kemper
5d0fd52305 Merge [5944] from trunk. References #7048.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5945 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 15:51:54 +00:00
Jeremy Kemper
aa30fc7914 Merge [5937] from trunk. References #6956.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5938 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 02:26:06 +00:00
Jeremy Kemper
5f114177ce Merge [5935] from trunk. References #3987, #6664.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5936 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 01:28:22 +00:00
Jeremy Kemper
143cc0ec2f Merge [5933] from trunk. References #7000.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5934 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 00:36:04 +00:00
Jeremy Kemper
5385859dcf Calculations don't modify their options hash. References [5931], [5426], closes #6929.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5932 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 16:22:33 +00:00
Jeremy Kemper
2d5bf4bbed Merge [5929] from trunk. References #6976.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5930 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 15:20:52 +00:00
Jeremy Kemper
2b6954aa8a Merge [5909], [5927] from trunk. References #6742, #7026.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5928 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 14:44:03 +00:00
Jeremy Kemper
68849e3239 Merge [5924] from trunk. References #7023.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5925 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 12:20:52 +00:00
Jeremy Kemper
debaf20803 Merge [5919] from trunk. References #7021.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5920 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-13 08:07:15 +00:00
Jeremy Kemper
8f84165cb4 Merge [5917] from trunk: unbundle flexmock.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5918 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-13 07:17:14 +00:00
Jeremy Kemper
18857ca2cb Merge [5914] from trunk. References #7015.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5915 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-13 04:10:18 +00:00
Jeremy Kemper
06c7584fba Merge [5907] from trunk. References #6482.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5908 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 10:19:12 +00:00
Jeremy Kemper
dd605e937f Merge [5904] from trunk. References #6252.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5906 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 09:13:05 +00:00
Jeremy Kemper
d12bcdac9d Merge [5901], [5902], [5903] from trunk. References #6156.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5905 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 09:12:28 +00:00
Jeremy Kemper
52923c9b55 Merge [5899] from trunk. References #6962.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5900 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 07:34:09 +00:00
Jeremy Kemper
1a7ce06e90 Merge [5895], [5896] from trunk. References #6891.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5897 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 07:04:53 +00:00
Jeremy Kemper
34603e7faf Merge [5893] from trunk. References #2541.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5894 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 06:28:51 +00:00
Jeremy Kemper
f7d25950f0 Merge [5891] from trunk. References #6635.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5892 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 05:45:31 +00:00
Jeremy Kemper
0ac6b5077f Merge [5889] from trunk. References #6030.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5890 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 05:36:43 +00:00
Jeremy Kemper
fd2b14c046 Merge [5887] from trunk. References #4668.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5888 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 05:24:07 +00:00
Rick Olson
86f78cd8b6 merge [5718] to 1.2 branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5880 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-11 16:29:44 +00:00
Rick Olson
398c1a504c add some more detail on nested resource docs [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5878 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-10 18:10:44 +00:00
Michael Koziarski
5bf40f7b79 Merge error_messages_on fix to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5871 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-07 09:00:11 +00:00
Michael Koziarski
e76eae612f Merge oracle clob / serialize fix to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5867 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 23:49:23 +00:00
Rick Olson
25c3ee407d add application.js filter to fix failing asset tag helper test
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5865 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 21:05:46 +00:00
Rick Olson
de9ccd8848 Slight doc tweak to the ActionView::Helpers::PrototypeHelper#replace docs. Closes #6922 [Steven Bristol]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5864 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:59:42 +00:00
Rick Olson
9cc2e0f2f4 Slight doc tweak to #prepend_filter. Closes #6493 [Jeremy Voorhis]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5861 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:45:58 +00:00
Rick Olson
1696c1f68d Add more extensive documentation to the AssetTagHelper. Closes #6452 [Bob Silva]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5860 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:43:57 +00:00
Rick Olson
2c1d0e2979 Clean up multiple calls to #stringify_keys in TagHelper, add better documentation and testing for TagHelper. Closes #6394 [Bob Silva]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5858 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:32:52 +00:00
Rick Olson
f1a4c44726 [DOCS] Apply more documentation for ActiveRecord Reflection. Closes #4055 [Robby Russell]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5856 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:23:25 +00:00
Rick Olson
382547dcbe [DOCS] Document :allow_nil option of #validate_uniqueness_of. Closes #3143 [Caio Chassot]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5854 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:18:21 +00:00
Rick Olson
376dcb8e02 [DOCS] fix reference to ActionController::Macros::AutoComplete for #text_field_with_auto_complete. Closes #2578 [Jan Prill]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5852 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:12:45 +00:00
David Heinemeier Hansson
ab3f6bcfaa Fixing release notes for RC2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5848 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 04:11:40 +00:00
David Heinemeier Hansson
04383b974d Fixed that webrick would strip leading newlines and hang connection (closes #4156) [psross]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5847 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 04:09:38 +00:00
David Heinemeier Hansson
fde811e2f6 Applied [5845] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5846 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 04:07:21 +00:00
Michael Koziarski
83a21f75cf merge sybase changes to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5840 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 00:16:54 +00:00
Rick Olson
e9a7b233f6 rollback [5833] and [5835]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5837 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-04 21:42:32 +00:00
Rick Olson
21e4825596 apply [5835] to 1.2 RC branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5836 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-04 21:31:48 +00:00
Rick Olson
622d70a11e apply [5833] to 1.2 RC branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5834 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-04 21:19:42 +00:00
Jamis Buck
c26cca3f45 Make sure html_document is reset between integration test requests
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5829 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 03:04:23 +00:00
Jeremy Kemper
b0303e1ac2 Merge [5826] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5827 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:36:48 +00:00
Jeremy Kemper
bdd09f50f8 Merge [5824] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5825 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:32:59 +00:00
Jeremy Kemper
6dc5756d39 Tighten new_session option check.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5822 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:27:55 +00:00
Jeremy Kemper
0120b226ba Merge [5820] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5821 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:14:02 +00:00
Jeremy Kemper
b6af22ec82 Missed additions from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5819 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 00:32:33 +00:00
Jeremy Kemper
4870becaeb Missed additions from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5818 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 00:30:20 +00:00
Jeremy Kemper
a68d1d35f8 Merge [5816] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5817 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 00:25:58 +00:00
Jeremy Kemper
a4e70d3e91 Merge [5814] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5815 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-31 23:54:28 +00:00
David Heinemeier Hansson
ba29222851 Make RDoc not spew errors on install because of HTML comments in code comments
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5813 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-31 19:28:28 +00:00
Nicholas Seckar
0ff4ede7ca Apply [5811] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5812 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-31 18:59:58 +00:00
Rick Olson
7269ee2da9 apply [5801] to 1.2 stable branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5802 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 22:19:36 +00:00
Michael Koziarski
59be73a1e7 Merge nil fix for error_message_on to RC, closes #6884
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5800 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 20:47:20 +00:00
Michael Koziarski
ce8e54e236 Apply doc fix to RC, closes #6522
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5798 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 20:42:51 +00:00
Michael Koziarski
155dcff431 Ensure dynamic finders are anchored to the beginning of the method name to prevent them from firing accidentally. [bradediger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5796 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 20:39:48 +00:00
Rick Olson
df27fb873c apply [5790] to 1.2 stable branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5791 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-26 19:41:08 +00:00
David Heinemeier Hansson
4aa93358fa Apply [5740] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5789 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-26 18:00:43 +00:00
Rick Olson
3054a742df apply [5785] to 1.2 branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5788 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-25 09:41:16 +00:00
Rick Olson
1fb2f21d1a apply [5784] to 1.2 pre-release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5787 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-25 09:37:06 +00:00
Nicholas Seckar
da8a896d86 Apply [5781] and [5782] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5783 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-24 15:19:04 +00:00
Jeremy Kemper
debd9ea2ce Merge [5746] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5765 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-21 19:30:27 +00:00
Jeremy Kemper
8ec9f4d2a0 Merge [5763] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5764 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-20 21:29:43 +00:00
Jeremy Kemper
4dcdf0834e Merge [5761] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5762 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-20 21:15:19 +00:00
Jeremy Kemper
a451fd1fbf Merge [5759] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5760 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-20 18:40:46 +00:00
Jeremy Kemper
c7e2b03424 Merge [5757] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5758 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 23:17:43 +00:00
Jeremy Kemper
6ccbef5862 Merge [5755] from trunk. Closes #6514, closes #6743.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5756 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 20:27:35 +00:00
Jeremy Kemper
498bca8ae8 Merge [5753] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5754 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 19:50:19 +00:00
Jeremy Kemper
c3c7648d20 Merge [5749],[5750],[5751] from trunk. References #6840.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5752 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 19:28:19 +00:00
Rick Olson
fe2e51b047 apply [5744] to 1.2 pre-release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5745 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 03:12:38 +00:00
Jeremy Kemper
67cda1f54e Rollback accidental commit from [5686].
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5743 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-18 23:19:24 +00:00
Michael Koziarski
cda3d89983 Merge plugin changes back to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5739 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-18 20:30:27 +00:00
Jeremy Kemper
0ae462a82d Merge [5730] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5731 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-17 08:31:27 +00:00
Jeremy Kemper
d5ca9a5814 Merge [5728] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5729 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-17 08:24:06 +00:00
Michael Koziarski
72d556a391 Merge [5722] to release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5723 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-16 02:26:01 +00:00
Michael Koziarski
34bc074441 merge plugin loading changes to 1.2 release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5721 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-15 23:51:13 +00:00
Jeremy Kemper
6df67f5607 Merge [5715] from trunk. Closes #6699.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5716 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-12 22:28:21 +00:00
Nicholas Seckar
590b192e02 Apply [5710] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5712 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-10 21:14:21 +00:00
Jeremy Kemper
67ac59afc8 Merge [5694]-[5698] from trunk: respond_to json and render :json => ...
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5699 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 23:26:18 +00:00
Jeremy Kemper
3d5fb40bb0 Partially merge [5691] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5693 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 22:11:30 +00:00
Jeremy Kemper
0c483d0c8d Merge [5689] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5690 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 20:29:16 +00:00
Jeremy Kemper
8804b7aeb7 Include svn revision in changelogs.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5687 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 19:30:04 +00:00
Jeremy Kemper
2876efb784 Merge [5685] from trunk. Closes #3811.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5686 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 19:27:05 +00:00
Jeremy Kemper
762fc5447f Merge [5682] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5683 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-05 22:09:18 +00:00
David Heinemeier Hansson
bd261ffd1f Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5672 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-04 03:50:57 +00:00
David Heinemeier Hansson
ffb17e89ef Dropped the idea of automatically routing :format for the vanilla routes -- that will be a treat for map.resources. Deprecated the name route root as it'll be used as a shortcut for map.connect '' in Rails 2.0 (Rails 1.2). Added map.root as an alias for map.connect '' (Rails 2.0)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5671 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-04 00:12:00 +00:00
David Heinemeier Hansson
2a08c4547a Documentation for generators (closes #6671) [topfunky]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5669 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-03 16:53:16 +00:00
David Heinemeier Hansson
2b68762f5a Fixed Array#to_xml when it contains a series of hashes (each piece would get its own XML declaration) (closes #6610) [thkarcher/cyu]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5668 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-03 16:47:53 +00:00
David Heinemeier Hansson
de3ec6c008 Wups
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5662 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 23:02:48 +00:00
Jeremy Kemper
2890b9648e Merge [5660] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5661 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 21:34:22 +00:00
David Heinemeier Hansson
98a0440a56 If only life was that simple (it didnt help)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5658 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 05:56:51 +00:00
David Heinemeier Hansson
f09c8c4529 Replace the elaborate reloading connection checking scheme, just fix the Ruby-based MySQL adapter, ye?
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5656 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 05:37:56 +00:00
David Heinemeier Hansson
25d7ea8ad2 Refactored to use same option setup
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5654 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-30 22:22:02 +00:00
David Heinemeier Hansson
91cd8890c7 Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5652 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-30 21:45:31 +00:00
Jeremy Kemper
87ef365a49 Merge [5435] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5651 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-29 22:58:21 +00:00
Jeremy Kemper
d6c28bfaed Use head. Stop last @response.redirect_url from bleeding through (should be recycled like request is).
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5645 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-28 23:38:29 +00:00
Jeremy Kemper
b2ae346484 Merge [5643] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5644 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-28 23:26:25 +00:00
Michael Koziarski
fb6cd55de7 ensure follow_redirect works with normalized headers
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5641 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-27 22:52:58 +00:00
Michael Koziarski
c4d4660de3 Ensure integration tests get the correct value of fixtures_path. Closes #6672
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5639 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-27 05:14:05 +00:00
David Heinemeier Hansson
205ae50d3f Only reload connections in development mode that supports (and requires that) -- in other words, only do it for SQLite (closes #6687, #6700) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5637 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 22:10:55 +00:00
Jeremy Kemper
5b8bfc40e0 Merge [5635] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5636 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 05:37:09 +00:00
David Heinemeier Hansson
f83eedd440 Fix that redirects should set "Location" header, not "location", and remove dead CGI.redirect
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5634 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 05:04:57 +00:00
David Heinemeier Hansson
691c439129 redirect_to is the one place where _url should be used, not _path [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5633 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 04:42:13 +00:00
Jeremy Kemper
8f3e81ed53 Merge [5631] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5632 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 01:24:57 +00:00
Jeremy Kemper
fd8ee0a253 Merge [5629] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5630 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 01:02:45 +00:00
David Heinemeier Hansson
509c920d35 Tried delaying database disconnect until after dependency resolution (references #6687, #6700) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5627 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-25 19:59:00 +00:00
David Heinemeier Hansson
cef81e71eb Dont set default charset if the response is sending a file. Closes #6689 [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5626 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-25 19:29:10 +00:00
Nicholas Seckar
3ee809655e Apply [5624] to RC. References #6698.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5625 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-25 17:16:52 +00:00
David Heinemeier Hansson
c3cbd6b806 Fixed that HEAD should return the proper Content-Length header (that is, actually use @body.size, not just 0) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5622 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 23:52:25 +00:00
David Heinemeier Hansson
fe1e771222 * Added GET-masquarading for HEAD, so request.method will return :get even for HEADs. This will help anyone relying on case request.method to automatically work with HEAD and map.resources will also allow HEADs to all GET actions. Rails automatically throws away the response content in a reply to HEAD, so you dont even need to worry about that. If you, for whatever reason, still need to distinguish between GET and HEAD in some edge case, you can use Request#head? and even Request.headers["REQUEST_METHOD"] for get the "real" answer. Closes #6694 [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5621 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 23:24:47 +00:00
David Heinemeier Hansson
694957ce5a Added text/csv as a default mime type and included example on how to make your own in config/environment.rb [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5620 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 17:25:52 +00:00
David Heinemeier Hansson
12949bbc13 Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5617 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 05:16:44 +00:00
David Heinemeier Hansson
82e5ff7c6e Actually require the gem found
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5615 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 04:49:04 +00:00
David Heinemeier Hansson
783c16bd61 Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5613 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 04:40:38 +00:00
David Heinemeier Hansson
34a3d04af1 Dont include the mime.yml anyway, Mongrel will just ship with more defaults instead
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5611 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 02:41:41 +00:00
David Heinemeier Hansson
766ca17c91 Update release date for RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5610 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 02:32:50 +00:00
Nicholas Seckar
ffa2c5fda5 Apply [5607] to RC. References #6669.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5608 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-22 16:38:06 +00:00
Thomas Fuchs
87ecb782e6 Merge [5602] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5603 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 23:45:47 +00:00
Jeremy Kemper
2043513f4c Merge [5586], [5596] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5599 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 12:20:16 +00:00
Jeremy Kemper
ef6c3c4289 Merge [5597] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5598 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 12:08:05 +00:00
Jeremy Kemper
af43e87f38 Merge [5591] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5592 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 11:05:12 +00:00
Jeremy Kemper
f2fd22c2d4 Merge [5589] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5590 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 10:55:41 +00:00
David Heinemeier Hansson
17921bafcb Proper dates
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5584 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 00:02:42 +00:00
Thomas Fuchs
36b3cb2c36 Merge 1-2-pre-release with [5581]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5582 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 23:08:27 +00:00
David Heinemeier Hansson
b93e4692b2 Made script/server work with -e and -d when using Mongrel [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5578 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 22:18:48 +00:00
Rick Olson
30e5436a3e merge [5571] and [5572] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5573 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 21:16:30 +00:00
David Heinemeier Hansson
9ba96771c3 Scaffold resource should have both a layout and a stylesheet [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5566 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 16:57:45 +00:00
Jeremy Kemper
97d9dca26f Merge [5561] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5562 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 09:59:55 +00:00
David Heinemeier Hansson
2a70f6f0a2 Update changelogs in preparation for RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5560 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 01:07:08 +00:00
David Heinemeier Hansson
1e532f6606 Merged [5503] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5559 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:17:13 +00:00
David Heinemeier Hansson
fb60a469c0 Merged [5485] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5558 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:12:22 +00:00
David Heinemeier Hansson
ac2295137c Merged [5482] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5557 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:10:18 +00:00
David Heinemeier Hansson
acfe119cb5 Merged [5473] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5556 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:05:13 +00:00
David Heinemeier Hansson
004a28de81 Merged [5546] and [5547] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5555 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 18:49:29 +00:00
David Heinemeier Hansson
0497868531 Active Resource will not ship with Rails 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5554 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 18:46:20 +00:00
Thomas Fuchs
23569d83b2 Update Prototype in RC to [5550]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5552 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-17 23:55:04 +00:00
Nicholas Seckar
bef626e2b1 Apply [5548] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5549 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-17 22:31:47 +00:00
Jeremy Kemper
b7f094e65e Merge [5543] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5545 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-17 13:11:59 +00:00
Jeremy Kemper
6baf9489d1 Merge [5541] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5542 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 22:51:17 +00:00
Jeremy Kemper
af33784698 Merge [5531] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5538 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 17:26:39 +00:00
Jeremy Kemper
a5631a5674 Merge [5535], [5536] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5537 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 06:45:06 +00:00
Jeremy Kemper
629b2ac36c Merge [5533] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5534 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 01:43:59 +00:00
Jeremy Kemper
dd1dc5e819 Merge [5521] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5522 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-14 09:23:17 +00:00
Jeremy Kemper
b8ff216f49 Merge [5518] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5519 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-14 02:52:14 +00:00
Tobias Lütke
924f5cdb61 Merge from [5516]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5517 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 20:30:18 +00:00
Jeremy Kemper
86bd0da7d0 Merge [5514] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5515 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 19:24:33 +00:00
Jeremy Kemper
35240ba66e Merge [5512] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5513 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 19:03:08 +00:00
Jeremy Kemper
b8a5d398b9 Merge [5509] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5510 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 07:40:20 +00:00
Jeremy Kemper
85c45051be Merge [5506] from trunk. Set Rails::VERSION::STRING to 1.1.6 pending 1.2 release.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5508 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 07:17:11 +00:00
Jeremy Kemper
f7c94e977b Merge [5501] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5502 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 01:10:13 +00:00
Sam Stephenson
69ada0e26e Merge [5497] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5500 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 03:48:45 +00:00
Sam Stephenson
9eaad14e8e Merge [5487] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5499 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 03:48:09 +00:00
Sam Stephenson
9f8c805f5d Merge [5486] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5498 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 03:47:27 +00:00
Jamis Buck
46b845e784 Add grep-based fallback to reaper, to work in pidless setups
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5494 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 02:51:43 +00:00
Jeremy Kemper
118764e47d Merge [5480] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5481 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-10 19:19:50 +00:00
Rick Olson
bcd50f1a37 merge [5476] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5479 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-10 18:35:24 +00:00
Jeremy Kemper
5aced86de6 Merge [5474] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5475 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-09 19:36:39 +00:00
Nicholas Seckar
792780a80c Apply [5471] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5472 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-09 18:38:04 +00:00
Jeremy Kemper
5e677b67b5 Merge [5469] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5470 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-09 08:10:14 +00:00
Jeremy Kemper
dfa070aab9 Merge [5466] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5467 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 21:47:01 +00:00
Jeremy Kemper
ba086a4fc0 Merge [5440], [5444], [5463], [5464] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5465 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 21:13:27 +00:00
Jeremy Kemper
cc299d1b94 Merge [5459] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5460 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 20:14:09 +00:00
Nicholas Seckar
cbffafb497 Remove temporary crutch to help ApplicationController be unloaded. Closes #6496.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5458 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 19:54:43 +00:00
Jamis Buck
84668af330 make add_order a tad faster
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5453 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 19:11:39 +00:00
Jeremy Kemper
013004b592 Merge [5445] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5446 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 00:20:07 +00:00
Jeremy Kemper
5f5d8c224b Merge [5442] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5443 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-06 21:49:35 +00:00
Thomas Fuchs
5887b183ce Merge [5438] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5439 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-06 09:45:39 +00:00
Jeremy Kemper
320875ad77 Merge [5432] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5433 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-05 19:05:00 +00:00
Jeremy Kemper
4aa358dd86 Merge [5429] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5430 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-05 02:42:42 +00:00
Jeremy Kemper
6439d0cd3e Merge [5427] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5428 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-05 02:16:34 +00:00
Scott Barron
7953eb170d merge [5424] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5425 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-03 18:21:23 +00:00
Jeremy Kemper
5350fda95d Merge [5422] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5423 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-03 04:18:52 +00:00
Jeremy Kemper
5fac326020 Merge [5420] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5421 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-03 00:41:48 +00:00
Jeremy Kemper
17e445813b Merge [5418] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5419 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 20:37:32 +00:00
Jeremy Kemper
a2edd4381e Merge [5416] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5417 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 20:22:28 +00:00
Michael Koziarski
2029b8a8f5 merge xmlsimple update to release branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5415 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 20:13:27 +00:00
Jeremy Kemper
53c49036ea Merge [5412] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5413 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 19:32:16 +00:00
Scott Barron
855e0f6f09 merge [5408] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5409 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 18:39:37 +00:00
Jeremy Kemper
e4e1d2afa3 Merge [5405] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5406 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 18:13:49 +00:00
Jeremy Kemper
526afd3ae2 Merge [5403] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5404 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 10:12:29 +00:00
Jeremy Kemper
31b901aa65 Merge [5401] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5402 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 09:47:36 +00:00
Jeremy Kemper
a746e39584 Merge [5399] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5400 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 08:49:47 +00:00
Jeremy Kemper
f4d88039fd Merge [5397] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5398 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 08:38:44 +00:00
Jeremy Kemper
9f26164d37 Merge [5395] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5396 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 07:57:44 +00:00
Scott Barron
c7f28e01c8 Merge in [5392] and [5393] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5394 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 05:02:09 +00:00
Michael Koziarski
3311953d3f merge rakefile changes to prerelease
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5391 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 03:38:36 +00:00
Jeremy Kemper
ce0653b1c6 Merge [5388] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5389 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 02:23:45 +00:00
Nicholas Seckar
229e197ac7 Update dependencies to allow constants to be defined alongside their siblings. (Applying changeset [5386] to RC.)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5387 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 23:24:17 +00:00
Jeremy Kemper
503c7c0afd Merge [5384] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5385 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 20:47:27 +00:00
Jeremy Kemper
8e01efee02 Merge [5379] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5383 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 19:41:01 +00:00
Jeremy Kemper
e09f224a5c Merge [5378] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5382 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 19:38:47 +00:00
Scott Barron
6eb941ee6c Merge breakpoint/1.8.5 fix from [5380]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5381 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 17:50:02 +00:00
Michael Koziarski
7e8dd0322c Revert environment.rb changes for autoloading
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5377 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-31 01:33:33 +00:00
Thomas Fuchs
159411f580 Update to latest Prototype, which doesnt serialize disabled form elements, adds clone() to arrays, empty/non-string Element.update() and adds a fixes excessive error reporting in WebKit beta versions [Thomas Fuchs]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5372 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-28 16:56:09 +00:00
Michael Koziarski
746cfb3ded Merge Statistics cleanup to release branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5370 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-27 01:42:47 +00:00
David Heinemeier Hansson
2227a178ee Branches so we can just get the bug fixes out of the way before shipping 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5368 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-26 17:05:00 +00:00
327 changed files with 10828 additions and 4952 deletions

View File

@@ -1,4 +1,33 @@
*SVN*
*1.3.6* (October 12th, 2007)
* Depend on Action Pack 1.13.6
*1.3.5* (October 12th, 2007)
* Depend on Action Pack 1.13.5
*1.3.4* (October 4th, 2007)
* Depend on Action Pack 1.13.4
*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. [Koz]
*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]
@@ -14,8 +43,6 @@
* 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.]
@@ -24,8 +51,30 @@
* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
*1.2.5* (August 10th, 2006)
* Depend on Action Pack 1.12.5
*1.2.4* (August 8th, 2006)
* Backport of documentation enhancements. [Kevin Clark, Marcel Molina Jr]
* Correct spurious documentation example code which results in a SyntaxError. [Marcel Molina Jr.]
* Mailer template root applies to a class and its subclasses rather than acting globally. #5555 [somekool@gmail.com]
*1.2.3* (June 29th, 2006)
* Depend on Action Pack 1.12.3
*1.2.2* (June 27th, 2006)
* Depend on Action Pack 1.12.2
*1.2.1* (April 6th, 2006)

View File

@@ -54,7 +54,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 1.12.5' + PKG_BUILD)
s.add_dependency('actionpack', '= 1.13.6' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
@@ -85,11 +85,11 @@ end
desc "Publish the release files to RubyForge."
task :release => [ :package ] do
`rubyforge login`
require 'rubyforge'
for ext in %w( gem tgz zip )
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command
system(release_command)
end
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
rubyforge = RubyForge.new
rubyforge.login
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end

View File

@@ -27,7 +27,7 @@ unless defined?(ActionController)
require 'action_controller'
rescue LoadError
require 'rubygems'
require_gem 'actionpack', '>= 1.12.5'
gem 'actionpack', '>= 1.12.5'
end
end

View File

@@ -184,7 +184,7 @@ module ActionMailer #:nodoc:
# * <tt>logger</tt> - the logger is used for generating information on the mailing run if available.
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
#
# * <tt>server_settings</tt> - Allows detailed configuration of the server:
# * <tt>smtp_settings</tt> - Allows detailed configuration for :smtp delivery method:
# * <tt>:address</tt> Allows you to use a remote mail server. Just change it from its default "localhost" setting.
# * <tt>:port</tt> On the off chance that your mail server doesn't run on port 25, you can change it.
# * <tt>:domain</tt> If you need to specify a HELO domain, you can do it here.
@@ -193,10 +193,12 @@ module ActionMailer #:nodoc:
# * <tt>:authentication</tt> If your mail server requires authentication, you need to specify the authentication type here.
# This is a symbol and one of :plain, :login, :cram_md5
#
# * <tt>sendmail_settings</tt> - Allows you to override options for the :sendmail delivery method
# * <tt>:location</tt> The location of the sendmail executable, defaults to "/usr/sbin/sendmail"
# * <tt>:arguments</tt> The command line arguments
# * <tt>raise_delivery_errors</tt> - whether or not errors should be raised if the email fails to be delivered.
#
# * <tt>delivery_method</tt> - Defines a delivery method. Possible values are :smtp (default), :sendmail, and :test.
# Sendmail is assumed to be present at "/usr/sbin/sendmail".
#
# * <tt>perform_deliveries</tt> - Determines whether deliver_* methods are actually carried out. By default they are,
# but this can be turned off to help functional testing.
@@ -228,7 +230,7 @@ module ActionMailer #:nodoc:
class_inheritable_accessor :template_root
cattr_accessor :logger
@@server_settings = {
@@smtp_settings = {
:address => "localhost",
:port => 25,
:domain => 'localhost.localdomain',
@@ -236,7 +238,13 @@ module ActionMailer #:nodoc:
:password => nil,
:authentication => nil
}
cattr_accessor :server_settings
cattr_accessor :smtp_settings
@@sendmail_settings = {
:location => '/usr/sbin/sendmail',
:arguments => '-i -t'
}
cattr_accessor :sendmail_settings
@@raise_delivery_errors = true
cattr_accessor :raise_delivery_errors
@@ -355,6 +363,18 @@ module ActionMailer #:nodoc:
def deliver(mail)
new.deliver!(mail)
end
# Server Settings is the old name for <tt>smtp_settings</tt>
def server_settings
smtp_settings
end
deprecate :server_settings=>"It's now named smtp_settings"
def server_settings=(settings)
ActiveSupport::Deprecation.warn("server_settings has been renamed smtp_settings, this warning will be removed with rails 2.0", caller)
self.smtp_settings=settings
end
end
# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
@@ -542,14 +562,14 @@ module ActionMailer #:nodoc:
destinations = mail.destinations
mail.ready_to_send
Net::SMTP.start(server_settings[:address], server_settings[:port], server_settings[:domain],
server_settings[:user_name], server_settings[:password], server_settings[:authentication]) do |smtp|
Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain],
smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp|
smtp.sendmail(mail.encoded, mail.from, destinations)
end
end
def perform_delivery_sendmail(mail)
IO.popen("/usr/sbin/sendmail -i -t","w+") do |sm|
IO.popen("#{sendmail_settings[:location]} #{sendmail_settings[:arguments]}","w+") do |sm|
sm.print(mail.encoded.gsub(/\r/, ''))
sm.flush
end

View File

@@ -1,8 +1,8 @@
module ActionMailer
module VERSION #:nodoc:
MAJOR = 1
MINOR = 2
TINY = 5
MINOR = 3
TINY = 6
STRING = [MAJOR, MINOR, TINY].join('.')
end

View File

@@ -787,6 +787,19 @@ EOF
assert_match %r{format=flowed}, mail['content-type'].to_s
assert_match %r{charset=utf-8}, mail['content-type'].to_s
end
def test_deprecated_server_settings
old_smtp_settings = ActionMailer::Base.smtp_settings
assert_deprecated do
ActionMailer::Base.server_settings
end
assert_deprecated do
ActionMailer::Base.server_settings={}
assert_equal Hash.new, ActionMailer::Base.smtp_settings
end
ensure
ActionMailer::Base.smtp_settings=old_smtp_settings
end
end
class InheritableTemplateRootTest < Test::Unit::TestCase

View File

@@ -1,4 +1,206 @@
*SVN*
*1.13.6* (November 24th, 2007)
* Correct Broken Fix for session_fixation attacks
* Ensure that cookies handle array values correctly. Closes #9937 [queso]
*1.13.5* (October 12th, 2007)
* Backport: allow array and hash query parameters. Array route parameters are converted/to/a/path as before. #6765, #7047, #7462 [bgipsy, Jeremy McAnally, Dan Kubb, brendan, Diego Algorta Casamayou]
* Fix in place editor's setter action with non-string fields. #7418 [Andreas]
*1.13.4* (October 4th, 2007)
* Only accept session ids from cookies, prevents session fixation attacks. [bradediger]
* Change the resource seperator from ; to / change the generated routes to use the new-style named routes. e.g. new_group_user_path(@group) instead of group_new_user_path(@group). [pixeltrix]
* Integration tests: introduce methods for other HTTP methods. #6353 [caboose]
* Improve performance of action caching. Closes #8231 [skaes]
* Fix errors with around_filters which do not yield, restore 1.1 behaviour with after filters. Closes #8891 [skaes]
After filters will *no longer* be run if an around_filter fails to yield, users relying on
this behaviour are advised to put the code in question after a yield statement in an around filter.
* Allow you to delete cookies with options. Closes #3685 [josh, Chris Wanstrath]
* Deprecate pagination. Install the classic_pagination plugin for forward compatibility, or move to the superior will_paginate plugin. #8157 [Mislav Marohnic]
* Fix filtered parameter logging with nil parameter values. #8422 [choonkeat]
* Integration tests: alias xhr to xml_http_request and add a request_method argument instead of always using POST. #7124 [Nik Wakelin, Francois Beausoleil, Wizard]
* Document caches_action. #5419 [Jarkko Laine]
* observe_form always sends the serialized form. #5271 [manfred, normelton@gmail.com]
* Update UrlWriter to accept :anchor parameter. Closes #6771. [octopod]
* Replace the current block/continuation filter chain handling by an implementation based on a simple loop. Closes #8226 [Stefan Kaes]
* Return the string representation from an Xml Builder when rendering a partial. #5044 [tpope]
* Cleaned up, corrected, and mildly expanded ActionPack documentation. Closes #7190 [jeremymcanally]
* Small collection of ActionController documentation cleanups. Closes #7319 [jeremymcanally]
* Performance: patch cgi/session/pstore to require digest/md5 once rather than per #initialize. #7583 [Stefan Kaes]
* Deprecation: verification with :redirect_to => :named_route shouldn't be deprecated. #7525 [Justin French]
*1.13.3* (March 12th, 2007)
* Fix a bug in Routing where a parameter taken from the path of the current request could not be used as a query parameter for the next. #6752 [Nicholas Seckar]
* session_enabled? works with session :off. #6680 [Catfish]
* Performance: patch cgi/session to require digest/md5 once rather than per #create_new_id. [Stefan Kaes]
*1.13.2* (February 5th, 2007)
* Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick]
* improve error message for Routing for named routes. [Rob Sanheim]
* Added enhanced docs to routing assertions. [Rob Sanheim]
* fix form_for example in ActionController::Resources documentation. [gnarg]
* Add singleton resources from trunk [Rick Olson]
* select :multiple => true suffixes the attribute name with [] unless already suffixed. #6977 [nik.kakelin, ben, julik]
* Improve routes documentation. #7095 [zackchandler]
* Resource member routes require :id, eliminating the ambiguous overlap with collection routes. #7229 [dkubb]
* Fixed NumberHelper#number_with_delimiter to use "." always for splitting the original number, not the delimiter parameter #7389 [ceefour]
* Autolinking recognizes trailing and embedded . , : ; #7354 [Jarkko Laine]
* Make TextHelper::auto_link recognize URLs with colons in path correctly, fixes #7268. [imajes]
* Improved auto_link to match more valid urls correctly [Tobias Luetke]
*1.13.1* (January 18th, 2007)
* Fixed content-type bug in Prototype [sam]
*1.13.0* (January 16th, 2007)
* Modernize cookie testing code, and increase coverage (Heckle++) #7101 [Kevin Clark]
* Heckling ActionController::Resources::Resource revealed that set_prefixes didn't break when :name_prefix was munged. #7081 [Kevin Clark]
* Update to Prototype 1.5.0. [Sam Stephenson]
* Allow exempt_from_layout :rhtml. #6742, #7026 [dcmanges, Squeegy]
* Fix parsing of array[] CGI parameters so extra empty values aren't included. #6252 [Nicholas Seckar, aiwilliams, brentrowland]
* link_to_unless_current works with full URLs as well as paths. #6891 [Jarkko Laine, manfred, idrifter]
* Fix HTML::Node to output double quotes instead of single quotes. Closes #6845 [mitreandy]
* Fix no method error with error_messages_on. Closes #6935 [nik.wakelin Koz]
* Slight doc tweak to the ActionView::Helpers::PrototypeHelper#replace docs. Closes #6922 [Steven Bristol]
* Slight doc tweak to #prepend_filter. Closes #6493 [Jeremy Voorhis]
* Add more extensive documentation to the AssetTagHelper. Closes #6452 [Bob Silva]
* Clean up multiple calls to #stringify_keys in TagHelper, add better documentation and testing for TagHelper. Closes #6394 [Bob Silva]
* [DOCS] fix reference to ActionController::Macros::AutoComplete for #text_field_with_auto_complete. Closes #2578 [Jan Prill]
* Make sure html_document is reset between integration test requests. [ctm]
* Set session to an empty hash if :new_session => false and no session cookie or param is present. CGI::Session was raising an unrescued ArgumentError. [Josh Susser]
* Fix assert_redirected_to bug where redirecting from a nested to to a top-level controller incorrectly added the current controller's nesting. Closes #6128. [Rick Olson]
* Ensure render :json => ... skips the layout. #6808 [Josh Peek]
* Silence log_error deprecation warnings from inspecting deprecated instance variables. [Nate Wiger]
* Only cache GET requests with a 200 OK response. #6514, #6743 [RSL, anamba]
* Correctly report which filter halted the chain. #6699 [Martin Emde]
* respond_to recognizes JSON. render :json => @person.to_json automatically sets the content type and takes a :callback option to specify a client-side function to call using the rendered JSON as an argument. #4185 [Scott Raymond, eventualbuddha]
# application/json response with body 'Element.show({:name: "David"})'
respond_to do |format|
format.json { render :json => { :name => "David" }.to_json, :callback => 'Element.show' }
end
* Makes :discard_year work without breaking multi-attribute parsing in AR. #1260, #3800 [sean@ardismg.com, jmartin@desertflood.com, stephen@touset.org, Bob Silva]
* Adds html id attribute to date helper elements. #1050, #1382 [mortonda@dgrmm.net, David North, Bob Silva]
* Add :index and @auto_index capability to model driven date/time selects. #847, #2655 [moriq, Doug Fales, Bob Silva]
* Add :order to datetime_select, select_datetime, and select_date. #1427 [Timothee Peignier, patrick@lenz.sh, Bob Silva]
* Added time_select to work with time values in models. Update scaffolding. #2489, #2833 [Justin Palmer, Andre Caum, Bob Silva]
* Added :include_seconds to select_datetime, datetime_select and time_select. #2998 [csn, Bob Silva]
* All date/datetime selects can now accept an array of month names with :use_month_names. Allows for localization. #363 [tomasj, Bob Silva]
* Adds :time_separator to select_time and :date_separator to select_datetime. Preserves BC. #3811 [Bob Silva]
* @response.redirect_url works with 201 Created responses: just return headers['Location'] rather than checking the response status. [Jeremy Kemper]
* Fixed that HEAD should return the proper Content-Length header (that is, actually use @body.size, not just 0) [DHH]
* Added GET-masquarading for HEAD, so request.method will return :get even for HEADs. This will help anyone relying on case request.method to automatically work with HEAD and map.resources will also allow HEADs to all GET actions. Rails automatically throws away the response content in a reply to HEAD, so you don't even need to worry about that. If you, for whatever reason, still need to distinguish between GET and HEAD in some edge case, you can use Request#head? and even Request.headers["REQUEST_METHOD"] for get the "real" answer. Closes #6694 [DHH]
*1.13.0 RC1* (r5619, November 22nd, 2006)
* Update Routing to complain when :controller is not specified by a route. Closes #6669. [Nicholas Seckar]
* Ensure render_to_string cleans up after itself when an exception is raised. #6658 [rsanheim]
* Update to Prototype and script.aculo.us [5579]. [Sam Stephenson, Thomas Fuchs]
* simple_format helper doesn't choke on nil. #6644 [jerry426]
* Reuse named route helper module between Routing reloads. Use remove_method to delete named route methods after each load. Since the module is never collected, this fixes a significant memory leak. [Nicholas Seckar]
* Deprecate standalone components. [Jeremy Kemper]
* Always clear model associations from session. #4795 [sd@notso.net, andylien@gmail.com]
* Remove JavaScriptLiteral in favor of ActiveSupport::JSON::Variable. [Sam Stephenson]
* Sync ActionController::StatusCodes::STATUS_CODES with http://www.iana.org/assignments/http-status-codes. #6586 [dkubb]
* Multipart form values may have a content type without being treated as uploaded files if they do not provide a filename. #6401 [Andreas Schwarz, Jeremy Kemper]
* assert_response supports symbolic status codes. #6569 [Kevin Clark]
assert_response :ok
assert_response :not_found
assert_response :forbidden
* Cache parsed query parameters. #6559 [Stefan Kaes]
* Deprecate JavaScriptHelper#update_element_function, which is superseeded by RJS [Thomas Fuchs]
* Fix invalid test fixture exposed by stricter Ruby 1.8.5 multipart parsing. #6524 [Bob Silva]
* Set ActionView::Base.default_form_builder once rather than passing the :builder option to every form or overriding the form helper methods. [Jeremy Kemper]
* Deprecate expire_matched_fragments. Use expire_fragment instead. #6535 [Bob Silva]
* Deprecate start_form_tag and end_form_tag. Use form_tag / '</form>' from now on. [Rick]
@@ -35,8 +237,6 @@
* Fix double-escaped entities, such as &amp;amp;, &amp;#123;, etc. [Rick]
* Fix deprecation warnings when rendering the template error template. [Nicholas Seckar]
* Fix routing to correctly determine when generation fails. Closes #6300. [psross].
* Fix broken assert_generates when extra keys are being checked. [Jamis Buck]
@@ -47,10 +247,6 @@
* Use String#chars in TextHelper::excerpt. Closes #6386 [Manfred Stienstra]
* Install named routes into ActionView::Base instead of proxying them to the view via helper_method. Closes #5932. [Nicholas Seckar]
* Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs]
* Fix relative URL root matching problems. [Mark Imbriaco]
* Fix filter skipping in controller subclasses. #5949, #6297, #6299 [Martin Emde]
@@ -106,8 +302,6 @@
* Filters overhaul including meantime filter support using around filters + blocks. #5949 [Martin Emde, Roman Le Negrate, Stefan Kaes, Jeremy Kemper]
* Update RJS render tests. [sam]
* Update CGI process to allow sessions to contain namespaced models. Closes #4638. [dfelstead@site5.com]
* Fix routing to respect user provided requirements and defaults when assigning default routing options (such as :action => 'index'). Closes #5950. [Nicholas Seckar]
@@ -133,12 +327,6 @@
response.content_type = Mime::ATOM
response.charset = "utf-8"
* Updated prototype.js to 1.5.0_rc1 with latest fixes. [Rick Olson]
- XPATH support
- Make Form.getElements() return elements in the correct order
- fix broken Form.serialize return
* Declare file extensions exempt from layouts. #6219 [brandon]
Example: ActionController::Base.exempt_from_layout 'rpdf'
@@ -163,8 +351,6 @@
* Fix assert_tag so that :content => "foo" does not match substrings, but only exact strings. Use :content => /foo/ to match substrings. #2799 [Eric Hodel]
* Add descriptive messages to the exceptions thrown by cgi_methods. #6091, #6103 [Nicholas Seckar, Bob Silva]
* Update JavaScriptGenerator#show/hide/toggle/remove to new Prototype syntax for multiple ids, #6068 [petermichaux@gmail.com]
* Update UrlWriter to support :only_path. [Nicholas Seckar, Dave Thomas]
@@ -177,10 +363,6 @@
link_to("Hider", :class => "hider_link") { |p| p[:something].hide }
* Update to script.aculo.us 1.6.3 [Thomas Fuchs]
* Update to Prototype 1.5.0_rc1 [sam]
* Added access to nested attributes in RJS #4548 [richcollins@gmail.com]. Examples:
page['foo']['style'] # => $('foo').style;
@@ -202,9 +384,6 @@
* Changed that uncaught exceptions raised any where in the application will cause RAILS_ROOT/public/500.html to be read and shown instead of just the static "Application error (Rails)" [DHH]
* Integration tests: thoroughly test ActionController::Integration::Session. #6022 [Kevin Clark]
(tests skipped unless you `gem install mocha`)
* Added deprecation language for pagination which will become a plugin by Rails 2.0 [DHH]
* Added deprecation language for in_place_editor and auto_complete_field that both pieces will become plugins by Rails 2.0 [DHH]
@@ -215,7 +394,7 @@
* radio_button_tag generates unique id attributes. #3353 [Bob Silva, somekool@gmail.com]
* strip_tags returns nil for a blank arg such as nil or "". #2229 [duncan@whomwah.com]
* strip_tags passes through blank args such as nil or "". #2229, #6702 [duncan@whomwah.com, dharana]
* Cleanup assert_tag :children counting. #2181 [jamie@bravenet.com]
@@ -223,20 +402,12 @@
* Update sanitize text helper to strip plaintext tags, and <img src="javascript:bang">. [Rick Olson]
* Update routing documentation. Closes #6017 [Nathan Witmer]
* Add routing tests to assert that RoutingError is raised when conditions aren't met. Closes #6016 [Nathan Witmer]
* Deprecation: update docs. #5998 [jakob@mentalized.net, Kevin Clark]
* Make auto_link parse a greater subset of valid url formats. [Jamis Buck]
* Integration tests: headers beginning with X aren't excluded from the HTTP_ prefix, so X-Requested-With becomes HTTP_X_REQUESTED_WITH as expected. [Mike Clark]
* Tighten rescue clauses. #5985 [james@grayproductions.net]
* Fix send_data documentation typo. #5982 [brad@madriska.com]
* Switch to using FormEncodedPairParser for parsing request parameters. [Nicholas Seckar, DHH]
* respond_to .html now always renders #{action_name}.rhtml so that registered custom template handlers do not override it in priority. Custom mime types require a block and throw proper error now. [Tobias Luetke]
@@ -245,12 +416,6 @@
* Add UrlWriter to allow writing urls from Mailers and scripts. [Nicholas Seckar]
* Clean up and run the Active Record integration tests by default. #5854 [kevin.clark@gmail.com, Jeremy Kemper]
* Correct example in cookies docs. #5832 [jessemerriman@warpmail.net]
* Updated to script.aculo.us 1.6.2 [Thomas Fuchs]
* Relax Routing's anchor pattern warning; it was preventing use of [^/] inside restrictions. [Nicholas Seckar]
* Add controller_paths variable to Routing. [Nicholas Seckar]
@@ -261,8 +426,6 @@
* Invoke method_missing directly on hidden actions. Closes #3030. [Nicholas Seckar]
* Require Tempfile explicitly for TestUploadedFile due to changes in class auto loading. [Rick Olson]
* Add RoutingError exception when RouteSet fails to generate a path from a Named Route. [Rick Olson]
* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
@@ -277,8 +440,6 @@
* Added months and years to the resolution of DateHelper#distance_of_time_in_words, such that "60 days ago" becomes "2 months ago" #5611 [pjhyett@gmail.com]
* Short documentation to mention use of Mime::Type.register. #5710 [choonkeat@gmail.com]
* Make controller_path available as an instance method. #5724 [jmckible@gmail.com]
* Update query parser to support adjacent hashes. [Nicholas Seckar]
@@ -287,10 +448,6 @@
* Restrict Request Method hacking with ?_method to POST requests. [Rick Olson]
* Fix bug when passing multiple options to SimplyRestful, like :new => { :preview => :get, :draft => :get }. [Rick Olson, Josh Susser, Lars Pind]
* Dup the options passed to map.resources so that multiple resources get the same options. [Rick Olson]
* Fixed the new_#{resource}_url route and added named route tests for Simply Restful. [Rick Olson]
* Added map.resources from the Simply Restful plugin [DHH]. Examples (the API has changed to use plurals!):
@@ -318,14 +475,10 @@
* Provide support for decimal columns to form helpers. Closes #5672. [dave@pragprog.com]
* Update documentation for erb trim syntax. #5651 [matt@mattmargolis.net]
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info]
* Reset @html_document between requests so assert_tag works. #4810 [jarkko@jlaine.net, easleydp@gmail.com]
* Update render :partial documentation. #5646 [matt@mattmargolis.net]
* Integration tests behave well with render_component. #4632 [edward.frederick@revolution.com, dev.rubyonrails@maxdunn.com]
* Added exception handling of missing layouts #5373 [chris@ozmm.org]
@@ -342,7 +495,7 @@
* Avoid naming collision among compiled view methods. [Jeremy Kemper]
* Fix CGI extensions when they expect string but get nil in Windows. Closes #5276 [mislav@nippur.irb.hr]
* Fix CGI extensions when they expect string but get nil in Windows. Closes #5276 [Mislav Marohnic]
* Determine the correct template_root for deeply nested components. #2841 [s.brink@web.de]
@@ -360,8 +513,6 @@
* Make sure :id and friends are unescaped properly. #5275 [me@julik.nl]
* Fix documentation for with_routing to reflect new reality. #5281 [rramdas@gmail.com]
* Rewind readable CGI params so others may reread them (such as CGI::Session when passing the session id in a multipart form). #210 [mklame@atxeu.com, matthew@walker.wattle.id.au]
* Added Mime::TEXT (text/plain) and Mime::ICS (text/calendar) as new default types [DHH]
@@ -425,8 +576,6 @@
* Fix NoMethodError when parsing params like &&. [Adam Greenfield]
* Fix flip flopped logic in docs for url_for's :only_path option. Closes #4998. [esad@esse.at]
* form.text_area handles the :size option just like the original text_area (:size => '60x10' becomes cols="60" rows="10"). [Jeremy Kemper]
* Excise ingrown code from FormOptionsHelper#options_for_select. #5008 [anonymous]
@@ -435,43 +584,17 @@
map.connect '*path', :controller => 'files', :action => 'show'
* 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.]
* Use #flush between switching from #write to #syswrite. Closes #4907. [Blair Zajac <blair@orcaware.com>]
* Documentation fix: integration test scripts don't require integration_test. Closes #4914. [Frederick Ros <sl33p3r@free.fr>]
* ActionController::Base Summary documentation rewrite. Closes #4900. [kevin.clark@gmail.com]
* Fix text_helper.rb documentation rendering. Closes #4725. [Frederick Ros]
* Fixes bad rendering of JavaScriptMacrosHelper rdoc (closes #4910) [Frederick Ros]
* Allow error_messages_for to report errors for multiple objects, as well as support for customizing the name of the object in the error summary header. Closes #4186. [andrew@redlinesoftware.com, Marcel Molina Jr.]
error_messages_for :account, :user, :subscription, :object_name => :account
* Enhance documentation for setting headers in integration tests. Skip auto HTTP prepending when its already there. Closes #4079. [Rick Olson]
* Documentation for AbstractRequest. Closes #4895. [kevin.clark@gmail.com]
* Refactor various InstanceTag instance method to class methods. Closes #4800. [skaes@web.de]
* Remove all remaining references to @params in the documentation. [Marcel Molina Jr.]
* Add documentation for redirect_to :back's RedirectBackError exception. [Marcel Molina Jr.]
* Update layout and content_for documentation to use yield rather than magic @content_for instance variables. [Marcel Molina Jr.]
* Fix assert_redirected_to tests according to real-world usage. Also, don't fail if you add an extra :controller option: [Rick]
redirect_to :action => 'new'
assert_redirected_to :controller => 'monkeys', :action => 'new'
* Cache CgiRequest#request_parameters so that multiple calls don't re-parse multipart data. [Rick]
* Diff compared routing options. Allow #assert_recognizes to take a second arg as a hash to specify optional request method [Rick]
assert_recognizes({:controller => 'users', :action => 'index'}, 'users')
@@ -483,8 +606,6 @@
* Change link_to_function and button_to_function to (optionally) take an update_page block instead of a JavaScript string. Closes #4804. [zraii@comcast.net, Sam Stephenson]
* Fixed that remote_form_for can leave out the object parameter and default to the instance variable of the object_name, just like form_for [DHH]
* Modify routing so that you can say :require => { :method => :post } for a route, and the route will never be selected unless the request method is POST. Only works for route recognition, not for route generation. [Jamis Buck]
* Added :add_headers option to verify which merges a hash of name/value pairs into the response's headers hash if the prerequisites cannot be satisfied. [Sam Stephenson]
@@ -492,7 +613,43 @@
:render => { :status => 405, :text => "Must be post" },
:add_headers => { "Allow" => "POST" }
* Added ActionController.filter_parameter_logging that makes it easy to remove passwords, credit card numbers, and other sensitive information from being logged when a request is handled #1897 [jeremye@bsa.ca.gov]
*1.12.5* (August 10th, 2006)
* Updated security fix
*1.12.4* (August 8th, 2006)
* Cache CgiRequest#request_parameters so that multiple calls don't re-parse multipart data. [Rick]
* Fixed that remote_form_for can leave out the object parameter and default to the instance variable of the object_name, just like form_for [DHH]
* Added ActionController.filter_parameter_logging that makes it easy to remove passwords, credit card numbers, and other sensitive information from being logged when a request is handled. #1897 [jeremye@bsa.ca.gov]
* Fixed that real files and symlinks should be treated the same when compiling templates. #5438 [zachary@panandscan.com]
* Add :status option to send_data and send_file. Defaults to '200 OK'. #5243 [Manfred Stienstra <m.stienstra@fngtps.com>]
* Update documentation for erb trim syntax. #5651 [matt@mattmargolis.net]
* Short documentation to mention use of Mime::Type.register. #5710 [choonkeat@gmail.com]
*1.12.3* (June 28th, 2006)
* Fix broken traverse_to_controller. We now:
Look for a _controller.rb file under RAILS_ROOT to load.
If we find it, we require_dependency it and return the controller it defined. (If none was defined we stop looking.)
If we don't find it, we look for a .rb file under RAILS_ROOT to load. If we find it, and it loads a constant we keep looking.
Otherwise we check to see if a directory of the same name exists, and if it does we create a module for it.
*1.12.2* (June 27th, 2006)
* Refinement to avoid exceptions in traverse_to_controller.
* (Hackish) Fix loading of arbitrary files in Ruby's load path by traverse_to_controller. [Nicholas Seckar]
*1.12.1* (April 6th, 2006)
@@ -2727,9 +2884,9 @@ Default YAML web services were retired, ActionController::Base.param_parsers car
* Added pluralize method to the TextHelper that makes it easy to get strings like "1 message", "3 messages"
* Added proper escaping for the rescues [Andreas Schwartz]
* Added proper escaping for the rescues [Andreas Schwarz]
* Added proper escaping for the option and collection tags [Andreas Schwartz]
* Added proper escaping for the option and collection tags [Andreas Schwarz]
* Fixed NaN errors on benchmarking [Jim Weirich]

View File

@@ -75,7 +75,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true
s.requirements << 'none'
s.add_dependency('activesupport', '= 1.3.1' + PKG_BUILD)
s.add_dependency('activesupport', '= 1.4.4' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'action_controller'
@@ -144,11 +144,11 @@ end
desc "Publish the release files to RubyForge."
task :release => [ :package ] do
`rubyforge login`
require 'rubyforge'
for ext in %w( gem tgz zip )
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command
system(release_command)
end
end
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
rubyforge = RubyForge.new
rubyforge.login
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end

View File

@@ -30,7 +30,7 @@ unless defined?(ActiveSupport)
require 'active_support'
rescue LoadError
require 'rubygems'
require_gem 'activesupport'
gem 'activesupport'
end
end

View File

@@ -2,7 +2,7 @@ require 'rexml/document'
module ActionController #:nodoc:
module Assertions #:nodoc:
module DeprecatedAssertions
module DeprecatedAssertions #:nodoc:
def assert_success(message=nil) #:nodoc:
assert_response(:success, message)
end

View File

@@ -1,7 +1,7 @@
module ActionController
module Assertions
module DomAssertions
# test 2 html strings to be equivalent, i.e. identical up to reordering of attributes
# Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
def assert_dom_equal(expected, actual, message="")
clean_backtrace do
expected_dom = HTML::Document.new(expected).root
@@ -11,7 +11,7 @@ module ActionController
end
end
# negated form of +assert_dom_equivalent+
# The negated form of +assert_dom_equivalent+.
def assert_dom_not_equal(expected, actual, message="")
clean_backtrace do
expected_dom = HTML::Document.new(expected).root

View File

@@ -1,7 +1,7 @@
module ActionController
module Assertions
module ModelAssertions
# ensures that the passed record is valid by active record standards. returns the error messages if not
# Ensures that the passed record is valid by ActiveRecord standards and returns any error messages if it is not.
def assert_valid(record)
clean_backtrace do
assert record.valid?, record.errors.full_messages.join("\n")

View File

@@ -5,27 +5,31 @@ module ActionController
module Assertions
module ResponseAssertions
# Asserts that the response is one of the following types:
#
#
# * <tt>:success</tt>: Status code was 200
# * <tt>:redirect</tt>: Status code was in the 300-399 range
# * <tt>:missing</tt>: Status code was 404
# * <tt>:error</tt>: Status code was in the 500-599 range
#
# You can also pass an explicit status code number as the type, like assert_response(501)
# You can also pass an explicit status number like assert_response(501)
# or its symbolic equivalent assert_response(:not_implemented).
# See ActionController::StatusCodes for a full list.
def assert_response(type, message = nil)
clean_backtrace do
if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?")
assert_block("") { true } # to count the assertion
elsif type.is_a?(Fixnum) && @response.response_code == type
assert_block("") { true } # to count the assertion
elsif type.is_a?(Symbol) && @response.response_code == ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
assert_block("") { true } # to count the assertion
else
assert_block(build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code)) { false }
end
end
end
end
# Assert that the redirection options passed in match those of the redirect called in the latest action. This match can be partial,
# such that assert_redirected_to(:controller => "weblog") will also match the redirection of
# such that assert_redirected_to(:controller => "weblog") will also match the redirection of
# redirect_to(:controller => "weblog", :action => "show") and so on.
def assert_redirected_to(options = {}, message=nil)
clean_backtrace do
@@ -65,19 +69,21 @@ module ActionController
end
if value.respond_to?(:[]) && value['controller']
value['controller'] = value['controller'].to_s
if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/')
value['controller'] = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path)
new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path)
value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path)
end
value['controller'] = value['controller'][1..-1] if value['controller'].first == '/' # strip leading hash
end
url[key] = value
end
@response_diff = url[:expected].diff(url[:actual]) if url[:actual]
msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is <?>), difference: <?>",
msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is <?>), difference: <?>",
url[:actual], @response_diff)
assert_block(msg) do
url[:expected].keys.all? do |k|
if k == :controller then url[:expected][k] == ActionController::Routing.controller_relative_to(url[:actual][k], @controller.class.controller_path)
@@ -94,7 +100,7 @@ module ActionController
end.flatten
assert_equal(eurl, url, msg) if eurl && url
assert_equal(epath, path, msg) if epath && path
assert_equal(epath, path, msg) if epath && path
end
end
end
@@ -110,11 +116,12 @@ module ActionController
else
expected == rendered
end
end
end
end
end
private
# Recognizes the route for a given path.
def recognized_request_for(path, request_method = nil)
path = "/#{path}" unless path.first == '/'
@@ -127,9 +134,10 @@ module ActionController
request
end
# Proxy to to_param if the object will respond to it.
def parameterize(value)
value.respond_to?(:to_param) ? value.to_param : value
end
end
end
end
end

View File

@@ -3,13 +3,23 @@ module ActionController
module RoutingAssertions
# Asserts that the routing of the given path was handled correctly and that the parsed options match.
#
# assert_recognizes({:controller => 'items', :action => 'index'}, 'items')
# assert_recognizes({:controller => 'items', :action => 'index'}, 'items') # check the default action
# assert_recognizes({:controller => 'items', :action => 'list'}, 'items/list') # check a specific action
# assert_recognizes({:controller => 'items', :action => 'list', :id => '1'}, 'items/list/1') # check an action with a parameter
#
# Pass a hash in the second argument to specify the request method. This is useful for routes
# requiring a specific method.
# requiring a specific HTTP method. The hash should contain a :path with the incoming request path
# and a :method containing the required HTTP verb.
#
# # assert that POSTing to /items will call the create action on ItemsController
# assert_recognizes({:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post})
#
# You can also pass in "extras" with a hash containing URL parameters that would normally be in the query string. This can be used
# to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the
# extras argument, appending the query string on the path directly will not work. For example:
#
# # assert that a path of '/items/list/1?view=print' returns the correct options
# assert_recognizes({:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" })
def assert_recognizes(expected_options, path, extras={}, message=nil)
if path.is_a? Hash
request_method = path[:method]
@@ -33,7 +43,12 @@ module ActionController
end
end
# Asserts that the provided options can be used to generate the provided path.
# Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes.
# For example:
#
# assert_generates("/items", :controller => "items", :action => "index")
# assert_generates("/items/list", :controller => "items", :action => "list")
# assert_generates("/items/list/1", { :controller => "items", :action => "list", :id => "1" })
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
clean_backtrace do
expected_path = "/#{expected_path}" unless expected_path[0] == ?/
@@ -53,7 +68,8 @@ module ActionController
end
# Asserts that path and options match both ways; in other words, the URL generated from
# options is the same as path, and also that the options recognized from path are the same as options
# options is the same as path, and also that the options recognized from path are the same as options. This
# essentially combines assert_recognizes and assert_generates into one step.
def assert_routing(path, options, defaults={}, extras={}, message=nil)
assert_recognizes(options, path, extras, message)
@@ -66,6 +82,7 @@ module ActionController
end
private
# Recognizes the route for a given path.
def recognized_request_for(path, request_method = nil)
path = "/#{path}" unless path.first == '/'

View File

@@ -561,6 +561,8 @@ module ActionController
# RJS encodes double quotes and line breaks.
unescaped= rjs_string.gsub('\"', '"')
unescaped.gsub!('\n', "\n")
unescaped.gsub!('\076', '>')
unescaped.gsub!('\074', '<')
# RJS encodes non-ascii characters.
unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')}
unescaped

View File

@@ -292,6 +292,10 @@ module ActionController #:nodoc:
# Turn on +ignore_missing_templates+ if you want to unit test actions without making the associated templates.
cattr_accessor :ignore_missing_templates
# Controls the resource action separator
@@resource_action_separator = "/"
cattr_accessor :resource_action_separator
# Holds the request object that's primarily used to get environment variables through access like
# <tt>request.env["REQUEST_URI"]</tt>.
attr_internal :request
@@ -393,7 +397,8 @@ module ActionController #:nodoc:
elsif value.is_a?(Hash)
filtered_parameters[key] = filter_parameters(value)
elsif block_given?
key, value = key.dup, value.dup
key = key.dup
value = value.dup if value
yield key, value
filtered_parameters[key] = value
else
@@ -407,10 +412,13 @@ module ActionController #:nodoc:
# Don't render layouts for templates with the given extensions.
def exempt_from_layout(*extensions)
regexps = extensions.collect do |extension|
extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
end
@@exempt_from_layout.merge regexps
@@exempt_from_layout.merge extensions.collect { |extension|
if extension.is_a?(Regexp)
extension
else
/\.#{Regexp.escape(extension.to_s)}$/
end
}
end
end
@@ -535,8 +543,9 @@ module ActionController #:nodoc:
self.class.controller_path
end
# Test whether the session is enabled for this request.
def session_enabled?
request.session_options[:disabled] != false
request.session_options && request.session_options[:disabled] != false
end
protected
@@ -650,6 +659,20 @@ module ActionController #:nodoc:
#
# _Deprecation_ _notice_: This used to have the signature <tt>render_text("text", status = 200)</tt>
#
# === Rendering JSON
#
# Rendering JSON sets the content type to text/x-json and optionally wraps the JSON in a callback. It is expected
# that the response will be eval'd for use as a data structure.
#
# # Renders '{name: "David"}'
# render :json => {:name => "David"}.to_json
#
# Sometimes the result isn't handled directly by a script (such as when the request comes from a SCRIPT tag),
# so the callback option is provided for these cases.
#
# # Renders 'show({name: "David"})'
# render :json => {:name => "David"}.to_json, :callback => 'show'
#
# === Rendering an inline template
#
# Rendering of an inline template works as a cross between text and action rendering where the source for the template
@@ -734,6 +757,9 @@ module ActionController #:nodoc:
elsif xml = options[:xml]
render_xml(xml, options[:status])
elsif json = options[:json]
render_json(json, options[:callback], options[:status])
elsif partial = options[:partial]
partial = default_template_name if partial == true
if collection = options[:collection]
@@ -763,13 +789,11 @@ module ActionController #:nodoc:
# Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
# of sending it as the response body to the browser.
def render_to_string(options = nil, &block) #:doc:
result = ActiveSupport::Deprecation.silence { render(options, &block) }
ActiveSupport::Deprecation.silence { render(options, &block) }
ensure
erase_render_results
forget_variables_added_to_assigns
reset_variables_added_to_assigns
result
end
def render_action(action_name, status = nil, with_layout = true) #:nodoc:
@@ -816,6 +840,13 @@ module ActionController #:nodoc:
render_text(xml, status)
end
def render_json(json, callback = nil, status = nil) #:nodoc:
json = "#{callback}(#{json})" unless callback.blank?
response.content_type = Mime::JSON
render_text(json, status)
end
def render_nothing(status = nil) #:nodoc:
render_text(' ', status)
end
@@ -893,7 +924,7 @@ module ActionController #:nodoc:
response.redirected_to = nil
response.redirected_to_method_params = nil
response.headers['Status'] = DEFAULT_RENDER_STATUS_CODE
response.headers.delete('location')
response.headers.delete('Location')
end
# Erase both render and redirect results
@@ -1089,7 +1120,11 @@ module ActionController #:nodoc:
def assign_default_content_type_and_charset
response.content_type ||= Mime::HTML
response.charset ||= self.class.default_charset
response.charset ||= self.class.default_charset unless sending_file?
end
def sending_file?
response.headers["Content-Transfer-Encoding"] == "binary"
end
def action_methods
@@ -1164,10 +1199,9 @@ module ActionController #:nodoc:
end
def template_exempt_from_layout?(template_name = default_template_name)
@@exempt_from_layout.any? { |ext| template_name =~ ext } or
@template.pick_template_extension(template_name) == :rjs
rescue
false
extension = @template.pick_template_extension(template_name) rescue nil
name_with_extension = !template_name.include?('.') && extension ? "#{template_name}.#{extension}" : template_name
extension == :rjs || @@exempt_from_layout.any? { |ext| name_with_extension =~ ext }
end
def assert_existence_of_template_file(template_name)

View File

@@ -1,5 +1,6 @@
require 'fileutils'
require 'uri'
require 'set'
module ActionController #:nodoc:
# Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls
@@ -135,7 +136,7 @@ module ActionController #:nodoc:
private
def caching_allowed
!request.post? && response.headers['Status'] && response.headers['Status'].to_i < 400
request.get? && response.headers['Status'].to_i == 200
end
end
@@ -163,13 +164,24 @@ module ActionController #:nodoc:
module Actions
def self.included(base) #:nodoc:
base.extend(ClassMethods)
base.send(:attr_accessor, :rendered_action_cache)
base.class_eval do
attr_accessor :rendered_action_cache, :action_cache_path
alias_method_chain :protected_instance_variables, :action_caching
end
end
module ClassMethods #:nodoc:
def protected_instance_variables_with_action_caching
protected_instance_variables_without_action_caching + %w(@action_cache_path)
end
module ClassMethods
# Declares that +actions+ should be cached.
# See ActionController::Caching::Actions for details.
def caches_action(*actions)
return unless perform_caching
around_filter(ActionCacheFilter.new(*actions))
action_cache_filter = ActionCacheFilter.new(*actions)
before_filter action_cache_filter
after_filter action_cache_filter
end
end
@@ -185,70 +197,59 @@ module ActionController #:nodoc:
end
class ActionCacheFilter #:nodoc:
def initialize(*actions, &block)
@actions = actions
def initialize(*actions)
@actions = Set.new actions
end
def before(controller)
return unless @actions.include?(controller.action_name.intern)
action_cache_path = ActionCachePath.new(controller)
if cache = controller.read_fragment(action_cache_path.path)
return unless @actions.include?(controller.action_name.to_sym)
cache_path = ActionCachePath.new(controller, {})
if cache = controller.read_fragment(cache_path.path)
controller.rendered_action_cache = true
set_content_type!(action_cache_path)
set_content_type!(controller, cache_path.extension)
controller.send(:render_text, cache)
false
else
controller.action_cache_path = cache_path
end
end
def after(controller)
return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache
controller.write_fragment(ActionCachePath.path_for(controller), controller.response.body)
return if !@actions.include?(controller.action_name.to_sym) || controller.rendered_action_cache
controller.write_fragment(controller.action_cache_path.path, controller.response.body)
end
private
def set_content_type!(action_cache_path)
if extention = action_cache_path.extension
content_type = Mime::EXTENSION_LOOKUP[extention]
action_cache_path.controller.response.content_type = content_type.to_s
end
def set_content_type!(controller, extension)
controller.response.content_type = Mime::EXTENSION_LOOKUP[extension].to_s if extension
end
end
class ActionCachePath
attr_reader :controller, :options
attr_reader :path, :extension
class << self
def path_for(*args, &block)
new(*args).path
def path_for(controller, options)
new(controller, options).path
end
end
def initialize(controller, options = {})
@controller = controller
@options = options
end
def path
return @path if @path
@path = controller.url_for(options).split('://').last
normalize!
add_extension!
URI.unescape(@path)
end
def extension
@extension ||= extract_extension(controller.request.path)
@extension = extract_extension(controller.request.path)
path = controller.url_for(options).split('://').last
normalize!(path)
add_extension!(path, @extension)
@path = URI.unescape(path)
end
private
def normalize!
@path << 'index' if @path.last == '/'
def normalize!(path)
path << 'index' if path[-1] == ?/
end
def add_extension!
@path << ".#{extension}" if extension
def add_extension!(path, extension)
path << ".#{extension}" if extension
end
def extract_extension(file_path)
@@ -363,7 +364,12 @@ module ActionController #:nodoc:
# Name can take one of three forms:
# * String: This would normally take the form of a path like "pages/45/notes"
# * Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 }
# * Regexp: Will destroy all the matched fragments, example: %r{pages/\d*/notes} Ensure you do not specify start and finish in the regex (^$) because the actual filename matched looks like ./cache/filename/path.cache
# * Regexp: Will destroy all the matched fragments, example:
# %r{pages/\d*/notes}
# Ensure you do not specify start and finish in the regex (^$) because
# the actual filename matched looks like ./cache/filename/path.cache
# Regexp expiration is not supported on caches which can't iterate over
# all keys, such as memcached.
def expire_fragment(name, options = nil)
return unless perform_caching
@@ -384,6 +390,7 @@ module ActionController #:nodoc:
def expire_matched_fragments(matcher = /.*/, options = nil) #:nodoc:
expire_fragment(matcher, options)
end
deprecate :expire_matched_fragments => :expire_fragment
class UnthreadedMemoryStore #:nodoc:

View File

@@ -27,13 +27,6 @@ class CGI #:nodoc:
def request_parameters
CGIMethods.parse_request_parameters(params, env_table)
end
def redirect(where)
header({
"Status" => "302 Moved",
"location" => "#{where}"
})
end
def session(parameters = nil)
parameters = {} if parameters.nil?

View File

@@ -23,18 +23,19 @@ class CGIMethods #:nodoc:
def parse_request_parameters(params)
parser = FormEncodedPairParser.new
finished = false
until finished
finished = true
params = params.dup
until params.empty?
for key, value in params
next if key.blank?
if !key.include?('[')
if key.blank?
params.delete key
elsif !key.include?('[')
# much faster to test for the most common case first (GET)
# and avoid the call to build_deep_hash
parser.result[key] = get_typed_value(value[0])
params.delete key
elsif value.is_a?(Array)
parser.parse(key, get_typed_value(value.shift))
finished = false unless value.empty?
params.delete key if value.empty?
else
raise TypeError, "Expected array, found #{value.inspect}"
end
@@ -63,48 +64,55 @@ class CGIMethods #:nodoc:
private
def get_typed_value(value)
# test most frequent case first
if value.is_a?(String)
value
elsif value.respond_to?(:content_type) && ! value.content_type.blank?
# Uploaded file
unless value.respond_to?(:full_original_filename)
class << value
alias_method :full_original_filename, :original_filename
case value
when String
value
when NilClass
''
when Array
value.map { |v| get_typed_value(v) }
else
# Uploaded file provides content type and filename.
if value.respond_to?(:content_type) &&
!value.content_type.blank? &&
!value.original_filename.blank?
unless value.respond_to?(:full_original_filename)
class << value
alias_method :full_original_filename, :original_filename
# Take the basename of the upload's original filename.
# This handles the full Windows paths given by Internet Explorer
# (and perhaps other broken user agents) without affecting
# those which give the lone filename.
# The Windows regexp is adapted from Perl's File::Basename.
def original_filename
if md = /^(?:.*[:\\\/])?(.*)/m.match(full_original_filename)
md.captures.first
else
File.basename full_original_filename
# Take the basename of the upload's original filename.
# This handles the full Windows paths given by Internet Explorer
# (and perhaps other broken user agents) without affecting
# those which give the lone filename.
# The Windows regexp is adapted from Perl's File::Basename.
def original_filename
if md = /^(?:.*[:\\\/])?(.*)/m.match(full_original_filename)
md.captures.first
else
File.basename full_original_filename
end
end
end
end
# Return the same value after overriding original_filename.
value
# Multipart values may have content type, but no filename.
elsif value.respond_to?(:read)
result = value.read
value.rewind
result
# Unknown value, neither string nor multipart.
else
raise "Unknown form value: #{value.inspect}"
end
end
# Return the same value after overriding original_filename.
value
elsif value.respond_to?(:read)
# Value as part of a multipart request
result = value.read
value.rewind
result
elsif value.class == Array
value.collect { |v| get_typed_value(v) }
else
# other value (neither string nor a multipart request)
value.to_s
end
end
end
class FormEncodedPairParser < StringScanner
class FormEncodedPairParser < StringScanner #:nodoc:
attr_reader :top, :parent, :result
def initialize(pairs = [])

View File

@@ -0,0 +1,30 @@
# CGI::Session::PStore.initialize requires 'digest/md5' on every call.
# This makes sense when spawning processes per request, but is
# unnecessarily expensive when serving requests from a long-lived
# process.
require 'cgi/session'
require 'cgi/session/pstore'
require 'digest/md5'
class CGI::Session::PStore #:nodoc:
def initialize(session, option={})
dir = option['tmpdir'] || Dir::tmpdir
prefix = option['prefix'] || ''
id = session.session_id
md5 = Digest::MD5.hexdigest(id)[0,16]
path = dir+"/"+prefix+md5
path.untaint
if File::exist?(path)
@hash = nil
else
unless session.new_session
raise CGI::Session::NoSession, "uninitialized session"
end
@hash = {}
end
@p = ::PStore.new(path)
@p.transaction do |p|
File.chmod(0600, p.path)
end
end
end

View File

@@ -65,7 +65,7 @@ class CGI #:nodoc:
if env_qs.blank? && !(uri = env_table['REQUEST_URI']).blank?
uri.split('?', 2)[1] || ''
else
env_qs
env_qs || ''
end
end
end

View File

@@ -0,0 +1,30 @@
# CGI::Session#create_new_id requires 'digest/md5' on every call. This makes
# sense when spawning processes per request, but is unnecessarily expensive
# when serving requests from a long-lived process.
#
# http://railsexpress.de/blog/articles/2005/11/22/speeding-up-the-creation-of-new-sessions
require 'cgi/session'
require 'digest/md5'
class CGI
class Session #:nodoc:
private
# Create a new session id.
#
# The session id is an MD5 hash based upon the time,
# a random number, and a constant string. This routine
# is used internally for automatically generated
# session ids.
def create_new_id
md5 = Digest::MD5::new
now = Time::now
md5.update(now.to_s)
md5.update(String(now.usec))
md5.update(String(rand(0)))
md5.update(String($$))
md5.update('foobar')
@new_session = true
md5.hexdigest
end
end
end

View File

@@ -1,6 +1,8 @@
require 'action_controller/cgi_ext/cgi_ext'
require 'action_controller/cgi_ext/cookie_performance_fix'
require 'action_controller/cgi_ext/raw_post_data_fix'
require 'action_controller/cgi_ext/session_performance_fix'
require 'action_controller/cgi_ext/pstore_performance_fix'
module ActionController #:nodoc:
class Base
@@ -8,13 +10,13 @@ module ActionController #:nodoc:
# sessions (large performance increase if sessions are not needed). The <tt>session_options</tt> are the same as for CGI::Session:
#
# * <tt>:database_manager</tt> - standard options are CGI::Session::FileStore, CGI::Session::MemoryStore, and CGI::Session::PStore
# (default). Additionally, there is CGI::Session::DRbStore and CGI::Session::ActiveRecordStore. Read more about these in
# (default). Additionally, there is CGI::Session::DRbStore and CGI::Session::ActiveRecordStore. Read more about these in
# lib/action_controller/session.
# * <tt>:session_key</tt> - the parameter name used for the session id. Defaults to '_session_id'.
# * <tt>:session_id</tt> - the session id to use. If not provided, then it is retrieved from the +session_key+ parameter
# of the request, or automatically generated for a new session.
# * <tt>:session_id</tt> - the session id to use. If not provided, then it is retrieved from the +session_key+ cookie, or
# automatically generated for a new session.
# * <tt>:new_session</tt> - if true, force creation of a new session. If not set, a new session is only created if none currently
# exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set,
# exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set,
# an ArgumentError is raised.
# * <tt>:session_expires</tt> - the time the current session expires, as a +Time+ object. If not set, the session will continue
# indefinitely.
@@ -22,10 +24,12 @@ module ActionController #:nodoc:
# server.
# * <tt>:session_secure</tt> - if +true+, this session will only work over HTTPS.
# * <tt>:session_path</tt> - the path for which this session applies. Defaults to the directory of the CGI script.
def self.process_cgi(cgi = CGI.new, session_options = {})
# * <tt>:cookie_only</tt> - if +true+ (the default), session IDs will only be accepted from cookies and not from
# the query string or POST parameters. This protects against session fixation attacks.
def self.process_cgi(cgi = CGI.new, session_options = {})
new.process_cgi(cgi, session_options)
end
def process_cgi(cgi, session_options = {}) #:nodoc:
process(CgiRequest.new(cgi, session_options), CgiResponse.new(cgi)).out
end
@@ -33,11 +37,14 @@ module ActionController #:nodoc:
class CgiRequest < AbstractRequest #:nodoc:
attr_accessor :cgi, :session_options
class SessionFixationAttempt < StandardError; end #:nodoc:
DEFAULT_SESSION_OPTIONS = {
:database_manager => CGI::Session::PStore,
:prefix => "ruby_sess.",
:session_path => "/"
:session_path => "/",
:session_key => "_session_id",
:cookie_only => true
} unless const_defined?(:DEFAULT_SESSION_OPTIONS)
def initialize(cgi, session_options = {})
@@ -47,11 +54,15 @@ module ActionController #:nodoc:
super()
end
def cookie_only?
session_options_with_string_keys['cookie_only']
end
def query_string
if (qs = @cgi.query_string) && !qs.empty?
qs
elsif uri = @env['REQUEST_URI']
parts = uri.split('?')
parts = uri.split('?')
parts.shift
parts.join('?')
else
@@ -60,7 +71,8 @@ module ActionController #:nodoc:
end
def query_parameters
(qs = self.query_string).empty? ? {} : CGIMethods.parse_query_parameters(qs)
@query_parameters ||=
(qs = self.query_string).empty? ? {} : CGIMethods.parse_query_parameters(qs)
end
def request_parameters
@@ -71,7 +83,7 @@ module ActionController #:nodoc:
CGIMethods.parse_request_parameters(@cgi.params)
end
end
def cookies
@cgi.cookies.freeze
end
@@ -106,10 +118,24 @@ module ActionController #:nodoc:
@session = Hash.new
else
stale_session_check! do
if session_options_with_string_keys['new_session'] == true
@session = new_session
else
@session = CGI::Session.new(@cgi, session_options_with_string_keys)
if cookie_only? && request_parameters[session_options_with_string_keys['session_key']]
raise SessionFixationAttempt
end
case value = session_options_with_string_keys['new_session']
when true
@session = new_session
when false
begin
@session = CGI::Session.new(@cgi, session_options_with_string_keys)
# CGI::Session raises ArgumentError if 'new_session' == false
# and no session cookie or query param is present.
rescue ArgumentError
@session = Hash.new
end
when nil
@session = CGI::Session.new(@cgi, session_options_with_string_keys)
else
raise ArgumentError, "Invalid new_session option: #{value}"
end
@session['__valid_session']
end
@@ -159,7 +185,7 @@ end_msg
end
def session_options_with_string_keys
@session_options_with_string_keys ||= DEFAULT_SESSION_OPTIONS.merge(@session_options).inject({}) { |options, (k,v)| options[k.to_s] = v; options }
@session_options_with_string_keys ||= DEFAULT_SESSION_OPTIONS.merge(@session_options).stringify_keys
end
end
@@ -170,7 +196,9 @@ end_msg
end
def out(output = $stdout)
convert_content_type!(@headers)
convert_content_type!
set_content_length!
output.binmode if output.respond_to?(:binmode)
output.sync = false if output.respond_to?(:sync=)
@@ -195,16 +223,22 @@ end_msg
end
private
def convert_content_type!(headers)
if header = headers.delete("Content-Type")
headers["type"] = header
def convert_content_type!
if content_type = @headers.delete("Content-Type")
@headers["type"] = content_type
end
if header = headers.delete("Content-type")
headers["type"] = header
if content_type = @headers.delete("Content-type")
@headers["type"] = content_type
end
if header = headers.delete("content-type")
headers["type"] = header
if content_type = @headers.delete("content-type")
@headers["type"] = content_type
end
end
# Don't set the Content-Length for block-based bodies as that would mean reading it all into memory. Not nice
# for, say, a 2GB streaming file.
def set_content_length!
@headers["Content-Length"] = @body.size unless @body.respond_to?(:call)
end
end
end

View File

@@ -75,11 +75,13 @@ module ActionController #:nodoc:
# will also use /code/weblog/components as template root
# and find templates in /code/weblog/components/admin/parties/users/
def uses_component_template_root
path_of_calling_controller = File.dirname(caller[0].split(/:\d+:/, 2).first)
path_of_calling_controller = File.dirname(caller[1].split(/:\d+:/, 2).first)
path_of_controller_root = path_of_calling_controller.sub(/#{Regexp.escape(File.dirname(controller_path))}$/, "")
self.template_root = path_of_controller_root
end
deprecate :uses_component_template_root => 'Components are deprecated and will be removed in Rails 2.0.'
end
module InstanceMethods

View File

@@ -47,7 +47,10 @@ module ActionController #:nodoc:
# Returns the value of the cookie by +name+ -- or nil if no such cookie exists. You set new cookies using either the cookie method
# or cookies[]= (for simple name/value cookies without options).
def [](name)
@cookies[name.to_s].value.first if @cookies[name.to_s] && @cookies[name.to_s].respond_to?(:value)
cookie = @cookies[name.to_s]
if cookie && cookie.respond_to?(:value)
cookie.size > 1 ? cookie.value : cookie.value.to_s
end
end
def []=(name, options)
@@ -62,9 +65,11 @@ module ActionController #:nodoc:
end
# Removes the cookie on the client machine by setting the value to an empty string
# and setting its expiration date into the past
def delete(name)
set_cookie("name" => name.to_s, "value" => "", "expires" => Time.at(0))
# and setting its expiration date into the past. Like []=, you can pass in an options
# hash to delete cookies with extra data such as a +path+.
def delete(name, options = {})
options.stringify_keys!
set_cookie(options.merge("name" => name.to_s, "value" => "", "expires" => Time.at(0)))
end
private

View File

@@ -81,10 +81,10 @@ module ActionController #:nodoc:
# can use <tt>prepend_before_filter</tt> and <tt>prepend_after_filter</tt>. Filters added by these methods will be put at the
# beginning of their respective chain and executed before the rest. For example:
#
# class ShoppingController
# class ShoppingController < ActionController::Base
# before_filter :verify_open_shop
#
# class CheckoutController
# class CheckoutController < ShoppingController
# prepend_before_filter :ensure_items_in_cart, :ensure_items_in_stock
#
# The filter chain for the CheckoutController is now <tt>:ensure_items_in_cart, :ensure_items_in_stock,</tt>
@@ -214,9 +214,10 @@ module ActionController #:nodoc:
# == Filter Chain Halting
#
# <tt>before_filter</tt> and <tt>around_filter</tt> may halt the request
# before controller action is run. This is useful, for example, to deny
# before a controller action is run. This is useful, for example, to deny
# access to unauthenticated users or to redirect from http to https.
# Simply return false from the filter or call render or redirect.
# After filters will not be executed if the filter chain is halted.
#
# Around filters halt the request unless the action block is called.
# Given these filters
@@ -238,12 +239,12 @@ module ActionController #:nodoc:
# . . /
# . #around (code after yield)
# . /
# #after (actual filter code is run)
# #after (actual filter code is run, unless the around filter does not yield)
#
# If #around returns before yielding, only #after will be run. The #before
# filter and controller action will not be run. If #before returns false,
# the second half of #around and all of #after will still run but the
# action will not.
# If #around returns before yielding, #after will still not be run. The #before
# filter and controller action will not be run. If #before returns false,
# the second half of #around and will still run but #after and the
# action will not. If #around does not yield, #after will not be run.
module ClassMethods
# The passed <tt>filters</tt> will be appended to the filter_chain and
# will execute before the action on this controller is performed.
@@ -263,13 +264,13 @@ module ActionController #:nodoc:
# The passed <tt>filters</tt> will be appended to the array of filters
# that run _after_ actions on this controller are performed.
def append_after_filter(*filters, &block)
prepend_filter_to_chain(filters, :after, &block)
append_filter_to_chain(filters, :after, &block)
end
# The passed <tt>filters</tt> will be prepended to the array of filters
# that run _after_ actions on this controller are performed.
def prepend_after_filter(*filters, &block)
append_filter_to_chain(filters, :after, &block)
prepend_filter_to_chain(filters, :after, &block)
end
# Shorthand for append_after_filter since it's the most common.
@@ -362,12 +363,12 @@ module ActionController #:nodoc:
# Returns a mapping between filters and the actions that may run them.
def included_actions #:nodoc:
read_inheritable_attribute("included_actions") || {}
@included_actions ||= read_inheritable_attribute("included_actions") || {}
end
# Returns a mapping between filters and actions that may not run them.
def excluded_actions #:nodoc:
read_inheritable_attribute("excluded_actions") || {}
@excluded_actions ||= read_inheritable_attribute("excluded_actions") || {}
end
# Find a filter in the filter_chain where the filter method matches the _filter_ param
@@ -381,10 +382,11 @@ module ActionController #:nodoc:
# Returns true if the filter is excluded from the given action
def filter_excluded_from_action?(filter,action) #:nodoc:
if (ia = included_actions[filter]) && !ia.empty?
case
when ia = included_actions[filter]
!ia.include?(action)
else
(excluded_actions[filter] || []).include?(action)
when ea = excluded_actions[filter]
ea.include?(action)
end
end
@@ -397,20 +399,28 @@ module ActionController #:nodoc:
@filter = filter
end
def type
:around
end
def before?
false
type == :before
end
def after?
false
type == :after
end
def around?
true
type == :around
end
def run(controller)
raise ActionControllerError, 'No filter type: Nothing to do here.'
end
def call(controller, &block)
raise(ActionControllerError, 'No filter type: Nothing to do here.')
run(controller)
end
end
@@ -420,35 +430,38 @@ module ActionController #:nodoc:
def filter
@filter.filter
end
def around?
false
end
end
class BeforeFilterProxy < FilterProxy #:nodoc:
def before?
true
def type
:before
end
def call(controller, &block)
if false == @filter.call(controller) # must only stop if equal to false. only filters returning false are halted.
controller.halt_filter_chain(@filter, :returned_false)
else
yield
def run(controller)
# only filters returning false are halted.
if false == @filter.call(controller)
controller.send :halt_filter_chain, @filter, :returned_false
end
end
def call(controller)
yield unless run(controller)
end
end
class AfterFilterProxy < FilterProxy #:nodoc:
def after?
true
def type
:after
end
def call(controller, &block)
yield
def run(controller)
@filter.call(controller)
end
def call(controller)
yield
run(controller)
end
end
class SymbolFilter < Filter #:nodoc:
@@ -485,29 +498,72 @@ module ActionController #:nodoc:
end
end
class ClassBeforeFilter < Filter #:nodoc:
def call(controller, &block)
@filter.before(controller)
end
end
class ClassAfterFilter < Filter #:nodoc:
def call(controller, &block)
@filter.after(controller)
end
end
protected
def append_filter_to_chain(filters, position = :around, &block)
write_inheritable_array('filter_chain', create_filters(filters, position, &block) )
def append_filter_to_chain(filters, filter_type = :around, &block)
pos = find_filter_append_position(filters, filter_type)
update_filter_chain(filters, filter_type, pos, &block)
end
def prepend_filter_to_chain(filters, position = :around, &block)
write_inheritable_attribute('filter_chain', create_filters(filters, position, &block) + filter_chain)
def prepend_filter_to_chain(filters, filter_type = :around, &block)
pos = find_filter_prepend_position(filters, filter_type)
update_filter_chain(filters, filter_type, pos, &block)
end
def create_filters(filters, position, &block) #:nodoc:
def update_filter_chain(filters, filter_type, pos, &block)
new_filters = create_filters(filters, filter_type, &block)
new_chain = filter_chain.insert(pos, new_filters).flatten
write_inheritable_attribute('filter_chain', new_chain)
end
def find_filter_append_position(filters, filter_type)
# appending an after filter puts it at the end of the call chain
# before and around filters go before the first after filter in the chain
unless filter_type == :after
filter_chain.each_with_index do |f,i|
return i if f.after?
end
end
return -1
end
def find_filter_prepend_position(filters, filter_type)
# prepending a before or around filter puts it at the front of the call chain
# after filters go before the first after filter in the chain
if filter_type == :after
filter_chain.each_with_index do |f,i|
return i if f.after?
end
return -1
end
return 0
end
def create_filters(filters, filter_type, &block) #:nodoc:
filters, conditions = extract_conditions(filters, &block)
filters.map! { |filter| find_or_create_filter(filter,position) }
filters.map! { |filter| find_or_create_filter(filter, filter_type) }
update_conditions(filters, conditions)
filters
end
def find_or_create_filter(filter,position)
if found_filter = find_filter(filter) { |f| f.send("#{position}?") }
def find_or_create_filter(filter, filter_type)
if found_filter = find_filter(filter) { |f| f.type == filter_type }
found_filter
else
f = class_for_filter(filter).new(filter)
f = class_for_filter(filter, filter_type).new(filter)
# apply proxy to filter if necessary
case position
case filter_type
when :before
BeforeFilterProxy.new(f)
when :after
@@ -520,7 +576,7 @@ module ActionController #:nodoc:
# The determination of the filter type was once done at run time.
# This method is here to extract as much logic from the filter run time as possible
def class_for_filter(filter) #:nodoc:
def class_for_filter(filter, filter_type) #:nodoc:
case
when filter.is_a?(Symbol)
SymbolFilter
@@ -534,8 +590,12 @@ module ActionController #:nodoc:
end
when filter.respond_to?(:filter)
ClassFilter
when filter.respond_to?(:before) && filter_type == :before
ClassBeforeFilter
when filter.respond_to?(:after) && filter_type == :after
ClassAfterFilter
else
raise(ActionControllerError, 'A filters must be a Symbol, Proc, Method, or object responding to filter.')
raise(ActionControllerError, 'A filter must be a Symbol, Proc, Method, or object responding to filter, after or before.')
end
end
@@ -550,8 +610,8 @@ module ActionController #:nodoc:
return if conditions.empty?
if conditions[:only]
write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only]))
else
write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) if conditions[:except]
elsif conditions[:except]
write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except]))
end
end
@@ -576,9 +636,9 @@ module ActionController #:nodoc:
def remove_actions_from_included_actions!(filters,*actions)
actions = actions.flatten.map(&:to_s)
updated_hash = filters.inject(included_actions) do |hash,filter|
updated_hash = filters.inject(read_inheritable_attribute('included_actions')||{}) do |hash,filter|
ia = (hash[filter] || []) - actions
ia.blank? ? hash.delete(filter) : hash[filter] = ia
ia.empty? ? hash.delete(filter) : hash[filter] = ia
hash
end
write_inheritable_attribute('included_actions', updated_hash)
@@ -595,7 +655,9 @@ module ActionController #:nodoc:
def proxy_before_and_after_filter(filter) #:nodoc:
return filter unless filter_responds_to_before_and_after(filter)
Proc.new do |controller, action|
unless filter.before(controller) == false
if filter.before(controller) == false
controller.send :halt_filter_chain, filter, :returned_false
else
begin
action.call
ensure
@@ -615,55 +677,90 @@ module ActionController #:nodoc:
end
end
def perform_action_with_filters
#result = perform_filters do
# perform_action_without_filters unless performed?
#end
@before_filter_chain_aborted = (call_filter(self.class.filter_chain, 0) == false)
end
protected
def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc:
@before_filter_chain_aborted = false
process_without_filters(request, response, method, *arguments)
end
def filter_chain
self.class.filter_chain
end
def call_filter(chain, index)
return (performed? || perform_action_without_filters) if index >= chain.size
filter = chain[index]
return call_filter(chain, index.next) if self.class.filter_excluded_from_action?(filter,action_name)
halted = false
filter.call(self) do
halted = call_filter(chain, index.next)
end
halt_filter_chain(filter.filter, :no_yield) if halted == false
halted
end
def halt_filter_chain(filter, reason)
if logger
case reason
when :no_yield
logger.info "Filter chain halted as [#{filter.inspect}] did not yield."
when :returned_false
logger.info "Filter chain halted as [#{filter.inspect}] returned false."
end
end
return false
def perform_action_with_filters
call_filters(self.class.filter_chain, 0, 0)
end
private
def process_cleanup_with_filters
if @before_filter_chain_aborted
close_session
def call_filters(chain, index, nesting)
index = run_before_filters(chain, index, nesting)
aborted = @before_filter_chain_aborted
perform_action_without_filters unless performed? || aborted
return index if nesting != 0 || aborted
run_after_filters(chain, index)
end
def skip_excluded_filters(chain, index)
while (filter = chain[index]) && self.class.filter_excluded_from_action?(filter, action_name)
index = index.next
end
[filter, index]
end
def run_before_filters(chain, index, nesting)
while chain[index]
filter, index = skip_excluded_filters(chain, index)
break unless filter # end of call chain reached
case filter.type
when :before
filter.run(self) # invoke before filter
index = index.next
break if @before_filter_chain_aborted
when :around
yielded = false
filter.call(self) do
yielded = true
# all remaining before and around filters will be run in this call
index = call_filters(chain, index.next, nesting.next)
end
halt_filter_chain(filter, :did_not_yield) unless yielded
break
else
process_cleanup_without_filters
break # no before or around filters left
end
end
index
end
def run_after_filters(chain, index)
seen_after_filter = false
while chain[index]
filter, index = skip_excluded_filters(chain, index)
break unless filter # end of call chain reached
case filter.type
when :after
seen_after_filter = true
filter.run(self) # invoke after filter
else
# implementation error or someone has mucked with the filter chain
raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter
end
index = index.next
end
index.next
end
def halt_filter_chain(filter, reason)
@before_filter_chain_aborted = true
logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger
false
end
def process_cleanup_with_filters
if @before_filter_chain_aborted
close_session
else
process_cleanup_without_filters
end
end
end
end
end

View File

@@ -67,7 +67,7 @@ module ActionController
@https = false
@cookies = {}
@controller = @request = @response = nil
self.host = "www.example.com"
self.remote_addr = "127.0.0.1"
self.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
@@ -89,7 +89,7 @@ module ActionController
# session.https!
# session.https!(false)
def https!(flag=true)
@https = flag
@https = flag
end
# Return +true+ if the session is mimicing a secure HTTPS request.
@@ -113,7 +113,7 @@ module ActionController
# performed on the location header.
def follow_redirect!
raise "not a redirect! #{@status} #{@status_message}" unless redirect?
get(interpret_uri(headers["location"].first))
get(interpret_uri(headers['location'].first))
status
end
@@ -143,10 +143,10 @@ module ActionController
# Performs a GET request with the given parameters. The parameters may
# be +nil+, a Hash, or a string that is appropriately encoded
# (application/x-www-form-urlencoded or multipart/form-data). The headers
# should be a hash. The keys will automatically be upcased, with the
# should be a hash. The keys will automatically be upcased, with the
# prefix 'HTTP_' added if needed.
#
# You can also perform POST, PUT, DELETE, and HEAD requests with #post,
# You can also perform POST, PUT, DELETE, and HEAD requests with #post,
# #put, #delete, and #head.
def get(path, parameters=nil, headers=nil)
process :get, path, parameters, headers
@@ -161,31 +161,41 @@ module ActionController
def put(path, parameters=nil, headers=nil)
process :put, path, parameters, headers
end
# Performs a DELETE request with the given parameters. See get() for more details.
def delete(path, parameters=nil, headers=nil)
process :delete, path, parameters, headers
end
# Performs a HEAD request with the given parameters. See get() for more details.
def head(path, parameters=nil, headers=nil)
process :head, path, parameters, headers
end
# Performs an XMLHttpRequest request with the given parameters, mimicing
# the request environment created by the Prototype library. The parameters
# may be +nil+, a Hash, or a string that is appropriately encoded
# (application/x-www-form-urlencoded or multipart/form-data). The headers
# should be a hash. The keys will automatically be upcased, with the
# prefix 'HTTP_' added if needed.
def xml_http_request(path, parameters=nil, headers=nil)
headers = (headers || {}).merge(
"X-Requested-With" => "XMLHttpRequest",
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
)
# Performs an XMLHttpRequest request with the given parameters, mirroring
# a request from the Prototype library.
#
# The request_method is :get, :post, :put, :delete or :head; the
# parameters are +nil+, a hash, or a url-encoded or multipart string;
# the headers are a hash. Keys are automatically upcased and prefixed
# with 'HTTP_' if not already.
#
# This method used to omit the request_method parameter, assuming it
# was :post. This was deprecated in Rails 1.2.4. Always pass the request
# method as the first argument.
def xml_http_request(request_method, path, parameters = nil, headers = nil)
unless request_method.is_a?(Symbol)
ActiveSupport::Deprecation.warn 'xml_http_request now takes the request_method (:get, :post, etc.) as the first argument. It used to assume :post, so add the :post argument to your existing method calls to silence this warning.'
request_method, path, parameters, headers = :post, request_method, path, parameters
end
post(path, parameters, headers)
headers ||= {}
headers['X-Requested-With'] = 'XMLHttpRequest'
headers['Accept'] = 'text/javascript, text/html, application/xml, text/xml, */*'
process(request_method, path, parameters, headers)
end
alias xhr :xml_http_request
# Returns the URL for the given options, according to the rules specified
# in the application's routes.
@@ -292,7 +302,7 @@ module ActionController
@status = @status.to_i
end
# Encode the cookies hash in a format suitable for passing to a
# Encode the cookies hash in a format suitable for passing to a
# request.
def encode_cookies
cookies.inject("") do |string, (name, value)|
@@ -450,7 +460,7 @@ module ActionController
# without any test methods.
def run(*args) #:nodoc:
return if @method_name == "default_test"
super
super
end
# Because of how use_instantiated_fixtures and use_transactional_fixtures
@@ -490,9 +500,11 @@ module ActionController
@integration_session = open_session
end
%w(get post cookies assigns xml_http_request).each do |method|
%w(get post put head delete cookies assigns xml_http_request).each do |method|
define_method(method) do |*args|
reset! unless @integration_session
# reset the html_document variable, but only for new get/post calls
@html_document = nil unless %w(cookies assigns).include?(method)
returning @integration_session.send(method, *args) do
copy_session_variables!
end

View File

@@ -27,9 +27,9 @@ module ActionController #:nodoc:
# With layouts, you can flip it around and have the common structure know where to insert changing content. This means
# that the header and footer are only mentioned in one place, like this:
#
# <!-- The header part of this layout -->
# // The header part of this layout
# <%= yield %>
# <!-- The footer part of this layout -->
# // The footer part of this layout -->
#
# And then you have content pages that look like this:
#
@@ -38,9 +38,9 @@ module ActionController #:nodoc:
# Not a word about common structures. At rendering time, the content page is computed and then inserted in the layout,
# like this:
#
# <!-- The header part of this layout -->
# // The header part of this layout
# hello world
# <!-- The footer part of this layout -->
# // The footer part of this layout -->
#
# == Accessing shared variables
#
@@ -266,7 +266,7 @@ module ActionController #:nodoc:
def candidate_for_layout?(options)
(options.has_key?(:layout) && options[:layout] != false) ||
options.values_at(:text, :xml, :file, :inline, :partial, :nothing).compact.empty? &&
options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing).compact.empty? &&
!template_exempt_from_layout?(default_template_name(options[:action] || options[:template]))
end

View File

@@ -24,7 +24,7 @@ module ActionController
define_method("set_#{object}_#{attribute}") do
@item = object.to_s.camelize.constantize.find(params[:id])
@item.update_attribute(attribute, params[:value])
render :text => @item.send(attribute)
render :text => @item.send(attribute).to_s
end
end
end

View File

@@ -135,12 +135,14 @@ module Mime
HTML = Type.new "text/html", :html, %w( application/xhtml+xml )
JS = Type.new "text/javascript", :js, %w( application/javascript application/x-javascript )
ICS = Type.new "text/calendar", :ics
CSV = Type.new "text/csv", :csv
XML = Type.new "application/xml", :xml, %w( text/xml application/x-xml )
RSS = Type.new "application/rss+xml", :rss
ATOM = Type.new "application/atom+xml", :atom
YAML = Type.new "application/x-yaml", :yaml, %w( text/yaml )
JSON = Type.new "application/json", :json, %w( text/x-json )
SET = [ ALL, TEXT, HTML, JS, ICS, XML, RSS, ATOM, YAML ]
SET = [ ALL, TEXT, HTML, JS, ICS, XML, RSS, ATOM, YAML, JSON ]
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k == "" }
@@ -157,6 +159,8 @@ module Mime
LOOKUP["text/calendar"] = ICS
LOOKUP["text/csv"] = CSV
LOOKUP["application/xml"] = XML
LOOKUP["text/xml"] = XML
LOOKUP["application/x-xml"] = XML
@@ -167,7 +171,10 @@ module Mime
LOOKUP["application/rss+xml"] = RSS
LOOKUP["application/atom+xml"] = ATOM
LOOKUP["application/json"] = JSON
LOOKUP["text/x-json"] = JSON
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k == "" }
EXTENSION_LOOKUP["html"] = HTML
@@ -181,9 +188,13 @@ module Mime
EXTENSION_LOOKUP["ics"] = ICS
EXTENSION_LOOKUP["csv"] = CSV
EXTENSION_LOOKUP["yml"] = YAML
EXTENSION_LOOKUP["yaml"] = YAML
EXTENSION_LOOKUP["rss"] = RSS
EXTENSION_LOOKUP["atom"] = ATOM
end
EXTENSION_LOOKUP["json"] = JSON
end

View File

@@ -1,7 +1,9 @@
module ActionController
# === Action Pack pagination for Active Record collections
#
# DEPRECATION WARNING: Pagination will be separated into its own plugin with Rails 2.0.
# DEPRECATION WARNING: Pagination will be moved to a plugin in Rails 2.0.
# Install the classic_pagination plugin for forward compatibility:
# script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination
#
# The Pagination module aids in the process of paging large collections of
# Active Record objects. It offers macro-style automatic fetching of your
@@ -130,6 +132,8 @@ module ActionController
paginator_and_collection_for(collection_id, options)
end
deprecate :paginate => 'Pagination is moving to a plugin in Rails 2.0: script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination'
# These methods become class methods on any controller
module ClassMethods
# Creates a +before_filter+ which automatically paginates an Active
@@ -148,6 +152,8 @@ module ActionController
OPTIONS[self][collection_id] = options
end
end
deprecate :paginate => 'Pagination is moving to a plugin in Rails 2.0: script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination'
end
def create_paginators_and_retrieve_collections #:nodoc:

View File

@@ -13,14 +13,18 @@ module ActionController
@parameters ||= request_parameters.update(query_parameters).update(path_parameters).with_indifferent_access
end
# Returns the HTTP request method as a lowercase symbol (:get, for example)
# Returns the HTTP request method as a lowercase symbol (:get, for example). Note, HEAD is returned as :get
# since the two are supposedly to be functionaly equivilent for all purposes except that HEAD won't return a response
# body (which Rails also takes care of elsewhere).
def method
@request_method ||= (!parameters[:_method].blank? && @env['REQUEST_METHOD'] == 'POST') ?
parameters[:_method].to_s.downcase.to_sym :
@env['REQUEST_METHOD'].downcase.to_sym
@request_method == :head ? :get : @request_method
end
# Is this a GET request? Equivalent to request.method == :get
# Is this a GET (or HEAD) request? Equivalent to request.method == :get
def get?
method == :get
end
@@ -40,9 +44,10 @@ module ActionController
method == :delete
end
# Is this a HEAD request? Equivalent to request.method == :head
# Is this a HEAD request? HEAD is mapped as :get for request.method, so here we ask the
# REQUEST_METHOD header directly. Thus, for head, both get? and head? will return true.
def head?
method == :head
@env['REQUEST_METHOD'].downcase.to_sym == :head
end
# Determine whether the body of a HTTP call is URL-encoded (default)
@@ -130,19 +135,21 @@ module ActionController
@env['RAW_POST_DATA']
end
# Returns the request URI correctly, taking into account the idiosyncracies
# of the various servers.
# Return the request URI, accounting for server idiosyncracies.
# WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
def request_uri
if uri = @env['REQUEST_URI']
(%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri # Remove domain, which webrick puts into the request_uri.
else # REQUEST_URI is blank under IIS - get this from PATH_INFO and SCRIPT_NAME
# Remove domain, which webrick puts into the request_uri.
(%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
else
# Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
uri = @env['PATH_INFO']
uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
uri << '?' << env_qs
end
uri
@env['REQUEST_URI'] = uri
end
end

View File

@@ -34,14 +34,16 @@ module ActionController #:nodoc:
# Overwrite to implement custom logging of errors. By default logs as fatal.
def log_error(exception) #:doc:
if ActionView::TemplateError === exception
logger.fatal(exception.to_s)
else
logger.fatal(
"\n\n#{exception.class} (#{exception.message}):\n " +
clean_backtrace(exception).join("\n ") +
"\n\n"
)
ActiveSupport::Deprecation.silence do
if ActionView::TemplateError === exception
logger.fatal(exception.to_s)
else
logger.fatal(
"\n\n#{exception.class} (#{exception.message}):\n " +
clean_backtrace(exception).join("\n ") +
"\n\n"
)
end
end
end

View File

@@ -2,48 +2,68 @@ module ActionController
module Resources
class Resource #:nodoc:
attr_reader :collection_methods, :member_methods, :new_methods
attr_reader :path_prefix, :name_prefix
attr_reader :path_prefix, :new_name_prefix
attr_reader :plural, :singular
attr_reader :options
def initialize(entities, options)
@plural = entities
@singular = options[:singular] || plural.to_s.singularize
@options = options
arrange_actions
add_default_actions
set_prefixes
end
def controller
(options[:controller] || plural).to_s
@controller ||= (options[:controller] || plural).to_s
end
def path
"#{path_prefix}/#{plural}"
@path ||= "#{path_prefix}/#{plural}"
end
def new_path
"#{path}/new"
@new_path ||= "#{path}/new"
end
def member_path
"#{path}/:id"
@member_path ||= "#{path}/:id"
end
def nesting_path_prefix
"#{path}/:#{singular}_id"
@nesting_path_prefix ||= "#{path}/:#{singular}_id"
end
private
def deprecate_name_prefix?
@name_prefix.blank? && !@new_name_prefix.blank?
end
def name_prefix
deprecate_name_prefix? ? @new_name_prefix : @name_prefix
end
def old_name_prefix
@name_prefix
end
def nesting_name_prefix
"#{new_name_prefix}#{singular}_"
end
def action_separator
@action_separator ||= Base.resource_action_separator
end
protected
def arrange_actions
@collection_methods = arrange_actions_by_methods(options.delete(:collection))
@member_methods = arrange_actions_by_methods(options.delete(:member))
@new_methods = arrange_actions_by_methods(options.delete(:new))
end
def add_default_actions
add_default_action(member_methods, :get, :edit)
add_default_action(new_methods, :get, :new)
@@ -52,6 +72,7 @@ module ActionController
def set_prefixes
@path_prefix = options.delete(:path_prefix)
@name_prefix = options.delete(:name_prefix)
@new_name_prefix = options.delete(:new_name_prefix)
end
def arrange_actions_by_methods(actions)
@@ -60,12 +81,25 @@ module ActionController
flipped_hash
end
end
def add_default_action(collection, method, action)
(collection[method] ||= []).unshift(action)
end
end
class SingletonResource < Resource #:nodoc:
def initialize(entity, options)
@plural = @singular = entity
@options = options
arrange_actions
add_default_actions
set_prefixes
end
alias_method :member_path, :path
alias_method :nesting_path_prefix, :path
end
# Creates named routes for implementing verb-oriented controllers. This is
# useful for implementing REST API's, where a single resource has different
# behavior based on the HTTP verb (method) used to access it.
@@ -145,7 +179,7 @@ module ActionController
#
# or
#
# <% form_for :message, @message, message_path(@message), :html => {:method => :put} do |f| %>
# <% form_for :message, @message, :url => message_path(@message), :html => {:method => :put} do |f| %>
#
# The #resources method accepts various options, too, to customize the resulting
# routes:
@@ -162,7 +196,15 @@ module ActionController
# map.resources :articles do |article|
# article.resources :comments
# end
#
#
# The comment resources work the same, but must now include a value for :article_id.
#
# article_comments_url(@article)
# article_comment_url(@article, @comment)
#
# article_comments_url(:article_id => @article)
# article_comment_url(:article_id => @article, :id => @comment)
#
# * <tt>:name_prefix</tt> -- define a prefix for all generated routes, usually ending in an underscore.
# Use this if you have named routes that may clash.
#
@@ -171,7 +213,7 @@ module ActionController
#
# * <tt>:collection</tt> -- add named routes for other actions that operate on the collection.
# Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt>
# or <tt>:any</tt> if the method does not matter. These routes map to a URL like /messages;rss, with a route of rss_messages_url.
# or <tt>:any</tt> if the method does not matter. These routes map to a URL like /messages/rss, with a route of rss_messages_url.
# * <tt>:member</tt> -- same as :collection, but for actions that operate on a specific member.
# * <tt>:new</tt> -- same as :collection, but for actions that operate on the new resource action.
#
@@ -183,19 +225,19 @@ module ActionController
# # --> GET /thread/7/messages/1
#
# map.resources :messages, :collection => { :rss => :get }
# # --> GET /messages;rss (maps to the #rss action)
# # --> GET /messages/rss (maps to the #rss action)
# # also adds a named route called "rss_messages"
#
# map.resources :messages, :member => { :mark => :post }
# # --> POST /messages/1;mark (maps to the #mark action)
# # --> POST /messages/1/mark (maps to the #mark action)
# # also adds a named route called "mark_message"
#
# map.resources :messages, :new => { :preview => :post }
# # --> POST /messages/new;preview (maps to the #preview action)
# # --> POST /messages/new/preview (maps to the #preview action)
# # also adds a named route called "preview_new_message"
#
# map.resources :messages, :new => { :new => :any, :preview => :post }
# # --> POST /messages/new;preview (maps to the #preview action)
# # --> POST /messages/new/preview (maps to the #preview action)
# # also adds a named route called "preview_new_message"
# # --> /messages/new can be invoked via any request method
#
@@ -209,84 +251,238 @@ module ActionController
entities.each { |entity| map_resource entity, options.dup, &block }
end
# Creates named routes for implementing verb-oriented controllers for a singleton resource.
# A singleton resource is global to the current user visiting the application, such as a user's
# /account profile.
#
# See map.resources for general conventions. These are the main differences:
# - A singular name is given to map.resource. The default controller name is taken from the singular name.
# - There is no <tt>:collection</tt> option as there is only the singleton resource.
# - There is no <tt>:singular</tt> option as the singular name is passed to map.resource.
# - No default index route is created for the singleton resource controller.
# - When nesting singleton resources, only the singular name is used as the path prefix (example: 'account/messages/1')
#
# Example:
#
# map.resource :account
#
# class AccountController < ActionController::Base
# # POST account_url
# def create
# # create an account
# end
#
# # GET new_account_url
# def new
# # return an HTML form for describing the new account
# end
#
# # GET account_url
# def show
# # find and return the account
# end
#
# # GET edit_account_url
# def edit
# # return an HTML form for editing the account
# end
#
# # PUT account_url
# def update
# # find and update the account
# end
#
# # DELETE account_url
# def destroy
# # delete the account
# end
# end
#
# Along with the routes themselves, #resource generates named routes for use in
# controllers and views. <tt>map.resource :account</tt> produces the following named routes and helpers:
#
# Named Route Helpers
# account account_url, hash_for_account_url,
# account_path, hash_for_account_path
# edit_account edit_account_url, hash_for_edit_account_url,
# edit_account_path, hash_for_edit_account_path
def resource(*entities, &block)
options = entities.last.is_a?(Hash) ? entities.pop : { }
entities.each { |entity| map_singleton_resource entity, options.dup, &block }
end
private
def map_resource(entities, options = {}, &block)
resource = Resource.new(entities, options)
with_options :controller => resource.controller do |map|
map_collection_actions(map, resource)
map_default_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
if block_given?
with_options(:path_prefix => resource.nesting_path_prefix, &block)
with_options(:path_prefix => resource.nesting_path_prefix, :new_name_prefix => resource.nesting_name_prefix, &block)
end
end
end
def map_singleton_resource(entities, options = {}, &block)
resource = SingletonResource.new(entities, options)
with_options :controller => resource.controller do |map|
map_collection_actions(map, resource)
map_default_singleton_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
if block_given?
with_options(:path_prefix => resource.nesting_path_prefix, :new_name_prefix => resource.nesting_name_prefix, &block)
end
end
end
def map_collection_actions(map, resource)
resource.collection_methods.each do |method, actions|
route_options = requirements_for(method)
actions.each do |action|
map.named_route(
"#{resource.name_prefix}#{action}_#{resource.plural}",
"#{resource.path};#{action}",
route_options.merge(:action => action.to_s)
)
action_options = action_options_for(action, resource, method)
map.named_route(
"formatted_#{resource.name_prefix}#{action}_#{resource.plural}",
"#{resource.path}.:format;#{action}",
route_options.merge(:action => action.to_s)
)
unless resource.old_name_prefix.blank?
map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.old_name_prefix}#{action}_#{resource.plural}")
map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "formatted_#{resource.old_name_prefix}#{action}_#{resource.plural}")
end
if resource.deprecate_name_prefix?
map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{action}_#{resource.plural}")
map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "formatted_#{action}_#{resource.plural}")
end
map.named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options)
map.connect("#{resource.path};#{action}", action_options)
map.connect("#{resource.path}.:format;#{action}", action_options)
map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}.:format", action_options)
end
end
end
map.named_route("#{resource.name_prefix}#{resource.plural}", resource.path, :action => "index", :conditions => { :method => :get })
map.named_route("formatted_#{resource.name_prefix}#{resource.plural}", "#{resource.path}.:format", :action => "index", :conditions => { :method => :get })
def map_default_collection_actions(map, resource)
index_action_options = action_options_for("index", resource)
map.named_route("#{resource.name_prefix}#{resource.plural}", resource.path, index_action_options)
map.named_route("formatted_#{resource.name_prefix}#{resource.plural}", "#{resource.path}.:format", index_action_options)
map.connect(resource.path, :action => "create", :conditions => { :method => :post })
map.connect("#{resource.path}.:format", :action => "create", :conditions => { :method => :post })
if resource.deprecate_name_prefix?
map.deprecated_named_route("#{resource.name_prefix}#{resource.plural}", "#{resource.plural}")
map.deprecated_named_route("formatted_#{resource.name_prefix}#{resource.plural}", "formatted_#{resource.plural}")
end
create_action_options = action_options_for("create", resource)
map.connect(resource.path, create_action_options)
map.connect("#{resource.path}.:format", create_action_options)
end
def map_default_singleton_actions(map, resource)
create_action_options = action_options_for("create", resource)
map.connect(resource.path, create_action_options)
map.connect("#{resource.path}.:format", create_action_options)
end
def map_new_actions(map, resource)
resource.new_methods.each do |method, actions|
route_options = requirements_for(method)
actions.each do |action|
action_options = action_options_for(action, resource, method)
if action == :new
map.named_route("#{resource.name_prefix}new_#{resource.singular}", resource.new_path, route_options.merge(:action => "new"))
map.named_route("formatted_#{resource.name_prefix}new_#{resource.singular}", "#{resource.new_path}.:format", route_options.merge(:action => "new"))
unless resource.old_name_prefix.blank?
map.deprecated_named_route("new_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}new_#{resource.singular}")
map.deprecated_named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}new_#{resource.singular}")
end
if resource.deprecate_name_prefix?
map.deprecated_named_route("new_#{resource.name_prefix}#{resource.singular}", "new_#{resource.singular}")
map.deprecated_named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "formatted_new_#{resource.singular}")
end
map.named_route("new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options)
map.named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}.:format", action_options)
else
map.named_route("#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path};#{action}", route_options.merge(:action => action.to_s))
map.named_route("formatted_#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path}.:format;#{action}", route_options.merge(:action => action.to_s))
unless resource.old_name_prefix.blank?
map.deprecated_named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}#{action}_new_#{resource.singular}")
map.deprecated_named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}#{action}_new_#{resource.singular}")
end
if resource.deprecate_name_prefix?
map.deprecated_named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{action}_new_#{resource.singular}")
map.deprecated_named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{action}_new_#{resource.singular}")
end
map.named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options)
map.connect("#{resource.new_path};#{action}", action_options)
map.connect("#{resource.new_path}.:format;#{action}", action_options)
map.named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}.:format", action_options)
end
end
end
end
def map_member_actions(map, resource)
resource.member_methods.each do |method, actions|
route_options = requirements_for(method)
actions.each do |action|
map.named_route("#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path};#{action}", route_options.merge(:action => action.to_s))
map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path}.:format;#{action}", route_options.merge(:action => action.to_s))
action_options = action_options_for(action, resource, method)
unless resource.old_name_prefix.blank?
map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}#{action}_#{resource.singular}")
map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}#{action}_#{resource.singular}")
end
if resource.deprecate_name_prefix?
map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{action}_#{resource.singular}")
map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "formatted_#{action}_#{resource.singular}")
end
map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}", action_options)
map.connect("#{resource.member_path};#{action}", action_options)
map.connect("#{resource.member_path}.:format;#{action}", action_options)
map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}.:format", action_options)
end
end
map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, :action => "show", :conditions => { :method => :get })
map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", :action => "show", :conditions => { :method => :get })
show_action_options = action_options_for("show", resource)
map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options)
map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", show_action_options)
map.connect(resource.member_path, :action => "update", :conditions => { :method => :put })
map.connect("#{resource.member_path}.:format", :action => "update", :conditions => { :method => :put })
if resource.deprecate_name_prefix?
map.deprecated_named_route("#{resource.name_prefix}#{resource.singular}", "#{resource.singular}")
map.deprecated_named_route("formatted_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.singular}")
end
map.connect(resource.member_path, :action => "destroy", :conditions => { :method => :delete })
map.connect("#{resource.member_path}.:format", :action => "destroy", :conditions => { :method => :delete })
update_action_options = action_options_for("update", resource)
map.connect(resource.member_path, update_action_options)
map.connect("#{resource.member_path}.:format", update_action_options)
destroy_action_options = action_options_for("destroy", resource)
map.connect(resource.member_path, destroy_action_options)
map.connect("#{resource.member_path}.:format", destroy_action_options)
end
def requirements_for(method)
method == :any ? {} : { :conditions => { :method => method } }
def conditions_for(method)
{ :conditions => method == :any ? {} : { :method => method } }
end
def action_options_for(action, resource, method = nil)
default_options = { :action => action.to_s }
require_id = resource.kind_of?(SingletonResource) ? {} : { :requirements => { :id => Regexp.new("[^#{Routing::SEPARATORS.join}]+") } }
case default_options[:action]
when "index", "new" : default_options.merge(conditions_for(method || :get))
when "create" : default_options.merge(conditions_for(method || :post))
when "show", "edit" : default_options.merge(conditions_for(method || :get)).merge(require_id)
when "update" : default_options.merge(conditions_for(method || :put)).merge(require_id)
when "destroy" : default_options.merge(conditions_for(method || :delete)).merge(require_id)
else default_options.merge(conditions_for(method))
end
end
end
end

View File

@@ -27,7 +27,7 @@ module ActionController
def redirect(to_url, permanently = false)
@headers["Status"] = "302 Found" unless @headers["Status"] == "301 Moved Permanently"
@headers["location"] = to_url
@headers["Location"] = to_url
@body = "<html><body>You are being <a href=\"#{to_url}\">redirected</a>.</body></html>"
end

View File

@@ -24,7 +24,7 @@ class NilClass
end
end
class Regexp
class Regexp #:nodoc:
def number_of_captures
Regexp.new("|#{source}").match('').captures.length
end
@@ -126,7 +126,8 @@ module ActionController
# == Named routes
#
# Routes can be named with the syntax <tt>map.name_of_route options</tt>,
# allowing for easy reference within your source as +name_of_route_url+.
# allowing for easy reference within your source as +name_of_route_url+
# for the full URL and +name_of_route_path+ for the URI path.
#
# Example:
# # In routes.rb
@@ -137,29 +138,39 @@ module ActionController
#
# Arguments can be passed as well.
#
# redirect_to show_item_url(:id => 25)
# redirect_to show_item_path(:id => 25)
#
# When using +with_options+, the name goes after the item passed to the block.
# Use <tt>map.root</tt> as a shorthand to name a route for the root path ""
#
# ActionController::Routing::Routes.draw do |map|
# map.with_options :controller => 'blog' do |blog|
# blog.show '', :action => 'list'
# blog.delete 'delete/:id', :action => 'delete',
# blog.edit 'edit/:id', :action => 'edit'
# end
# map.connect ':controller/:action/:view
# end
# # In routes.rb
# map.root :controller => 'blogs'
#
# You would then use the named routes in your views:
# # would recognize http://www.example.com/ as
# params = { :controller => 'blogs', :action => 'index' }
#
# link_to @article.title, show_url(:id => @article.id)
# # and provide these named routes
# root_url # => 'http://www.example.com/'
# root_path # => ''
#
# == Pretty URL's
# Note: when using +with_options+, the route is simply named after the
# method you call on the block parameter rather than map.
#
# # In routes.rb
# map.with_options :controller => 'blog' do |blog|
# blog.show '', :action => 'list'
# blog.delete 'delete/:id', :action => 'delete',
# blog.edit 'edit/:id', :action => 'edit'
# end
#
# # provides named routes for show, delete, and edit
# link_to @article.title, show_path(:id => @article.id)
#
# == Pretty URLs
#
# Routes can generate pretty URLs. For example:
#
# map.connect 'articles/:year/:month/:day',
# :controller => 'articles',
# :controller => 'articles',
# :action => 'find_by_date',
# :year => /\d{4}/,
# :month => /\d{1,2}/,
@@ -305,7 +316,7 @@ module ActionController
end
end
class Route
class Route #:nodoc:
attr_accessor :segments, :requirements, :conditions
def initialize
@@ -333,10 +344,10 @@ module ActionController
# the query string. (Never use keys from the recalled request when building the
# query string.)
method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(hash, expire_on))\nend"
method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend"
instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(hash, expire_on)]\nend"
method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend"
instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
raw_method
end
@@ -440,26 +451,17 @@ module ActionController
# is given (as an array), only the keys indicated will be used to build
# the query string. The query string will correctly build array parameter
# values.
def build_query_string(hash, only_keys=nil)
def build_query_string(hash, only_keys = nil)
elements = []
only_keys ||= hash.keys
only_keys.each do |key|
value = hash[key] or next
key = CGI.escape key.to_s
if value.class == Array
key << '[]'
else
value = [ value ]
end
value.each { |val| elements << "#{key}=#{CGI.escape(val.to_param.to_s)}" }
end
query_string = "?#{elements.join("&")}" unless elements.empty?
query_string || ""
(only_keys || hash.keys).each do |key|
if value = hash[key]
elements << value.to_query(key)
end
end
elements.empty? ? '' : "?#{elements.sort * '&'}"
end
# Write the real recognition implementation and then resend the message.
def recognize(path, environment={})
write_recognition
@@ -536,7 +538,7 @@ module ActionController
end
class Segment
class Segment #:nodoc:
attr_accessor :is_optional
alias_method :optional?, :is_optional
@@ -591,7 +593,7 @@ module ActionController
end
end
class StaticSegment < Segment
class StaticSegment < Segment #:nodoc:
attr_accessor :value, :raw
alias_method :raw?, :raw
@@ -625,7 +627,7 @@ module ActionController
end
end
class DividerSegment < StaticSegment
class DividerSegment < StaticSegment #:nodoc:
def initialize(value = nil)
super(value)
self.raw = true
@@ -637,7 +639,7 @@ module ActionController
end
end
class DynamicSegment < Segment
class DynamicSegment < Segment #:nodoc:
attr_accessor :key, :default, :regexp
def initialize(key = nil, options = {})
@@ -657,7 +659,7 @@ module ActionController
end
def extract_value
"#{local_name} = hash[:#{key}] #{"|| #{default.inspect}" if default}"
"#{local_name} = hash[:#{key}] && hash[:#{key}].to_param #{"|| #{default.inspect}" if default}"
end
def value_check
if default # Then we know it won't be nil
@@ -725,7 +727,7 @@ module ActionController
end
class ControllerSegment < DynamicSegment
class ControllerSegment < DynamicSegment #:nodoc:
def regexp_chunk
possible_names = Routing.possible_controllers.collect { |name| Regexp.escape name }
"(?i-:(#{(regexp || Regexp.union(*possible_names)).source}))"
@@ -752,7 +754,7 @@ module ActionController
end
end
class PathSegment < DynamicSegment
class PathSegment < DynamicSegment #:nodoc:
EscapedSlash = CGI.escape("/")
def interpolation_chunk
"\#{CGI.escape(#{local_name}.to_s).gsub(#{EscapedSlash.inspect}, '/')}"
@@ -782,7 +784,7 @@ module ActionController
end
end
class RouteBuilder
class RouteBuilder #:nodoc:
attr_accessor :separators, :optional_separators
def initialize
@@ -950,17 +952,21 @@ module ActionController
route.significant_keys << :action
end
if !route.significant_keys.include?(:controller)
raise ArgumentError, "Illegal route: the :controller must be specified!"
end
route
end
end
class RouteSet
class RouteSet #:nodoc:
# Mapper instances are used to build routes. The object passed to the draw
# block in config/routes.rb is a Mapper instance.
#
# Mapper instances have relatively few instance methods, in order to avoid
# clashes with named routes.
class Mapper
class Mapper #:nodoc:
def initialize(set)
@set = set
end
@@ -974,6 +980,18 @@ module ActionController
def named_route(name, path, options = {})
@set.add_named_route(name, path, options)
end
def deprecated_named_route(name, deprecated_name, options = {})
@set.add_deprecated_named_route(name, deprecated_name)
end
# Added deprecation notice for anyone who already added a named route called "root".
# It'll be used as a shortcut for map.connect '' in Rails 2.0.
def root(*args, &proc)
super unless args.length >= 1 && proc.nil?
@set.add_named_route("root", *args)
end
deprecate :root => "(as the the label for a named route) will become a shortcut for map.connect '', so find another name"
def method_missing(route_name, *args, &proc)
super unless args.length >= 1 && proc.nil?
@@ -984,7 +1002,7 @@ module ActionController
# A NamedRouteCollection instance is a collection of named routes, and also
# maintains an anonymous module that can be used to install helpers for the
# named routes.
class NamedRouteCollection
class NamedRouteCollection #:nodoc:
include Enumerable
attr_reader :routes, :helpers
@@ -996,7 +1014,11 @@ module ActionController
def clear!
@routes = {}
@helpers = []
@module = Module.new
@module ||= Module.new
@module.instance_methods.each do |selector|
@module.send :remove_method, selector
end
end
def add(name, route)
@@ -1028,6 +1050,38 @@ module ActionController
def install(destinations = [ActionController::Base, ActionView::Base])
Array(destinations).each { |dest| dest.send :include, @module }
end
def define_deprecated_named_route_methods(name, deprecated_name)
[:url, :path].each do |kind|
@module.send :module_eval, <<-end_eval # We use module_eval to avoid leaks
def #{url_helper_name(deprecated_name, kind)}(*args)
ActiveSupport::Deprecation.warn(
'The named route "#{url_helper_name(deprecated_name, kind)}" uses a format that has been deprecated. ' +
'You should use "#{url_helper_name(name, kind)}" instead.', caller
)
send :#{url_helper_name(name, kind)}, *args
end
def #{hash_access_name(deprecated_name, kind)}(*args)
ActiveSupport::Deprecation.warn(
'The named route "#{hash_access_name(deprecated_name, kind)}" uses a format that has been deprecated. ' +
'You should use "#{hash_access_name(name, kind)}" instead.', caller
)
send :#{hash_access_name(name, kind)}, *args
end
end_eval
end
end
private
def url_helper_name(name, kind = :url)
@@ -1150,6 +1204,10 @@ module ActionController
def add_named_route(name, path, options = {})
named_routes[name] = add_route(path, options)
end
def add_deprecated_named_route(name, deprecated_name)
named_routes.define_deprecated_named_route_methods(name, deprecated_name)
end
def options_as_params(options)
# If an explicit :controller was given, always make :action explicit
@@ -1163,10 +1221,9 @@ module ActionController
#
# great fun, eh?
options_as_params = options[:controller] ? { :action => "index" } : {}
options.each do |k, value|
options_as_params[k] = value.to_param
end
options_as_params = options.clone
options_as_params[:action] ||= 'index' if options[:controller]
options_as_params[:action] = options_as_params[:action].to_s if options_as_params[:action]
options_as_params
end
@@ -1197,6 +1254,9 @@ module ActionController
options = options_as_params(options)
expire_on = build_expiry(options, recall)
if options[:controller]
options[:controller] = options[:controller].to_s
end
# if the controller has changed, make sure it changes relative to the
# current controller module, if any. In other words, if we're currently
# on admin/get, and the new controller is 'set', the new controller
@@ -1211,11 +1271,14 @@ module ActionController
# drop the leading '/' on the controller name
options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/
merged = recall.merge(options)
if named_route
path = named_route.generate(options, merged, expire_on)
raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect}, expected: #{named_route.requirements.inspect}, diff: #{named_route.requirements.diff(options).inspect}" if path.nil?
return path
if path.nil?
raise_named_route_error(options, named_route, named_route_name)
else
return path
end
else
merged[:action] ||= 'index'
options[:action] ||= 'index'
@@ -1235,6 +1298,18 @@ module ActionController
raise RoutingError, "No route matches #{options.inspect}"
end
# try to give a helpful error message when named route generation fails
def raise_named_route_error(options, named_route, named_route_name)
diff = named_route.requirements.diff(options)
unless diff.empty?
raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect}, expected: #{named_route.requirements.inspect}, diff: #{named_route.requirements.diff(options).inspect}"
else
required_segments = named_route.segments.select {|seg| (!seg.optional?) && (!seg.is_a?(DividerSegment)) }
required_keys_or_values = required_segments.map { |seg| seg.key rescue seg.value } # we want either the key or the value from the segment
raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: #{required_keys_or_values.inspect} - are they all satisifed?"
end
end
def recognize(request)
params = recognize_path(request.path, extract_request_environment(request))

View File

@@ -5,6 +5,8 @@ require 'base64'
class CGI
class Session
attr_reader :data
# Return this session's underlying Session instance. Useful for the DB-backed session stores.
def model
@dbman.model if @dbman

View File

@@ -26,6 +26,10 @@ class CGI #:nodoc:all
def delete
@@session_data.delete(@session_id)
end
def data
@@session_data[@session_id]
end
end
end
end

View File

@@ -93,6 +93,10 @@ begin
end
@session_data = {}
end
def data
@session_data
end
end
end
end

View File

@@ -120,16 +120,16 @@ module ActionController #:nodoc:
end
def process_cleanup_with_session_management_support
process_cleanup_without_session_management_support
clear_persistent_model_associations
process_cleanup_without_session_management_support
end
# Clear cached associations in session data so they don't overflow
# the database field. Only applies to ActiveRecordStore since there
# is not a standard way to iterate over session data.
def clear_persistent_model_associations #:doc:
if defined?(@_session) && @_session.instance_variables.include?('@data')
session_data = @_session.instance_variable_get('@data')
if defined?(@_session) && @_session.respond_to?(:data)
session_data = @_session.data
if session_data && session_data.respond_to?(:each_value)
session_data.each_value do |obj|

View File

@@ -1,11 +1,12 @@
module ActionController
module StatusCodes
module StatusCodes #:nodoc:
# Defines the standard HTTP status codes, by integer, with their
# corresponding default message texts.
# Source: http://www.iana.org/assignments/http-status-codes
STATUS_CODES = {
100 => "Continue",
101 => "Switching Protocols",
102 => "Processing",
200 => "OK",
201 => "Created",
@@ -14,6 +15,8 @@ module ActionController
204 => "No Content",
205 => "Reset Content",
206 => "Partial Content",
207 => "Multi-Status",
226 => "IM Used",
300 => "Multiple Choices",
301 => "Moved Permanently",
@@ -41,13 +44,19 @@ module ActionController
415 => "Unsupported Media Type",
416 => "Requested Range Not Satisfiable",
417 => "Expectation Failed",
422 => "Unprocessable Entity",
423 => "Locked",
424 => "Failed Dependency",
426 => "Upgrade Required",
500 => "Internal Server Error",
501 => "Not Implemented",
502 => "Bad Gateway",
503 => "Service Unavailable",
504 => "Gateway Timeout",
505 => "HTTP Version Not Supported"
505 => "HTTP Version Not Supported",
507 => "Insufficient Storage",
510 => "Not Extended"
}
# Provides a symbol-to-fixnum lookup for converting a symbol (like

View File

@@ -24,6 +24,7 @@ module ActionController #:nodoc:
attr_accessor :cookies, :session_options
attr_accessor :query_parameters, :request_parameters, :path, :session, :env
attr_accessor :host
attr_reader :request_uri_overridden
def initialize(query_parameters = nil, request_parameters = nil, session = nil)
@query_parameters = query_parameters || {}
@@ -38,7 +39,7 @@ module ActionController #:nodoc:
def reset_session
@session = TestSession.new
end
end
def raw_post
if raw_post = env['RAW_POST_DATA']
@@ -67,12 +68,14 @@ module ActionController #:nodoc:
# Used to check AbstractRequest's request_uri functionality.
# Disables the use of @path and @request_uri so superclass can handle those.
def set_REQUEST_URI(value)
@request_uri_overridden = true
@env["REQUEST_URI"] = value
@request_uri = nil
@path = nil
end
def request_uri=(uri)
@env["REQUEST_URI"] = uri
@request_uri = uri
@path = uri.split("?").first
end
@@ -179,7 +182,7 @@ module ActionController #:nodoc:
# returns the redirection location or nil
def redirect_url
redirect? ? headers['location'] : nil
headers['Location']
end
# does the redirect location match this regexp pattern?
@@ -275,27 +278,40 @@ module ActionController #:nodoc:
end
class TestSession #:nodoc:
def initialize(attributes = {})
attr_accessor :session_id
def initialize(attributes = nil)
@session_id = ''
@attributes = attributes
@saved_attributes = nil
end
def data
@attributes ||= @saved_attributes || {}
end
def [](key)
@attributes[key]
data[key]
end
def []=(key, value)
@attributes[key] = value
data[key] = value
end
def session_id
""
def update
@saved_attributes = @attributes
end
def update() end
def close() end
def delete() @attributes = {} end
def delete
@attributes = nil
end
def close
update
delete
end
end
# Essentially generates a modified Tempfile object similar to the object
# you'd get from the standard library CGI module in a multipart
# request. This means you can use an ActionController::TestUploadedFile
@@ -413,12 +429,12 @@ module ActionController #:nodoc:
end
def build_request_uri(action, parameters)
unless @request.env['REQUEST_URI']
unless @request.request_uri_overridden
options = @controller.send(:rewrite_options, parameters)
options.update(:only_path => true, :action => action)
url = ActionController::UrlRewriter.new(@request, parameters)
@request.set_REQUEST_URI(url.rewrite(options))
@request.request_uri = url.rewrite(options)
end
end

View File

@@ -52,8 +52,9 @@ module ActionController
# Delete the unused options to prevent their appearance in the query string
[:protocol, :host, :port].each { |k| options.delete k }
end
anchor = "##{options.delete(:anchor)}" if options.key?(:anchor)
url << Routing::Routes.generate(options, {})
return url
return "#{url}#{anchor}"
end
end
@@ -76,6 +77,7 @@ module ActionController
alias_method :to_s, :to_str
private
# Given a path and options, returns a rewritten URL string
def rewrite_url(path, options)
rewritten_url = ""
unless options[:only_path]
@@ -91,6 +93,7 @@ module ActionController
rewritten_url
end
# Given a Hash of options, generates a route
def rewrite_path(options)
options = options.symbolize_keys
options.update(options[:params].symbolize_keys) if options[:params]

View File

@@ -92,7 +92,6 @@ module HTML #:nodoc:
# returns non +nil+. Returns the result of the #find call that succeeded.
def find(conditions)
conditions = validate_conditions(conditions)
@children.each do |child|
node = child.find(conditions)
return node if node
@@ -152,7 +151,7 @@ module HTML #:nodoc:
if scanner.skip(/!\[CDATA\[/)
scanner.scan_until(/\]\]>/)
return CDATA.new(parent, line, pos, scanner.pre_match)
return CDATA.new(parent, line, pos, scanner.pre_match.gsub(/<!\[CDATA\[/, ''))
end
closing = ( scanner.scan(/\//) ? :close : nil )
@@ -316,7 +315,7 @@ module HTML #:nodoc:
s = "<#{@name}"
@attributes.each do |k,v|
s << " #{k}"
s << "='#{v.gsub(/'/,"\\\\'")}'" if String === v
s << "=\"#{v}\"" if String === v
end
s << " /" if @closing == :self
s << ">"
@@ -410,7 +409,6 @@ module HTML #:nodoc:
# :child => /hello world/ }
def match(conditions)
conditions = validate_conditions(conditions)
# check content of child nodes
if conditions[:content]
if children.empty?

View File

@@ -201,7 +201,8 @@ module HTML
# An invalid selector.
class InvalidSelectorError < StandardError ; end
class InvalidSelectorError < StandardError #:nodoc:
end
class << self

View File

@@ -95,6 +95,7 @@ module ActionController #:nodoc:
response.headers.update(options[:add_headers]) if options[:add_headers]
unless performed?
render(options[:render]) if options[:render]
options[:redirect_to] = self.send(options[:redirect_to]) if options[:redirect_to].is_a? Symbol
redirect_to(options[:redirect_to]) if options[:redirect_to]
end
return false

View File

@@ -1,8 +1,8 @@
module ActionPack #:nodoc:
module VERSION #:nodoc:
MAJOR = 1
MINOR = 12
TINY = 5
MINOR = 13
TINY = 6
STRING = [MAJOR, MINOR, TINY].join('.')
end

View File

@@ -148,7 +148,7 @@ module ActionView #:nodoc:
#
# This refreshes the sidebar, removes a person element and highlights the user list.
#
# See the ActionView::Helpers::PrototypeHelper::JavaScriptGenerator documentation for more details.
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
class Base
include ERB::Util
@@ -160,7 +160,7 @@ module ActionView #:nodoc:
attr_internal *ActionController::Base::DEPRECATED_INSTANCE_VARIABLES
# Specify trim mode for the ERB compiler. Defaults to '-'.
# See ERB documentation for suitable values.
# See ERb documentation for suitable values.
@@erb_trim_mode = '-'
cattr_accessor :erb_trim_mode
@@ -191,17 +191,17 @@ module ActionView #:nodoc:
end
include CompiledTemplates
# maps inline templates to their method names
# Maps inline templates to their method names
@@method_names = {}
# map method names to their compile time
# Map method names to their compile time
@@compile_time = {}
# map method names to the names passed in local assigns so far
# Map method names to the names passed in local assigns so far
@@template_args = {}
# count the number of inline templates
# Count the number of inline templates
@@inline_template_count = 0
# maps template paths without extension to their file extension returned by pick_template_extension.
# if for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions
# used by pick_template_extension determines whether ext1 or ext2 will be stored
# Maps template paths without extension to their file extension returned by pick_template_extension.
# If for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions
# used by pick_template_extension determines whether ext1 or ext2 will be stored.
@@cached_template_extension = {}
class ObjectWrapper < Struct.new(:value) #:nodoc:
@@ -305,7 +305,6 @@ module ActionView #:nodoc:
# Render the provided template with the given local assigns. If the template has not been rendered with the provided
# local assigns yet, or if the template has been updated on disk, then the template will be compiled to a method.
#
# Either, but not both, of template and file_path may be nil. If file_path is given, the template
# will only be read if it has to be compiled.
#
@@ -371,10 +370,12 @@ module ActionView #:nodoc:
end
private
# Builds a string holding the full path of the template including extension
def full_template_path(template_path, extension)
"#{@base_path}/#{template_path}.#{extension}"
end
# Asserts the existence of a template.
def template_exists?(template_path, extension)
file_path = full_template_path(template_path, extension)
@@method_names.has_key?(file_path) || FileTest.exists?(file_path)
@@ -389,6 +390,7 @@ module ActionView #:nodoc:
@@cache_template_extensions && @@cached_template_extension[template_path]
end
# Determines the template's file extension, such as rhtml, rxml, or rjs.
def find_template_extension_for(template_path)
if match = delegate_template_exists?(template_path)
match.first.to_sym
@@ -405,6 +407,7 @@ module ActionView #:nodoc:
File.read(template_path)
end
# Evaluate the local assigns and pushes them to the view.
def evaluate_assigns
unless @assigns_added
assign_variables_from_controller
@@ -416,6 +419,7 @@ module ActionView #:nodoc:
handler.new(self).render(template, local_assigns)
end
# Assigns instance variables from the controller to the view.
def assign_variables_from_controller
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
end
@@ -427,10 +431,10 @@ module ActionView #:nodoc:
((args = @@template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) })
end
# Check whether compilation is necessary.
# Compile if the inline template or file has not been compiled yet.
# Or if local_assigns has a new key, which isn't supported by the compiled code yet.
# Or if the file has changed on disk and checking file mods hasn't been disabled.
# Method to check whether template compilation is necessary.
# The template will be compiled if the inline template or file has not been compiled yet,
# if local_assigns has a new key, which isn't supported by the compiled code yet,
# or if the file has changed on disk and checking file mods hasn't been disabled.
def compile_template?(template, file_name, local_assigns)
method_key = file_name || template
render_symbol = @@method_names[method_key]
@@ -445,14 +449,15 @@ module ActionView #:nodoc:
end
end
# Create source code for given template
# Method to create the source code for a given template.
def create_template_source(extension, template, render_symbol, locals)
if template_requires_setup?(extension)
body = case extension.to_sym
when :rxml
"controller.response.content_type ||= 'application/xml'\n" +
"xml = Builder::XmlMarkup.new(:indent => 2)\n" +
template
"xml ||= Builder::XmlMarkup.new(:indent => 2)\n" +
template +
"\nxml.target!\n"
when :rjs
"controller.response.content_type ||= 'text/javascript'\n" +
"update_page do |page|\n#{template}\nend"
@@ -473,11 +478,11 @@ module ActionView #:nodoc:
"def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend"
end
def template_requires_setup?(extension)
def template_requires_setup?(extension) #:nodoc:
templates_requiring_setup.include? extension.to_s
end
def templates_requiring_setup
def templates_requiring_setup #:nodoc:
%w(rxml rjs)
end
@@ -501,6 +506,7 @@ module ActionView #:nodoc:
end
end
# Compile and evaluate the template's code
def compile_template(extension, template, file_name, local_assigns)
render_symbol = assign_method_name(extension, template, file_name)
render_source = create_template_source(extension, template, render_symbol, local_assigns.keys)

View File

@@ -3,14 +3,14 @@ module ActionView
# CompiledTemplates modules hold methods that have been compiled.
# Templates are compiled into these methods so that they do not need to be
# re-read and re-parsed each request.
# read and parsed for each request.
#
# Each template may be compiled into one or more methods. Each method accepts a given
# set of parameters which is used to implement local assigns passing.
#
# To use a compiled template module, create a new instance and include it into the class
# in which you want the template to be rendered.
class CompiledTemplates < Module #:nodoc:
class CompiledTemplates < Module
attr_reader :method_names
def initialize

View File

@@ -13,17 +13,18 @@ module ActionView
# is a great of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form.
# In that case, it's better to use the input method and the specialized form methods in link:classes/ActionView/Helpers/FormHelper.html
module ActiveRecordHelper
# Returns a default input tag for the type of object returned by the method. Example
# (title is a VARCHAR column and holds "Hello World"):
# Returns a default input tag for the type of object returned by the method. For example, let's say you have a model
# that has an attribute +title+ of type VARCHAR column, and this instance holds "Hello World":
# input("post", "title") =>
# <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
def input(record_name, method, options = {})
InstanceTag.new(record_name, method, self).to_tag(options)
end
# Returns an entire form with input tags and everything for a specified Active Record object. Example
# (post is a new record that has a title using VARCHAR and a body using TEXT):
# form("post") =>
# Returns an entire form with all needed input tags for a specified Active Record object. For example, let's say you
# have a table model <tt>Post</tt> with attributes named <tt>title</tt> of type <tt>VARCHAR</tt> and <tt>body</tt> of type <tt>TEXT</tt>:
# form("post")
# That line would yield a form like the following:
# <form action='/post/create' method='post'>
# <p>
# <label for="post_title">Title</label><br />
@@ -32,14 +33,13 @@ module ActionView
# <p>
# <label for="post_body">Body</label><br />
# <textarea cols="40" id="post_body" name="post[body]" rows="20">
# Back to the hill and over it again!
# </textarea>
# </p>
# <input type='submit' value='Create' />
# </form>
#
# It's possible to specialize the form builder by using a different action name and by supplying another
# block renderer. Example (entry is a new record that has a message attribute using VARCHAR):
# block renderer. For example, let's say you have a model <tt>Entry</tt> with an attribute <tt>message</tt> of type <tt>VARCHAR</tt>:
#
# form("entry", :action => "sign", :input_block =>
# Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}<br />" }) =>
@@ -74,27 +74,29 @@ module ActionView
content_tag('form', contents, :action => action, :method => 'post', :enctype => options[:multipart] ? 'multipart/form-data': nil)
end
# Returns a string containing the error message attached to the +method+ on the +object+, if one exists.
# This error message is wrapped in a DIV tag, which can be specialized to include both a +prepend_text+ and +append_text+
# to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message
# "can't be empty" on the title attribute):
# Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
# This error message is wrapped in a <tt>DIV</tt> tag, which can be extended to include a +prepend_text+ and/or +append_text+
# (to properly explain the error), and a +css_class+ to style it accordingly. As an example, let's say you have a model
# +post+ that has an error message on the +title+ attribute:
#
# <%= error_message_on "post", "title" %> =>
# <div class="formError">can't be empty</div>
#
# <%= error_message_on "post", "title", "Title simply ", " (or it won't work)", "inputError" %> =>
# <div class="inputError">Title simply can't be empty (or it won't work)</div>
# <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %> =>
# <div class="inputError">Title simply can't be empty (or it won't work).</div>
def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError")
if errors = instance_variable_get("@#{object}").errors.on(method)
if (obj = instance_variable_get("@#{object}")) && (errors = obj.errors.on(method))
content_tag("div", "#{prepend_text}#{errors.is_a?(Array) ? errors.first : errors}#{append_text}", :class => css_class)
else
''
end
end
# Returns a string with a div containing all of the error messages for the objects located as instance variables by the names
# Returns a string with a <tt>DIV</tt> containing all of the error messages for the objects located as instance variables by the names
# given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are
# provided.
#
# This div can be tailored by the following options:
# This <tt>DIV</tt> can be tailored by the following options:
#
# * <tt>header_tag</tt> - Used for the header of the error div (default: h2)
# * <tt>id</tt> - The id of the error div (default: errorExplanation)
@@ -103,12 +105,12 @@ module ActionView
# any text that you prefer. If <tt>object_name</tt> is not set, the name of
# the first object will be used.
#
# Specifying one object:
# To specify the display for one object, you simply provide its name as a parameter. For example, for the +User+ model:
#
# error_messages_for 'user'
#
# Specifying more than one object (and using the name 'user' in the
# header as the <tt>object_name</tt> instead of 'user_common'):
# To specify more than one object, you simply list them; optionally, you can add an extra +object_name+ parameter, which
# be the name in the header.
#
# error_messages_for 'user_common', 'user', :object_name => 'user'
#
@@ -167,6 +169,8 @@ module ActionView
to_date_select_tag(options)
when :datetime, :timestamp
to_datetime_select_tag(options)
when :time
to_time_select_tag(options)
when :boolean
to_boolean_select_tag(options)
end
@@ -208,6 +212,15 @@ module ActionView
end
end
alias_method :to_time_select_tag_without_error_wrapping, :to_time_select_tag
def to_time_select_tag(options = {})
if object.respond_to?("errors") && object.errors.respond_to?("on")
error_wrapping(to_time_select_tag_without_error_wrapping(options), object.errors.on(@method_name))
else
to_time_select_tag_without_error_wrapping(options)
end
end
def error_wrapping(html_tag, has_error)
has_error ? Base.field_error_proc.call(html_tag, self) : html_tag
end

View File

@@ -3,20 +3,36 @@ require File.dirname(__FILE__) + '/url_helper'
require File.dirname(__FILE__) + '/tag_helper'
module ActionView
module Helpers
# Provides methods for linking a HTML page together with other assets, such as javascripts, stylesheets, and feeds.
module Helpers #:nodoc:
# Provides methods for linking an HTML page together with other assets such
# as images, javascripts, stylesheets, and feeds. You can direct Rails to
# link to assets from a dedicated assets server by setting ActionController::Base.asset_host
# in your environment.rb. These methods do not verify the assets exist before
# linking to them.
#
# ActionController::Base.asset_host = "http://assets.example.com"
# image_tag("rails.png")
# => <img src="http://assets.example.com/images/rails.png" alt="Rails" />
# stylesheet_include_tag("application")
# => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="Stylesheet" type="text/css" />
module AssetTagHelper
# Returns a link tag that browsers and news readers can use to auto-detect a RSS or ATOM feed for this page. The +type+ can
# either be <tt>:rss</tt> (default) or <tt>:atom</tt> and the +options+ follow the url_for style of declaring a link target.
# Returns a link tag that browsers and news readers can use to auto-detect
# an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or
# <tt>:atom</tt>. Control the link options in url_for format using the
# +url_options+. You can modify the LINK tag itself in +tag_options+.
#
# Examples:
# auto_discovery_link_tag # =>
# Tag Options:
# * <tt>:rel</tt> - Specify the relation of this link, defaults to "alternate"
# * <tt>:type</tt> - Override the auto-generated mime type
# * <tt>:title</tt> - Specify the title of the link, defaults to the +type+
#
# auto_discovery_link_tag # =>
# <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/action" />
# auto_discovery_link_tag(:atom) # =>
# auto_discovery_link_tag(:atom) # =>
# <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/action" />
# auto_discovery_link_tag(:rss, {:action => "feed"}) # =>
# auto_discovery_link_tag(:rss, {:action => "feed"}) # =>
# <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/feed" />
# auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
# auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
# <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.curenthost.com/controller/feed" />
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
tag(
@@ -28,9 +44,14 @@ module ActionView
)
end
# Returns path to a javascript asset. Example:
# Computes the path to a javascript asset in the public javascripts directory.
# If the +source+ filename has no extension, .js will be appended.
# Full paths from the document root will be passed through.
# Used internally by javascript_include_tag to build the script path.
#
# javascript_path "xmlhr" # => /javascripts/xmlhr.js
# javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
# javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
def javascript_path(source)
compute_public_path(source, 'javascripts', 'js')
end
@@ -38,7 +59,15 @@ module ActionView
JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'] unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
@@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup
# Returns a script include tag per source given as argument. Examples:
# Returns an html script tag for each of the +sources+ provided. You
# can pass in the filename (.js extension is optional) of javascript files
# that exist in your public/javascripts directory for inclusion into the
# current page or you can pass the full path relative to your document
# root. To include the Prototype and Scriptaculous javascript libraries in
# your application, pass <tt>:defaults</tt> as the source. When using
# :defaults, if an <tt>application.js</tt> file exists in your public
# javascripts directory, it will be included as well. You can modify the
# html attributes of the script tag by passing a hash as the last argument.
#
# javascript_include_tag "xmlhr" # =>
# <script type="text/javascript" src="/javascripts/xmlhr.js"></script>
@@ -52,11 +81,6 @@ module ActionView
# <script type="text/javascript" src="/javascripts/effects.js"></script>
# ...
# <script type="text/javascript" src="/javascripts/application.js"></script> *see below
#
# If there's an <tt>application.js</tt> file in your <tt>public/javascripts</tt> directory,
# <tt>javascript_include_tag :defaults</tt> will automatically include it. This file
# facilitates the inclusion of small snippets of JavaScript code, along the lines of
# <tt>controllers/application.rb</tt> and <tt>helpers/application_helper.rb</tt>.
def javascript_include_tag(*sources)
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
@@ -69,18 +93,16 @@ module ActionView
sources << "application" if defined?(RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
end
sources.collect { |source|
sources.collect do |source|
source = javascript_path(source)
content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
}.join("\n")
end.join("\n")
end
# Register one or more additional JavaScript files to be included when
#
# javascript_include_tag :defaults
#
# is called. This method is intended to be called only from plugin initialization
# to register extra .js files the plugin installed in <tt>public/javascripts</tt>.
# <tt>javascript_include_tag :defaults</tt> is called. This method is
# only intended to be called from plugin initialization to register additional
# .js files that the plugin installed in <tt>public/javascripts</tt>.
def self.register_javascript_include_default(*sources)
@@javascript_default_sources.concat(sources)
end
@@ -89,14 +111,21 @@ module ActionView
@@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup
end
# Returns path to a stylesheet asset. Example:
# Computes the path to a stylesheet asset in the public stylesheets directory.
# If the +source+ filename has no extension, .css will be appended.
# Full paths from the document root will be passed through.
# Used internally by stylesheet_link_tag to build the stylesheet path.
#
# stylesheet_path "style" # => /stylesheets/style.css
# stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
# stylesheet_path "/dir/style.css" # => /dir/style.css
def stylesheet_path(source)
compute_public_path(source, 'stylesheets', 'css')
end
# Returns a css link tag per source given as argument. Examples:
# Returns a stylesheet link tag for the sources specified as arguments. If
# you don't specify an extension, .css will be appended automatically.
# You can modify the link attributes by passing a hash as the last argument.
#
# stylesheet_link_tag "style" # =>
# <link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />
@@ -109,18 +138,20 @@ module ActionView
# <link href="/css/stylish.css" media="screen" rel="Stylesheet" type="text/css" />
def stylesheet_link_tag(*sources)
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
sources.collect { |source|
sources.collect do |source|
source = stylesheet_path(source)
tag("link", { "rel" => "Stylesheet", "type" => "text/css", "media" => "screen", "href" => source }.merge(options))
}.join("\n")
end.join("\n")
end
# Returns path to an image asset. Example:
# Computes the path to an image asset in the public images directory.
# Full paths from the document root will be passed through.
# Used internally by image_tag to build the image path. Passing
# a filename without an extension is deprecated.
#
# The +src+ can be supplied as a...
# * full path, like "/my_images/image.gif"
# * file name, like "rss.gif", that gets expanded to "/images/rss.gif"
# * file name without extension, like "logo", that gets expanded to "/images/logo.png"
# image_path("edit.png") # => /images/edit.png
# image_path("icons/edit.png") # => /images/icons/edit.png
# image_path("/icons/edit.png") # => /icons/edit.png
def image_path(source)
unless (source.split("/").last || source).include?(".") || source.blank?
ActiveSupport::Deprecation.warn(
@@ -133,15 +164,24 @@ module ActionView
compute_public_path(source, 'images', 'png')
end
# Returns an image tag converting the +options+ into html options on the tag, but with these special cases:
# Returns an html image tag for the +source+. The +source+ can be a full
# path or a file that exists in your public images directory. Note that
# specifying a filename without the extension is now deprecated in Rails.
# You can add html attributes using the +options+. The +options+ supports
# two additional keys for convienence and conformance:
#
# * <tt>:alt</tt> - If no alt text is given, the file name part of the +src+ is used (capitalized and without the extension)
# * <tt>:size</tt> - Supplied as "XxY", so "30x45" becomes width="30" and height="45"
# * <tt>:alt</tt> - If no alt text is given, the file name part of the
# +source+ is used (capitalized and without the extension)
# * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes
# width="30" and height="45". <tt>:size</tt> will be ignored if the
# value is not in the correct format.
#
# The +src+ can be supplied as a...
# * full path, like "/my_images/image.gif"
# * file name, like "rss.gif", that gets expanded to "/images/rss.gif"
# * file name without extension, like "logo", that gets expanded to "/images/logo.png"
# image_tag("icon.png") # =>
# <img src="/images/icon.png" alt="Icon" />
# image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # =>
# <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" />
# image_tag("/icons/icon.gif", :size => "16x16") # =>
# <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
def image_tag(source, options = {})
options.symbolize_keys!
@@ -149,8 +189,8 @@ module ActionView
options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize
if options[:size]
options[:width], options[:height] = options[:size].split("x")
options.delete :size
options[:width], options[:height] = options[:size].split("x") if options[:size] =~ %r{^\d+x\d+$}
options.delete(:size)
end
tag("img", options)
@@ -163,7 +203,7 @@ module ActionView
unless source =~ %r{^[-a-z]+://}
source = "/#{dir}/#{source}" unless source[0] == ?/
asset_id = rails_asset_id(source)
source << '?' + asset_id if defined?(RAILS_ROOT) and not asset_id.blank?
source << '?' + asset_id if defined?(RAILS_ROOT) && !asset_id.blank?
source = "#{ActionController::Base.asset_host}#{@controller.request.relative_url_root}#{source}"
end
source

View File

@@ -62,7 +62,7 @@ module ActionView
when 40..59 then 'less than a minute'
else '1 minute'
end
when 2..44 then "#{distance_in_minutes} minutes"
when 45..89 then 'about 1 hour'
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
@@ -74,12 +74,12 @@ module ActionView
else "over #{(distance_in_minutes / 525960).round} years"
end
end
# Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
def time_ago_in_words(from_time, include_seconds = false)
distance_of_time_in_words(from_time, Time.now, include_seconds)
end
alias_method :distance_of_time_in_words_to_now, :time_ago_in_words
# Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
@@ -108,6 +108,19 @@ module ActionView
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options)
end
# Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified
# time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+).
# You can include the seconds with <tt>:include_seconds</tt>.
# Examples:
#
# time_select("post", "sunrise")
# time_select("post", "start_time", :include_seconds => true)
#
# The selects are prepared for multi-parameter assignment to an Active Record object.
def time_select(object_name, method, options = {})
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options)
end
# Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based
# attribute (identified by +method+) on an object assigned to the template (identified by +object+). Examples:
#
@@ -119,36 +132,55 @@ module ActionView
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options)
end
# Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
def select_date(date = Date.today, options = {})
select_year(date, options) + select_month(date, options) + select_day(date, options)
end
# Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
def select_datetime(datetime = Time.now, options = {})
select_year(datetime, options) + select_month(datetime, options) + select_day(datetime, options) +
select_hour(datetime, options) + select_minute(datetime, options)
# It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
# symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
# will be appened onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt> and <tt>:time_separator</tt>
# keys to the +options+ to control visual display of the elements.
def select_datetime(datetime = Time.now, options = {})
separator = options[:datetime_separator] || ''
select_date(datetime, options) + separator + select_time(datetime, options)
end
# Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
# It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
# symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
# will be appened onto the <tt>:order</tt> passed in.
def select_date(date = Date.today, options = {})
options[:order] ||= []
[:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
select_date = ''
options[:order].each do |o|
select_date << self.send("select_#{o}", date, options)
end
select_date
end
# Returns a set of html select-tags (one for hour and minute)
# You can set <tt>:add_separator</tt> key to format the output.
def select_time(datetime = Time.now, options = {})
h = select_hour(datetime, options) + select_minute(datetime, options) + (options[:include_seconds] ? select_second(datetime, options) : '')
separator = options[:time_separator] || ''
select_hour(datetime, options) + separator + select_minute(datetime, options) + (options[:include_seconds] ? separator + select_second(datetime, options) : '')
end
# Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
# The <tt>second</tt> can also be substituted for a second number.
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
def select_second(datetime, options = {})
second_options = []
0.upto(59) do |second|
second_options << ((datetime && (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) == second) ?
%(<option value="#{leading_zero_on_single_digits(second)}" selected="selected">#{leading_zero_on_single_digits(second)}</option>\n) :
%(<option value="#{leading_zero_on_single_digits(second)}">#{leading_zero_on_single_digits(second)}</option>\n)
)
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : ''
if options[:use_hidden]
options[:include_seconds] ? hidden_html(options[:field_name] || 'second', val, options) : ''
else
second_options = []
0.upto(59) do |second|
second_options << ((val == second) ?
%(<option value="#{leading_zero_on_single_digits(second)}" selected="selected">#{leading_zero_on_single_digits(second)}</option>\n) :
%(<option value="#{leading_zero_on_single_digits(second)}">#{leading_zero_on_single_digits(second)}</option>\n)
)
end
select_html(options[:field_name] || 'second', second_options, options)
end
select_html(options[:field_name] || 'second', second_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
end
# Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
@@ -156,84 +188,100 @@ module ActionView
# The <tt>minute</tt> can also be substituted for a minute number.
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
def select_minute(datetime, options = {})
minute_options = []
0.step(59, options[:minute_step] || 1) do |minute|
minute_options << ((datetime && (datetime.kind_of?(Fixnum) ? datetime : datetime.min) == minute) ?
%(<option value="#{leading_zero_on_single_digits(minute)}" selected="selected">#{leading_zero_on_single_digits(minute)}</option>\n) :
%(<option value="#{leading_zero_on_single_digits(minute)}">#{leading_zero_on_single_digits(minute)}</option>\n)
)
end
select_html(options[:field_name] || 'minute', minute_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : ''
if options[:use_hidden]
hidden_html(options[:field_name] || 'minute', val, options)
else
minute_options = []
0.step(59, options[:minute_step] || 1) do |minute|
minute_options << ((val == minute) ?
%(<option value="#{leading_zero_on_single_digits(minute)}" selected="selected">#{leading_zero_on_single_digits(minute)}</option>\n) :
%(<option value="#{leading_zero_on_single_digits(minute)}">#{leading_zero_on_single_digits(minute)}</option>\n)
)
end
select_html(options[:field_name] || 'minute', minute_options, options)
end
end
# Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
# The <tt>hour</tt> can also be substituted for a hour number.
# Override the field name using the <tt>:field_name</tt> option, 'hour' by default.
def select_hour(datetime, options = {})
hour_options = []
0.upto(23) do |hour|
hour_options << ((datetime && (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) == hour) ?
%(<option value="#{leading_zero_on_single_digits(hour)}" selected="selected">#{leading_zero_on_single_digits(hour)}</option>\n) :
%(<option value="#{leading_zero_on_single_digits(hour)}">#{leading_zero_on_single_digits(hour)}</option>\n)
)
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : ''
if options[:use_hidden]
hidden_html(options[:field_name] || 'hour', val, options)
else
hour_options = []
0.upto(23) do |hour|
hour_options << ((val == hour) ?
%(<option value="#{leading_zero_on_single_digits(hour)}" selected="selected">#{leading_zero_on_single_digits(hour)}</option>\n) :
%(<option value="#{leading_zero_on_single_digits(hour)}">#{leading_zero_on_single_digits(hour)}</option>\n)
)
end
select_html(options[:field_name] || 'hour', hour_options, options)
end
select_html(options[:field_name] || 'hour', hour_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
end
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
# The <tt>date</tt> can also be substituted for a hour number.
# Override the field name using the <tt>:field_name</tt> option, 'day' by default.
def select_day(date, options = {})
day_options = []
1.upto(31) do |day|
day_options << ((date && (date.kind_of?(Fixnum) ? date : date.day) == day) ?
%(<option value="#{day}" selected="selected">#{day}</option>\n) :
%(<option value="#{day}">#{day}</option>\n)
)
val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
if options[:use_hidden]
hidden_html(options[:field_name] || 'day', val, options)
else
day_options = []
1.upto(31) do |day|
day_options << ((val == day) ?
%(<option value="#{day}" selected="selected">#{day}</option>\n) :
%(<option value="#{day}">#{day}</option>\n)
)
end
select_html(options[:field_name] || 'day', day_options, options)
end
select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
end
# Returns a select tag with options for each of the months January through December with the current month selected.
# The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are used as values
# (what's submitted to the server). It's also possible to use month numbers for the presentation instead of names --
# set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names,
# set the <tt>:add_month_numbers</tt> key in +options+ to true. Examples:
# set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer to show month names as abbreviations,
# set the <tt>:use_short_month</tt> key in +options+ to true. If you want to use your own month names, set the
# <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
#
# Examples:
#
# select_month(Date.today) # Will use keys like "January", "March"
# select_month(Date.today, :use_month_numbers => true) # Will use keys like "1", "3"
# select_month(Date.today, :add_month_numbers => true) # Will use keys like "1 - January", "3 - March"
# select_month(Date.today, :use_short_month => true) # Will use keys like "Jan", "Mar"
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...)) # Will use keys like "Januar", "Marts"
#
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
#
# If you would prefer to show month names as abbreviations, set the
# <tt>:use_short_month</tt> key in +options+ to true.
def select_month(date, options = {})
month_options = []
month_names = options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES
val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
if options[:use_hidden]
hidden_html(options[:field_name] || 'month', val, options)
else
month_options = []
month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
month_names.unshift(nil) if month_names.size < 13
1.upto(12) do |month_number|
month_name = if options[:use_month_numbers]
month_number
elsif options[:add_month_numbers]
month_number.to_s + ' - ' + month_names[month_number]
else
month_names[month_number]
end
1.upto(12) do |month_number|
month_name = if options[:use_month_numbers]
month_number
elsif options[:add_month_numbers]
month_number.to_s + ' - ' + month_names[month_number]
else
month_names[month_number]
month_options << ((val == month_number) ?
%(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
%(<option value="#{month_number}">#{month_name}</option>\n)
)
end
month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
%(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
%(<option value="#{month_number}">#{month_name}</option>\n)
)
select_html(options[:field_name] || 'month', month_options, options)
end
select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
end
# Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius
@@ -243,37 +291,51 @@ module ActionView
#
# select_year(Date.today, :start_year => 1992, :end_year => 2007) # ascending year values
# select_year(Date.today, :start_year => 2005, :end_year => 1900) # descending year values
# select_year(2006, :start_year => 2000, :end_year => 2010)
#
# Override the field name using the <tt>:field_name</tt> option, 'year' by default.
def select_year(date, options = {})
year_options = []
y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
val = date ? (date.kind_of?(Fixnum) ? date : date.year) : ''
if options[:use_hidden]
hidden_html(options[:field_name] || 'year', val, options)
else
year_options = []
y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
start_year, end_year = (options[:start_year] || y-5), (options[:end_year] || y+5)
step_val = start_year < end_year ? 1 : -1
start_year.step(end_year, step_val) do |year|
year_options << ((date && (date.kind_of?(Fixnum) ? date : date.year) == year) ?
%(<option value="#{year}" selected="selected">#{year}</option>\n) :
%(<option value="#{year}">#{year}</option>\n)
)
start_year, end_year = (options[:start_year] || y-5), (options[:end_year] || y+5)
step_val = start_year < end_year ? 1 : -1
start_year.step(end_year, step_val) do |year|
year_options << ((val == year) ?
%(<option value="#{year}" selected="selected">#{year}</option>\n) :
%(<option value="#{year}">#{year}</option>\n)
)
end
select_html(options[:field_name] || 'year', year_options, options)
end
select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
end
private
def select_html(type, options, prefix = nil, include_blank = false, discard_type = false, disabled = false)
select_html = %(<select name="#{prefix || DEFAULT_PREFIX})
select_html << "[#{type}]" unless discard_type
select_html << %(")
select_html << %( disabled="disabled") if disabled
def select_html(type, html_options, options)
name_and_id_from_options(options, type)
select_html = %(<select id="#{options[:id]}" name="#{options[:name]}")
select_html << %( disabled="disabled") if options[:disabled]
select_html << %(>\n)
select_html << %(<option value=""></option>\n) if include_blank
select_html << options.to_s
select_html << %(<option value=""></option>\n) if options[:include_blank]
select_html << html_options.to_s
select_html << "</select>\n"
end
def hidden_html(type, value, options)
name_and_id_from_options(options, type)
hidden_html = %(<input type="hidden" id="#{options[:id]}" name="#{options[:name]}" value="#{value}" />\n)
end
def name_and_id_from_options(options, type)
options[:name] = (options[:prefix] || DEFAULT_PREFIX) + (options[:discard_type] ? '' : "[#{type}]")
options[:id] = options[:name].gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
end
def leading_zero_on_single_digits(number)
number > 9 ? number : "0#{number}"
end
@@ -283,45 +345,71 @@ module ActionView
include DateHelper
def to_date_select_tag(options = {})
defaults = { :discard_type => true }
options = defaults.merge(options)
options_with_prefix = Proc.new { |position| options.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") }
value = value(object)
date = options[:include_blank] ? (value || 0) : (value || Date.today)
date_or_time_select options.merge(:discard_hour => true)
end
date_select = ''
options[:order] = [:month, :year, :day] if options[:month_before_year] # For backwards compatibility
options[:order] ||= [:year, :month, :day]
position = {:year => 1, :month => 2, :day => 3}
discard = {}
discard[:year] = true if options[:discard_year]
discard[:month] = true if options[:discard_month]
discard[:day] = true if options[:discard_day] or options[:discard_month]
options[:order].each do |param|
date_select << self.send("select_#{param}", date, options_with_prefix.call(position[param])) unless discard[param]
end
date_select
def to_time_select_tag(options = {})
date_or_time_select options.merge(:discard_year => true, :discard_month => true)
end
def to_datetime_select_tag(options = {})
defaults = { :discard_type => true }
options = defaults.merge(options)
options_with_prefix = Proc.new { |position| options.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") }
value = value(object)
datetime = options[:include_blank] ? (value || nil) : (value || Time.now)
datetime_select = select_year(datetime, options_with_prefix.call(1))
datetime_select << select_month(datetime, options_with_prefix.call(2)) unless options[:discard_month]
datetime_select << select_day(datetime, options_with_prefix.call(3)) unless options[:discard_day] || options[:discard_month]
datetime_select << ' &mdash; ' + select_hour(datetime, options_with_prefix.call(4)) unless options[:discard_hour]
datetime_select << ' : ' + select_minute(datetime, options_with_prefix.call(5)) unless options[:discard_minute] || options[:discard_hour]
datetime_select
date_or_time_select options
end
private
def date_or_time_select(options)
defaults = { :discard_type => true }
options = defaults.merge(options)
datetime = value(object)
datetime ||= Time.now unless options[:include_blank]
position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 }
order = (options[:order] ||= [:year, :month, :day])
# Discard explicit and implicit by not being included in the :order
discard = {}
discard[:year] = true if options[:discard_year] or !order.include?(:year)
discard[:month] = true if options[:discard_month] or !order.include?(:month)
discard[:day] = true if options[:discard_day] or discard[:month] or !order.include?(:day)
discard[:hour] = true if options[:discard_hour]
discard[:minute] = true if options[:discard_minute] or discard[:hour]
discard[:second] = true unless options[:include_seconds] && !discard[:minute]
# Maintain valid dates by including hidden fields for discarded elements
[:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
# Ensure proper ordering of :hour, :minute and :second
[:hour, :minute, :second].each { |o| order.delete(o); order.push(o) }
date_or_time_select = ''
order.reverse.each do |param|
# Send hidden fields for discarded elements once output has started
# This ensures AR can reconstruct valid dates using ParseDate
next if discard[param] && date_or_time_select.empty?
date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param]))))
date_or_time_select.insert(0,
case param
when :hour then (discard[:year] && discard[:day] ? "" : " &mdash; ")
when :minute then " : "
when :second then options[:include_seconds] ? " : " : ""
else ""
end)
end
date_or_time_select
end
def options_with_prefix(position, options)
prefix = "#{@object_name}"
if options[:index]
prefix << "[#{options[:index]}]"
elsif @auto_index
prefix << "[#{@auto_index}]"
end
options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}i)]")
end
end
class FormBuilder
@@ -329,6 +417,10 @@ module ActionView
@template.date_select(@object_name, method, options.merge(:object => @object))
end
def time_select(method, options = {})
@template.time_select(@object_name, method, options.merge(:object => @object))
end
def datetime_select(method, options = {})
@template.datetime_select(@object_name, method, options.merge(:object => @object))
end

View File

@@ -3,6 +3,16 @@ module ActionView
# Provides a set of methods for making it easier to locate problems.
module DebugHelper
# Returns a <pre>-tag set with the +object+ dumped by YAML. Very readable way to inspect an object.
# my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]}
# debug(my_hash)
# => <pre class='debug_dump'>---
# first: 1
# second: two
# third:
# - 1
# - 2
# - 3
# </pre>
def debug(object)
begin
Marshal::dump(object)

View File

@@ -0,0 +1,37 @@
module ActionView
module Helpers
module PrototypeHelper
# Method to execute an element update using Prototype.
# DEPRECATION WARNING: This helper has been depercated; use RJS instead.
# See ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods for more information.
def update_element_function(element_id, options = {}, &block)
content = escape_javascript(options[:content] || '')
content = escape_javascript(capture(&block)) if block
javascript_function = case (options[:action] || :update)
when :update
if options[:position]
"new Insertion.#{options[:position].to_s.camelize}('#{element_id}','#{content}')"
else
"$('#{element_id}').innerHTML = '#{content}'"
end
when :empty
"$('#{element_id}').innerHTML = ''"
when :remove
"Element.remove('#{element_id}')"
else
raise ArgumentError, "Invalid action, choose one of :update, :remove, :empty"
end
javascript_function << ";\n"
options[:binding] ? concat(javascript_function, options[:binding]) : javascript_function
end
deprecate :update_element_function => "use RJS instead"
end
end
end

View File

@@ -142,11 +142,13 @@ module ActionView
#
# Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
# Like collection_select and datetime_select.
def fields_for(object_name, *args, &proc)
def fields_for(object_name, *args, &block)
raise ArgumentError, "Missing block" unless block_given?
options = args.last.is_a?(Hash) ? args.pop : {}
object = args.first
yield((options[:builder] || FormBuilder).new(object_name, object, self, options, proc))
builder = options[:builder] || ActionView::Base.default_form_builder
yield builder.new(object_name, object, self, options, block)
end
# Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object
@@ -385,7 +387,7 @@ module ActionView
options["name"] ||= tag_name_with_index(@auto_index)
options["id"] ||= tag_id_with_index(@auto_index)
else
options["name"] ||= tag_name
options["name"] ||= tag_name + (options.has_key?('multiple') ? '[]' : '')
options["id"] ||= tag_id
end
end
@@ -436,4 +438,9 @@ module ActionView
end
end
end
class Base
cattr_accessor :default_form_builder
self.default_form_builder = ::ActionView::Helpers::FormBuilder
end
end

View File

@@ -189,9 +189,9 @@ module ActionView
# Wrapper for text_field with added AJAX autocompletion functionality.
#
# In your controller, you'll need to define an action called
# auto_complete_for_object_method to respond the AJAX calls,
# auto_complete_for to respond the AJAX calls,
#
# See the RDoc on ActionController::AutoComplete to learn more about this.
# See the RDoc on ActionController::Macros::AutoComplete to learn more about this.
def text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {})
(completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
text_field(object, method, tag_options) +

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005 Jon Tirsen (http://www.tirsen.com)
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
@@ -473,6 +473,7 @@ Ajax.InPlaceEditor.prototype = {
this.element = $(element);
this.options = Object.extend({
paramName: "value",
okButton: true,
okText: "ok",
cancelLink: true,
@@ -604,7 +605,7 @@ Ajax.InPlaceEditor.prototype = {
var textField = document.createElement("input");
textField.obj = this;
textField.type = "text";
textField.name = "value";
textField.name = this.options.paramName;
textField.value = text;
textField.style.backgroundColor = this.options.highlightcolor;
textField.className = 'editor_field';
@@ -617,7 +618,7 @@ Ajax.InPlaceEditor.prototype = {
this.options.textarea = true;
var textArea = document.createElement("textarea");
textArea.obj = this;
textArea.name = "value";
textArea.name = this.options.paramName;
textArea.value = this.convertHTMLLineBreaks(text);
textArea.rows = this.options.rows;
textArea.cols = this.options.cols || 40;

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)
@@ -10,7 +10,7 @@
// converts rgb() and #xxx to #xxxxxx format,
// returns self (or first argument) if not convertable
String.prototype.parseColor = function() {
var color = '#';
var color = '#';
if(this.slice(0,4) == 'rgb(') {
var cols = this.slice(4,this.length-1).split(',');
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
@@ -939,8 +939,142 @@ Effect.Fold = function(element) {
}}, arguments[1] || {}));
};
Effect.Morph = Class.create();
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
initialize: function(element) {
this.element = $(element);
if(!this.element) throw(Effect._elementDoesNotExistError);
var options = Object.extend({
style: ''
}, arguments[1] || {});
this.start(options);
},
setup: function(){
function parseColor(color){
if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
color = color.parseColor();
return $R(0,2).map(function(i){
return parseInt( color.slice(i*2+1,i*2+3), 16 )
});
}
this.transforms = this.options.style.parseStyle().map(function(property){
var originalValue = this.element.getStyle(property[0]);
return $H({
style: property[0],
originalValue: property[1].unit=='color' ?
parseColor(originalValue) : parseFloat(originalValue || 0),
targetValue: property[1].unit=='color' ?
parseColor(property[1].value) : property[1].value,
unit: property[1].unit
});
}.bind(this)).reject(function(transform){
return (
(transform.originalValue == transform.targetValue) ||
(
transform.unit != 'color' &&
(isNaN(transform.originalValue) || isNaN(transform.targetValue))
)
)
});
},
update: function(position) {
var style = $H(), value = null;
this.transforms.each(function(transform){
value = transform.unit=='color' ?
$R(0,2).inject('#',function(m,v,i){
return m+(Math.round(transform.originalValue[i]+
(transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) :
transform.originalValue + Math.round(
((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
style[transform.style] = value;
});
this.element.setStyle(style);
}
});
Effect.Transform = Class.create();
Object.extend(Effect.Transform.prototype, {
initialize: function(tracks){
this.tracks = [];
this.options = arguments[1] || {};
this.addTracks(tracks);
},
addTracks: function(tracks){
tracks.each(function(track){
var data = $H(track).values().first();
this.tracks.push($H({
ids: $H(track).keys().first(),
effect: Effect.Morph,
options: { style: data }
}));
}.bind(this));
return this;
},
play: function(){
return new Effect.Parallel(
this.tracks.map(function(track){
var elements = [$(track.ids) || $$(track.ids)].flatten();
return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
}).flatten(),
this.options
);
}
});
Element.CSS_PROPERTIES = ['azimuth', 'backgroundAttachment', 'backgroundColor', 'backgroundImage',
'backgroundPosition', 'backgroundRepeat', 'borderBottomColor', 'borderBottomStyle',
'borderBottomWidth', 'borderCollapse', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth',
'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderSpacing', 'borderTopColor',
'borderTopStyle', 'borderTopWidth', 'bottom', 'captionSide', 'clear', 'clip', 'color', 'content',
'counterIncrement', 'counterReset', 'cssFloat', 'cueAfter', 'cueBefore', 'cursor', 'direction',
'display', 'elevation', 'emptyCells', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch',
'fontStyle', 'fontVariant', 'fontWeight', 'height', 'left', 'letterSpacing', 'lineHeight',
'listStyleImage', 'listStylePosition', 'listStyleType', 'marginBottom', 'marginLeft', 'marginRight',
'marginTop', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity',
'orphans', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowX', 'overflowY',
'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'page', 'pageBreakAfter', 'pageBreakBefore',
'pageBreakInside', 'pauseAfter', 'pauseBefore', 'pitch', 'pitchRange', 'position', 'quotes',
'richness', 'right', 'size', 'speakHeader', 'speakNumeral', 'speakPunctuation', 'speechRate', 'stress',
'tableLayout', 'textAlign', 'textDecoration', 'textIndent', 'textShadow', 'textTransform', 'top',
'unicodeBidi', 'verticalAlign', 'visibility', 'voiceFamily', 'volume', 'whiteSpace', 'widows',
'width', 'wordSpacing', 'zIndex'];
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
String.prototype.parseStyle = function(){
var element = Element.extend(document.createElement('div'));
element.innerHTML = '<div style="' + this + '"></div>';
var style = element.down().style, styleRules = $H();
Element.CSS_PROPERTIES.each(function(property){
if(style[property]) styleRules[property] = style[property];
});
var result = $H();
styleRules.each(function(pair){
var property = pair[0], value = pair[1], unit = null;
if(value.parseColor('#zzzzzz') != '#zzzzzz') {
value = value.parseColor();
unit = 'color';
} else if(Element.CSS_LENGTH.test(value))
var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
result[property.underscore().dasherize()] = $H({ value:value, unit:unit });
}.bind(this));
return result;
};
Element.morph = function(element, style) {
new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
return element;
};
['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
'collectTextNodes','collectTextNodesIgnoreClass'].each(
'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
function(f) { Element.Methods[f] = Element[f]; }
);

File diff suppressed because it is too large Load Diff

View File

@@ -94,16 +94,16 @@ module ActionView
end
# Formats a +number+ with grouped thousands using +delimiter+. You
# can customize the format in the +options+ hash.
# * <tt>:delimiter</tt> - Sets the thousands delimiter, defaults to ","
# * <tt>:separator</tt> - Sets the separator between the units, defaults to "."
# can customize the format using optional <em>delimiter</em> and <em>separator</em> parameters.
# * <tt>delimiter</tt> - Sets the thousands delimiter, defaults to ","
# * <tt>separator</tt> - Sets the separator between the units, defaults to "."
#
# number_with_delimiter(12345678) => 12,345,678
# number_with_delimiter(12345678.05) => 12,345,678.05
# number_with_delimiter(12345678, :delimiter => ".") => 12.345.678
# number_with_delimiter(12345678, ".") => 12.345.678
def number_with_delimiter(number, delimiter=",", separator=".")
begin
parts = number.to_s.split(separator)
parts = number.to_s.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
parts.join separator
rescue

View File

@@ -63,7 +63,7 @@ module ActionView
# can simulate PUT or DELETE over POST. All specified with <tt>options[:method]</tt>
#
# Example:
# link_to_remote "Destroy", person_url(:id => person), :method => :delete
# link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete
#
# By default, these remote requests are processed asynchronous during
# which various JavaScript callbacks can be triggered (for progress
@@ -204,81 +204,6 @@ module ActionView
tag("input", options[:html], false)
end
# Returns a JavaScript function (or expression) that'll update a DOM
# element according to the options passed.
#
# * <tt>:content</tt>: The content to use for updating. Can be left out
# if using block, see example.
# * <tt>:action</tt>: Valid options are :update (assumed by default),
# :empty, :remove
# * <tt>:position</tt> If the :action is :update, you can optionally
# specify one of the following positions: :before, :top, :bottom,
# :after.
#
# Examples:
# <%= javascript_tag(update_element_function("products",
# :position => :bottom, :content => "<p>New product!</p>")) %>
#
# <% replacement_function = update_element_function("products") do %>
# <p>Product 1</p>
# <p>Product 2</p>
# <% end %>
# <%= javascript_tag(replacement_function) %>
#
# This method can also be used in combination with remote method call
# where the result is evaluated afterwards to cause multiple updates on
# a page. Example:
#
# # Calling view
# <%= form_remote_tag :url => { :action => "buy" },
# :complete => evaluate_remote_response %>
# all the inputs here...
#
# # Controller action
# def buy
# @product = Product.find(1)
# end
#
# # Returning view
# <%= update_element_function(
# "cart", :action => :update, :position => :bottom,
# :content => "<p>New Product: #{@product.name}</p>")) %>
# <% update_element_function("status", :binding => binding) do %>
# You've bought a new product!
# <% end %>
#
# Notice how the second call doesn't need to be in an ERb output block
# since it uses a block and passes in the binding to render directly.
# This trick will however only work in ERb (not Builder or other
# template forms).
#
# See also JavaScriptGenerator and update_page.
def update_element_function(element_id, options = {}, &block)
content = escape_javascript(options[:content] || '')
content = escape_javascript(capture(&block)) if block
javascript_function = case (options[:action] || :update)
when :update
if options[:position]
"new Insertion.#{options[:position].to_s.camelize}('#{element_id}','#{content}')"
else
"$('#{element_id}').innerHTML = '#{content}'"
end
when :empty
"$('#{element_id}').innerHTML = ''"
when :remove
"Element.remove('#{element_id}')"
else
raise ArgumentError, "Invalid action, choose one of :update, :remove, :empty"
end
javascript_function << ";\n"
options[:binding] ? concat(javascript_function, options[:binding]) : javascript_function
end
# Returns 'eval(request.responseText)' which is the JavaScript function
# that form_remote_tag can call in :complete to evaluate a multiple
# update return document using update_element_function calls.
@@ -325,8 +250,10 @@ module ActionView
return function
end
# Observes the field with the DOM ID specified by +field_id+ and makes
# an Ajax call when its contents have changed.
# Observes the field with the DOM ID specified by +field_id+ and calls a
# callback when its contents have changed. The default callback is an
# Ajax call. By default the value of the observed field is sent as a
# parameter with the Ajax call.
#
# Required +options+ are either of:
# <tt>:url</tt>:: +url_for+-style options for the action to call
@@ -343,14 +270,24 @@ module ActionView
# <tt>:update</tt>:: Specifies the DOM ID of the element whose
# innerHTML should be updated with the
# XMLHttpRequest response text.
# <tt>:with</tt>:: A JavaScript expression specifying the
# parameters for the XMLHttpRequest. This defaults
# to 'value', which in the evaluated context
# refers to the new field value. If you specify a
# string without a "=", it'll be extended to mean
# the form key that the value should be assigned to.
# So :with => "term" gives "'term'=value". If a "=" is
# present, no extension will happen.
# <tt>:with</tt>:: A JavaScript expression specifying the parameters
# for the XMLHttpRequest. The default is to send the
# key and value of the observed field. Any custom
# expressions should return a valid URL query string.
# The value of the field is stored in the JavaScript
# variable +value+.
#
# Examples
#
# :with => "'my_custom_key=' + value"
# :with => "'person[name]=' + prompt('New name')"
# :with => "Form.Element.serialize('other-field')"
#
# Finally
# :with => 'name'
# is shorthand for
# :with => "'name=' + value"
# This essentially just changes the key of the parameter.
# <tt>:on</tt>:: Specifies which event handler to observe. By default,
# it's set to "changed" for text fields and areas and
# "click" for radio buttons and checkboxes. With this,
@@ -366,11 +303,15 @@ module ActionView
build_observer('Form.Element.EventObserver', field_id, options)
end
end
# Like +observe_field+, but operates on an entire form identified by the
# DOM ID +form_id+. +options+ are the same as +observe_field+, except
# the default value of the <tt>:with</tt> option evaluates to the
# serialized (request string) value of the form.
# Observes the form with the DOM ID specified by +form_id+ and calls a
# callback when its contents have changed. The default callback is an
# Ajax call. By default all fields of the observed field are sent as
# parameters with the Ajax call.
#
# The +options+ for +observe_form+ are the same as the options for
# +observe_field+. The JavaScript variable +value+ available to the
# <tt>:with</tt> option is set to the serialized form by default.
def observe_form(form_id, options = {})
if options[:frequency]
build_observer('Form.Observer', form_id, options)
@@ -466,7 +407,7 @@ module ActionView
# Returns an object whose <tt>#to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript
# expression as an argument to another JavaScriptGenerator method.
def literal(code)
JavaScriptLiteral.new(code)
ActiveSupport::JSON::Variable.new(code.to_s)
end
# Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be
@@ -542,7 +483,7 @@ module ActionView
#
# # Replace the DOM element having ID 'person-45' with the
# # 'person' partial for the appropriate object.
# replace_html 'person-45', :partial => 'person', :object => @person
# replace 'person-45', :partial => 'person', :object => @person
#
# This allows the same partial that is used for the +insert_html+ to
# be also used for the input to +replace+ without resorting to
@@ -735,10 +676,10 @@ module ActionView
end
def build_observer(klass, name, options = {})
if options[:with] && !options[:with].include?("=")
if options[:with] && (options[:with] !~ /[=(.]/)
options[:with] = "'#{options[:with]}=' + value"
else
options[:with] ||= 'value' if options[:update]
options[:with] ||= 'value' unless options[:function]
end
callback = options[:function] || remote_function(options)
@@ -763,13 +704,6 @@ module ActionView
end
end
# Bypasses string escaping so you can pass around raw JavaScript
class JavaScriptLiteral < String #:nodoc:
def to_json
to_s
end
end
# Converts chained method calls on DOM proxy elements into JavaScript chains
class JavaScriptProxy < Builder::BlankSlate #:nodoc:
def initialize(generator, root = nil)

View File

@@ -2,30 +2,48 @@ require 'cgi'
require 'erb'
module ActionView
module Helpers
# This is poor man's Builder for the rare cases where you need to programmatically make tags but can't use Builder.
module Helpers #:nodoc:
# Use these methods to generate HTML tags programmatically when you can't use
# a Builder. By default, they output XHTML compliant tags.
module TagHelper
include ERB::Util
# Examples:
# * <tt>tag("br") => <br /></tt>
# * <tt>tag("input", { "type" => "text"}) => <input type="text" /></tt>
# Returns an empty HTML tag of type +name+ which by default is XHTML
# compliant. Setting +open+ to true will create an open tag compatible
# with HTML 4.0 and below. Add HTML attributes by passing an attributes
# hash to +options+. For attributes with no value like (disabled and
# readonly), give it a value of true in the +options+ hash. You can use
# symbols or strings for the attribute names.
#
# tag("br")
# # => <br />
# tag("br", nil, true)
# # => <br>
# tag("input", { :type => 'text', :disabled => true })
# # => <input type="text" disabled="disabled" />
def tag(name, options = nil, open = false)
"<#{name}#{tag_options(options.stringify_keys) if options}" + (open ? ">" : " />")
"<#{name}#{tag_options(options) if options}" + (open ? ">" : " />")
end
# Examples:
# * <tt>content_tag(:p, "Hello world!") => <p>Hello world!</p></tt>
# * <tt>content_tag(:div, content_tag(:p, "Hello world!"), :class => "strong") => </tt>
# <tt><div class="strong"><p>Hello world!</p></div></tt>
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
# HTML attributes by passing an attributes hash to +options+. For attributes
# with no value like (disabled and readonly), give it a value of true in
# the +options+ hash. You can use symbols or strings for the attribute names.
#
# ERb example:
# <% content_tag :div, :class => "strong" do -%>
# Hello world!
# <% end -%>
# content_tag(:p, "Hello world!")
# # => <p>Hello world!</p>
# content_tag(:div, content_tag(:p, "Hello world!"), :class => "strong")
# # => <div class="strong"><p>Hello world!</p></div>
# content_tag("select", options, :multiple => true)
# # => <select multiple="multiple">...options...</select>
#
# Will output:
# <div class="strong"><p>Hello world!</p></div>
# Instead of passing the content as an argument, you can also use a block
# in which case, you pass your +options+ as the second parameter.
#
# <% content_tag :div, :class => "strong" do -%>
# Hello world!
# <% end -%>
# # => <div class="strong"><p>Hello world!</p></div>
def content_tag(name, content_or_options_with_block = nil, options = nil, &block)
if block_given?
options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
@@ -37,27 +55,28 @@ module ActionView
end
end
# Returns a CDATA section for the given +content+. CDATA sections
# Returns a CDATA section with the given +content+. CDATA sections
# are used to escape blocks of text containing characters which would
# otherwise be recognized as markup. CDATA sections begin with the string
# <tt>&lt;![CDATA[</tt> and end with (and may not contain) the string
# <tt>]]></tt>.
# <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>.
#
# cdata_section("<hello world>")
# # => <![CDATA[<hello world>]]>
def cdata_section(content)
"<![CDATA[#{content}]]>"
end
# Escapes a given string, while leaving any currently escaped entities alone.
# Returns the escaped +html+ without affecting existing escaped entities.
#
# escape_once("1 > 2 &amp; 3")
# # => "1 &lt; 2 &amp; 3"
#
# # => "1 &lt; 2 &amp; 3"
def escape_once(html)
fix_double_escape(html_escape(html.to_s))
end
private
def content_tag_string(name, content, options)
tag_options = options ? tag_options(options.stringify_keys) : ""
tag_options = options ? tag_options(options) : ""
"<#{name}#{tag_options}>#{content}</#{name}>"
end

View File

@@ -154,12 +154,10 @@ module ActionView
# considered as a linebreak and a <tt><br /></tt> tag is appended. This
# method does not remove the newlines from the +text+.
def simple_format(text)
text = text.gsub(/(\r\n|\n|\r)/, "\n") # lets make them newlines crossplatform
text.gsub!(/\n\n+/, "\n\n") # zap dupes
text.gsub!(/\n\n/, '</p>\0<p>') # turn two newlines into paragraph
text.gsub!(/([^\n])(\n)(?=[^\n])/, '\1\2<br />') # turn single newline into <br />
content_tag("p", text)
content_tag 'p', text.to_s.
gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
gsub(/\n\n+/, "</p>\n\n<p>"). # 2+ newline -> paragraph
gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
end
# Turns all urls and email addresses into clickable links. The +link+ parameter
@@ -256,7 +254,7 @@ module ActionView
# html-scanner tokenizer and so its HTML parsing ability is limited by
# that of html-scanner.
def strip_tags(html)
return nil if html.blank?
return html if html.blank?
if html.index("<")
text = ""
tokenizer = HTML::Tokenizer.new(html)
@@ -356,26 +354,26 @@ module ActionView
@_cycles = Hash.new unless defined?(@_cycles)
@_cycles[name] = cycle_object
end
AUTO_LINK_RE = %r{
( # leading text
<\w+.*?>| # leading HTML tag, or
[^=!:'"/]| # leading punctuation, or
^ # beginning of line
( # leading text
<\w+.*?>| # leading HTML tag, or
[^=!:'"/]| # leading punctuation, or
^ # beginning of line
)
(
(?:https?://)| # protocol spec, or
(?:www\.) # www.*
(?:https?://)| # protocol spec, or
(?:www\.) # www.*
)
(
[-\w]+ # subdomain or domain
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
(?:/(?:[~\w%.;-]+)?)* # path
(?:\?[\w%&=.;-]+)? # query string
(?:\#\w*)? # trailing anchor
[-\w]+ # subdomain or domain
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
(?:/(?:(?:[~\w\+%-]|(?:[,.;:][^\s$]))+)?)* # path
(?:\?[\w\+%&=.;-]+)? # query string
(?:\#[\w\-]*)? # trailing anchor
)
([[:punct:]]|\s|<|$) # trailing text
([[:punct:]]|\s|<|$) # trailing text
}x unless const_defined?(:AUTO_LINK_RE)
# Turns all urls into clickable links. If a block is given, each url

View File

@@ -310,9 +310,15 @@ module ActionView
end
end
# Returns true if the current page uri is generated by the +options+ passed.
# True if the current request uri was generated by the given +options+.
def current_page?(options)
CGI.escapeHTML(self.url_for(options)) == @controller.request.request_uri
url_string = CGI.escapeHTML(url_for(options))
request = @controller.request
if url_string =~ /^\w+:\/\//
url_string == "#{request.protocol}#{request.host_with_port}#{request.request_uri}"
else
url_string == request.request_uri
end
end
private

View File

@@ -6,16 +6,22 @@ module ActionView
attr_reader :original_exception
def initialize(base_path, file_name, assigns, source, original_exception)
@base_path, @assigns, @source, @original_exception =
base_path, assigns, source, original_exception
@file_name = file_name
def initialize(base_path, file_path, assigns, source, original_exception)
@base_path, @assigns, @source, @original_exception =
base_path, assigns.dup, source, original_exception
@file_path = file_path
remove_deprecated_assigns!
end
def message
original_exception.message
ActiveSupport::Deprecation.silence { original_exception.message }
end
def clean_backtrace
original_exception.clean_backtrace
end
def sub_template_message
if @sub_templates
"Trace of template inclusion: " +
@@ -24,63 +30,81 @@ module ActionView
""
end
end
def source_extract(indention = 0)
source_code = IO.readlines(@file_name)
start_on_line = [ line_number - SOURCE_CODE_RADIUS - 1, 0 ].max
end_on_line = [ line_number + SOURCE_CODE_RADIUS - 1, source_code.length].min
def source_extract(indentation = 0)
return unless num = line_number
num = num.to_i
source_code = IO.readlines(@file_path)
start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
indent = ' ' * indentation
line_counter = start_on_line
extract = source_code[start_on_line..end_on_line].collect do |line|
source_code[start_on_line..end_on_line].sum do |line|
line_counter += 1
"#{' ' * indention}#{line_counter}: " + line
"#{indent}#{line_counter}: #{line}"
end
extract.join
end
def sub_template_of(file_name)
def sub_template_of(template_path)
@sub_templates ||= []
@sub_templates << file_name
@sub_templates << template_path
end
def line_number
if file_name
regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/
[@original_exception.message, @original_exception.clean_backtrace].flatten.each do |line|
return $1.to_i if regexp =~ line
@line_number ||=
if file_name
regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/
$1 if message =~ regexp or clean_backtrace.find { |line| line =~ regexp }
end
end
0
end
def file_name
stripped = strip_base_path(@file_name)
stripped[0] == ?/ ? stripped[1..-1] : stripped
stripped = strip_base_path(@file_path)
stripped.slice!(0,1) if stripped[0] == ?/
stripped
end
def to_s
"\n\n#{self.class} (#{message}) on line ##{line_number} of #{file_name}:\n" +
source_extract + "\n " +
original_exception.clean_backtrace.join("\n ") +
"\n\n"
"\n\n#{self.class} (#{message}) #{source_location}:\n" +
"#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
end
def backtrace
[
"On line ##{line_number} of #{file_name}\n\n#{source_extract(4)}\n " +
original_exception.clean_backtrace.join("\n ")
[
"#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
clean_backtrace.join("\n ")
]
end
private
def strip_base_path(file_name)
file_name = File.expand_path(file_name).gsub(/^#{Regexp.escape File.expand_path(RAILS_ROOT)}/, '')
file_name.gsub(@base_path, "")
def remove_deprecated_assigns!
ActionController::Base::DEPRECATED_INSTANCE_VARIABLES.each do |ivar|
@assigns.delete(ivar)
end
end
def strip_base_path(path)
File.expand_path(path).
gsub(/^#{Regexp.escape File.expand_path(RAILS_ROOT)}/, '').
gsub(@base_path, "")
end
def source_location
if line_number
"on line ##{line_number} of "
else
'in '
end + file_name
end
end
end
Exception::TraceSubstitutions << [/:in\s+`_run_(html|xml).*'\s*$/, ''] if defined?(Exception::TraceSubstitutions)
Exception::TraceSubstitutions << [%r{^\s*#{Regexp.escape RAILS_ROOT}}, '#{RAILS_ROOT}'] if defined?(RAILS_ROOT)
if defined?(Exception::TraceSubstitutions)
Exception::TraceSubstitutions << [/:in\s+`_run_(html|xml).*'\s*$/, '']
Exception::TraceSubstitutions << [%r{^\s*#{Regexp.escape RAILS_ROOT}}, '#{RAILS_ROOT}'] if defined?(RAILS_ROOT)
end

View File

@@ -5,6 +5,8 @@ class PaginationTest < ActiveRecordTestCase
class PaginationController < ActionController::Base
self.template_root = "#{File.dirname(__FILE__)}/../fixtures/"
around_filter :silence_deprecation_warnings
def simple_paginate
@topic_pages, @topics = paginate(:topics)
@@ -67,6 +69,13 @@ class PaginationTest < ActiveRecordTestCase
:count => "d.id")
render :nothing => true
end
def silence_deprecation_warnings
ActiveSupport::Deprecation.silence do
yield
end
end
def rescue_errors(e) raise e end

View File

@@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../abstract_unit'
class ActionPackAssertionsController < ActionController::Base
# this does absolutely nothing
def nothing() render_text ""; end
def nothing() head :ok end
# a standard template
def hello_world() render "test/hello_world"; end
@@ -19,6 +19,8 @@ class ActionPackAssertionsController < ActionController::Base
def redirect_to_controller() redirect_to :controller => "elsewhere", :action => "flash_me"; end
def redirect_to_controller_with_symbol() redirect_to :controller => :elsewhere, :action => :flash_me; end
def redirect_to_path() redirect_to '/some/path' end
def redirect_to_named_route() redirect_to route_one_url end
@@ -27,13 +29,13 @@ class ActionPackAssertionsController < ActionController::Base
def redirect_external() redirect_to_url "http://www.rubyonrails.org"; end
# a 404
def response404() render_text "", "404 AWOL"; end
def response404() head '404 AWOL' end
# a 500
def response500() render_text "", "500 Sorry"; end
def response500() head '500 Sorry' end
# a fictional 599
def response599() render_text "", "599 Whoah!"; end
def response599() head '599 Whoah!' end
# putting stuff in the flash
def flash_me
@@ -139,6 +141,10 @@ module Admin
def redirect_to_fellow_controller
redirect_to :controller => 'user'
end
def redirect_to_top_level_named_route
redirect_to top_level_url(:id => "foo")
end
end
end
@@ -155,10 +161,16 @@ ActionPackAssertionsController.template_root = File.dirname(__FILE__) + "/../fix
class ActionPackAssertionsControllerTest < Test::Unit::TestCase
# let's get this party started
def setup
ActionController::Routing::Routes.reload
ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module content admin/user))
@controller = ActionPackAssertionsController.new
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
end
def teardown
ActionController::Routing::Routes.reload
end
# -- assertion-based testing ------------------------------------------------
def test_assert_tag_and_url_for
@@ -295,6 +307,19 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
end
end
def test_assert_redirected_to_top_level_named_route_from_nested_controller
with_routing do |set|
set.draw do |map|
map.top_level '/action_pack_assertions/:id', :controller => 'action_pack_assertions', :action => 'index'
map.connect ':controller/:action/:id'
end
@controller = Admin::InnerModuleController.new
process :redirect_to_top_level_named_route
# passes -> assert_redirected_to "http://test.host/action_pack_assertions/foo"
assert_redirected_to "/action_pack_assertions/foo"
end
end
# test the flash-based assertions with something is in the flash
def test_flash_assertions_full
process :flash_me
@@ -402,7 +427,9 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
process :redirect_external
assert_equal 'http://www.rubyonrails.org', @response.redirect_url
end
def test_no_redirect_url
process :nothing
assert_nil @response.redirect_url
end
@@ -530,6 +557,17 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
assert_redirected_to 'http://test.host/some/path'
end
def test_assert_redirection_with_symbol
process :redirect_to_controller_with_symbol
assert_nothing_raised {
assert_redirected_to :controller => "elsewhere", :action => "flash_me"
}
process :redirect_to_controller_with_symbol
assert_nothing_raised {
assert_redirected_to :controller => :elsewhere, :action => :flash_me
}
end
def test_redirected_to_with_nested_controller
@controller = Admin::InnerModuleController.new
get :redirect_to_absolute_controller

View File

@@ -39,7 +39,10 @@ class AddressesTest < Test::Unit::TestCase
end
def test_list
get :list
# because pagination is deprecated
ActiveSupport::Deprecation.silence do
get :list
end
assert_equal "We only need to get this far!", @response.body.chomp
end
end

View File

@@ -13,7 +13,7 @@ unless defined?(ActionMailer)
require 'action_mailer'
rescue LoadError
require 'rubygems'
require_gem 'actionmailer'
gem 'actionmailer'
end
end

View File

@@ -88,7 +88,7 @@ class ControllerInstanceTests < Test::Unit::TestCase
# Mocha adds methods to Object which are then included in the public_instance_methods
# This method hides those from the controller so the above tests won't know the difference
def hide_mocha_methods_from_controller(controller)
mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify]
mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify, :__is_a__, :__metaclass__]
controller.class.send(:hide_action, *mocha_methods)
end

View File

@@ -5,8 +5,29 @@ CACHE_DIR = 'test_cache'
# Don't change '/../temp/' cavalierly or you might hoze something you don't want hozed
FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
ActionController::Base.perform_caching = true
ActionController::Base.page_cache_directory = FILE_STORE_PATH
ActionController::Base.fragment_cache_store = :file_store, FILE_STORE_PATH
class PageCachingTestController < ActionController::Base
caches_page :ok, :no_content, :found, :not_found
def ok
head :ok
end
def no_content
head :no_content
end
def found
redirect_to :action => 'ok'
end
def not_found
head :not_found
end
end
class PageCachingTest < Test::Unit::TestCase
def setup
ActionController::Routing::Routes.draw do |map|
@@ -14,11 +35,23 @@ class PageCachingTest < Test::Unit::TestCase
map.resources :posts
map.connect ':controller/:action/:id'
end
@request = ActionController::TestRequest.new
@request.host = 'hostname.com'
@response = ActionController::TestResponse.new
@controller = PageCachingTestController.new
@params = {:controller => 'posts', :action => 'index', :only_path => true, :skip_relative_url_root => true}
@rewriter = ActionController::UrlRewriter.new(@request, @params)
end
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
FileUtils.mkdir_p(FILE_STORE_PATH)
end
def teardown
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
end
def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
@params[:format] = 'rss'
@@ -26,35 +59,68 @@ class PageCachingTest < Test::Unit::TestCase
@params[:format] = nil
assert_equal '/', @rewriter.rewrite(@params)
end
def test_should_cache_get_with_ok_status
get :ok
assert_response :ok
assert_page_cached :ok, "get with ok status should have been cached"
end
[:ok, :no_content, :found, :not_found].each do |status|
[:get, :post, :put, :delete].each do |method|
unless method == :get and status == :ok
define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
@request.env['REQUEST_METHOD'] = method.to_s.upcase
process status
assert_response status
assert_page_not_cached status, "#{method} with #{status} status shouldn't have been cached"
end
end
end
end
private
def assert_page_cached(action, message = "#{action} should have been cached")
assert page_cached?(action), message
end
def assert_page_not_cached(action, message = "#{action} shouldn't have been cached")
assert !page_cached?(action), message
end
def page_cached?(action)
File.exist? "#{FILE_STORE_PATH}/page_caching_test/#{action}.html"
end
end
class ActionCachingTestController < ActionController::Base
caches_action :index
def index
sleep 0.01
@cache_this = Time.now.to_f.to_s
render :text => @cache_this
end
def expire
expire_action :controller => 'action_caching_test', :action => 'index'
render :nothing => true
end
end
class ActionCachingMockController
attr_accessor :mock_url_for
attr_accessor :mock_path
def initialize
yield self if block_given?
end
def url_for(*args)
@mock_url_for
end
def request
mocked_path = @mock_path
Object.new.instance_eval(<<-EVAL)
@@ -71,95 +137,93 @@ class ActionCacheTest < Test::Unit::TestCase
@path_class = ActionController::Caching::Actions::ActionCachePath
@mock_controller = ActionCachingMockController.new
end
def teardown
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
end
def test_simple_action_cache
get :index
cached_time = content_to_cache
assert_equal cached_time, @response.body
reset!
get :index
assert_equal cached_time, @response.body
end
def test_cache_expiration
get :index
cached_time = content_to_cache
reset!
get :index
assert_equal cached_time, @response.body
reset!
get :expire
reset!
get :index
new_cached_time = content_to_cache
assert_not_equal cached_time, @response.body
reset!
get :index
assert_response :success
assert_equal new_cached_time, @response.body
end
def test_cache_is_scoped_by_subdomain
@request.host = 'jamis.hostname.com'
get :index
jamis_cache = content_to_cache
@request.host = 'david.hostname.com'
get :index
david_cache = content_to_cache
assert_not_equal jamis_cache, @response.body
@request.host = 'jamis.hostname.com'
get :index
assert_equal jamis_cache, @response.body
@request.host = 'david.hostname.com'
get :index
assert_equal david_cache, @response.body
end
def test_xml_version_of_resource_is_treated_as_different_cache
@mock_controller.mock_url_for = 'http://example.org/posts/'
@mock_controller.mock_path = '/posts/index.xml'
path_object = @path_class.new(@mock_controller)
path_object = @path_class.new(@mock_controller, {})
assert_equal 'xml', path_object.extension
assert_equal 'example.org/posts/index.xml', path_object.path
end
def test_empty_path_is_normalized
@mock_controller.mock_url_for = 'http://example.org/'
@mock_controller.mock_path = '/'
assert_equal 'example.org/index', @path_class.path_for(@mock_controller)
assert_equal 'example.org/index', @path_class.path_for(@mock_controller, {})
end
def test_file_extensions
get :index, :id => 'kitten.jpg'
get :index, :id => 'kitten.jpg'
get :index, :id => 'kitten.jpg'
assert_response :success
end
private
def content_to_cache
assigns(:cache_this)
end
def reset!
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@controller = ActionCachingTestController.new
@request.host = 'hostname.com'
end
end
end

View File

@@ -7,15 +7,15 @@ class CaptureController < ActionController::Base
def content_for
render :layout => "talk_from_action"
end
def erb_content_for
render :layout => "talk_from_action"
end
def block_content_for
render :layout => "talk_from_action"
end
def non_erb_block_content_for
render :layout => "talk_from_action"
end
@@ -43,36 +43,38 @@ class CaptureTest < Test::Unit::TestCase
get :capturing
assert_equal "Dreamy days", @response.body.strip
end
def test_content_for
get :content_for
assert_equal expected_content_for_output, @response.body
end
def test_erb_content_for
get :content_for
assert_equal expected_content_for_output, @response.body
end
def test_block_content_for
get :block_content_for
assert_equal expected_content_for_output, @response.body
end
def test_non_erb_block_content_for
get :non_erb_block_content_for
assert_equal expected_content_for_output, @response.body
end
def test_update_element_with_capture
get :update_element_with_capture
assert_deprecated 'update_element_function' do
get :update_element_with_capture
end
assert_equal(
"<script type=\"text/javascript\">\n//<![CDATA[\n$('products').innerHTML = '\\n <p>Product 1</p>\\n <p>Product 2</p>\\n';\n\n//]]>\n</script>" +
"\n\n$('status').innerHTML = '\\n <b>You bought something!</b>\\n';",
"\n\n$('status').innerHTML = '\\n <b>You bought something!</b>\\n';",
@response.body.strip
)
end
private
def expected_content_for_output
"<title>Putting stuff in the title!</title>\n\nGreat stuff!"

View File

@@ -155,9 +155,10 @@ class CGITest < Test::Unit::TestCase
end
def test_parse_params_from_multipart_upload
mockup = Struct.new(:content_type, :original_filename)
mockup = Struct.new(:content_type, :original_filename, :read, :rewind)
file = mockup.new('img/jpeg', 'foo.jpg')
ie_file = mockup.new('img/jpeg', 'c:\\Documents and Settings\\foo\\Desktop\\bar.jpg')
non_file_text_part = mockup.new('text/plain', '', 'abc')
input = {
"something" => [ StringIO.new("") ],
@@ -168,9 +169,10 @@ class CGITest < Test::Unit::TestCase
"products[string]" => [ StringIO.new("Apple Computer") ],
"products[file]" => [ file ],
"ie_products[string]" => [ StringIO.new("Microsoft") ],
"ie_products[file]" => [ ie_file ]
"ie_products[file]" => [ ie_file ],
"text_part" => [non_file_text_part]
}
expected_output = {
"something" => "",
"array_of_stringios" => ["One", "Two"],
@@ -192,7 +194,8 @@ class CGITest < Test::Unit::TestCase
"ie_products" => {
"string" => "Microsoft",
"file" => ie_file
}
},
"text_part" => "abc"
}
params = CGIMethods.parse_request_parameters(input)
@@ -338,7 +341,7 @@ class MultipartCGITest < Test::Unit::TestCase
assert_equal 'bar', params['foo']
# Ruby CGI doesn't handle multipart/mixed for us.
assert_kind_of StringIO, params['files']
assert_kind_of String, params['files']
assert_equal 19756, params['files'].size
end
@@ -422,4 +425,16 @@ class CGIRequestTest < Test::Unit::TestCase
assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], alt_cookies["_session_id"]
assert_equal ["yes"], alt_cookies["is_admin"]
end
def test_unbalanced_query_string_with_array
assert_equal(
{'location' => ["1", "2"], 'age_group' => ["2"]},
CGIMethods.parse_query_parameters("location[]=1&location[]=2&age_group[]=2")
)
assert_equal(
{'location' => ["1", "2"], 'age_group' => ["2"]},
CGIMethods.parse_request_parameters({'location[]' => ["1", "2"],
'age_group[]' => ["2"]})
)
end
end

View File

@@ -134,7 +134,8 @@ module A
class NestedController < ActionController::Base
# Stub for uses_component_template_root
def self.caller
['./test/fixtures/a/b/c/nested_controller.rb']
[ '/path/to/active_support/deprecation.rb:93:in `uses_component_template_root',
'./test/fixtures/a/b/c/nested_controller.rb' ]
end
end
end
@@ -143,6 +144,8 @@ end
class UsesComponentTemplateRootTest < Test::Unit::TestCase
def test_uses_component_template_root
assert_equal './test/fixtures/', A::B::C::NestedController.uses_component_template_root
assert_deprecated 'uses_component_template_root' do
assert_equal './test/fixtures/', A::B::C::NestedController.uses_component_template_root
end
end
end

View File

@@ -4,77 +4,104 @@ class CookieTest < Test::Unit::TestCase
class TestController < ActionController::Base
def authenticate_with_deprecated_writer
cookie "name" => "user_name", "value" => "david"
render_text "hello world"
end
def authenticate
cookies["user_name"] = "david"
render_text "hello world"
end
def authenticate_for_fourten_days
cookies["user_name"] = { "value" => "david", "expires" => Time.local(2005, 10, 10) }
render_text "hello world"
end
def authenticate_for_fourten_days_with_symbols
cookies[:user_name] = { :value => "david", :expires => Time.local(2005, 10, 10) }
render_text "hello world"
end
def set_multiple_cookies
cookies["user_name"] = { "value" => "david", "expires" => Time.local(2005, 10, 10) }
cookies["login"] = "XJ-122"
render_text "hello world"
end
def access_frozen_cookies
cookies["will"] = "work"
end
def logout
cookies.delete("user_name")
end
def delete_cookie_with_path
cookies.delete("user_name", :path => '/beaten')
render_text "hello world"
end
def rescue_action(e) raise end
def rescue_action(e)
raise unless ActionController::MissingTemplate # No templates here, and we don't care about the output
end
end
def setup
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@controller = TestController.new
@request.host = "www.nextangle.com"
end
def test_setting_cookie_with_deprecated_writer
@request.action = "authenticate_with_deprecated_writer"
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david") ], process_request.headers["cookie"]
get :authenticate_with_deprecated_writer
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david") ], @response.headers["cookie"]
end
def test_setting_cookie
@request.action = "authenticate"
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david") ], process_request.headers["cookie"]
get :authenticate
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david") ], @response.headers["cookie"]
end
def test_setting_cookie_for_fourteen_days
@request.action = "authenticate_for_fourten_days"
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david", "expires" => Time.local(2005, 10, 10)) ], process_request.headers["cookie"]
get :authenticate_for_fourten_days
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david", "expires" => Time.local(2005, 10, 10)) ], @response.headers["cookie"]
end
def test_setting_cookie_for_fourteen_days_with_symbols
@request.action = "authenticate_for_fourten_days"
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david", "expires" => Time.local(2005, 10, 10)) ], process_request.headers["cookie"]
get :authenticate_for_fourten_days
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david", "expires" => Time.local(2005, 10, 10)) ], @response.headers["cookie"]
end
def test_multiple_cookies
@request.action = "set_multiple_cookies"
assert_equal 2, process_request.headers["cookie"].size
get :set_multiple_cookies
assert_equal 2, @response.cookies.size
end
def test_setting_test_cookie
@request.action = "access_frozen_cookies"
assert_nothing_raised { process_request }
assert_nothing_raised { get :access_frozen_cookies }
end
def test_expiring_cookie
get :logout
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "", "expires" => Time.at(0)) ], @response.headers["cookie"]
end
def test_cookiejar_accessor
@request.cookies["user_name"] = CGI::Cookie.new("name" => "user_name", "value" => "david", "expires" => Time.local(2025, 10, 10))
@controller.request = @request
jar = ActionController::CookieJar.new(@controller)
assert_equal "david", jar["user_name"]
assert_equal nil, jar["something_else"]
end
private
def process_request
TestController.process(@request, @response)
end
def test_cookiejar_accessor_with_array_value
a = %w{1 2 3}
@request.cookies["pages"] = CGI::Cookie.new("name" => "pages", "value" => a, "expires" => Time.local(2025, 10, 10))
@controller.request = @request
jar = ActionController::CookieJar.new(@controller)
assert_equal a, jar["pages"]
end
def test_delete_cookie_with_path
get :delete_cookie_with_path
assert_equal "/beaten", @response.headers["cookie"].first.path
assert_not_equal "/", @response.headers["cookie"].first.path
end
end

View File

@@ -1,6 +1,12 @@
require File.dirname(__FILE__) + '/../../abstract_unit'
class DeprecatedBaseMethodsTest < Test::Unit::TestCase
# ActiveRecord model mock to test pagination deprecation
class DummyModel
def self.find(*args) [] end
def self.count(*args) 0 end
end
class Target < ActionController::Base
def deprecated_symbol_parameter_to_url_for
redirect_to(url_for(:home_url, "superstars"))
@@ -14,6 +20,15 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase
"http://example.com/#{greeting}"
end
def raises_name_error
this_method_doesnt_exist
end
def pagination
paginate :dummy_models, :class_name => 'DeprecatedBaseMethodsTest::DummyModel'
render :nothing => true
end
def rescue_action(e) raise e end
end
@@ -23,6 +38,7 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@controller = Target.new
@controller.logger = Logger.new(nil) unless @controller.logger
end
def test_deprecated_symbol_parameter_to_url_for
@@ -40,4 +56,23 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase
assert_equal "Living in a nested world", @response.body
end
def test_log_error_silences_deprecation_warnings
get :raises_name_error
rescue => e
assert_not_deprecated { @controller.send :log_error, e }
end
def test_assertion_failed_error_silences_deprecation_warnings
get :raises_name_error
rescue => e
error = Test::Unit::Error.new('testing ur doodz', e)
assert_not_deprecated { error.message }
end
def test_pagination_deprecation
assert_deprecated('svn://errtheblog.com/svn/plugins/classic_pagination') do
get :pagination
end
end
end

View File

@@ -16,6 +16,7 @@ class FilterParamTest < Test::Unit::TestCase
assert @controller.respond_to?(:filter_parameters)
test_hashes = [[{},{},[]],
[{'foo'=>nil},{'foo'=>nil},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},%w'food'],
[{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'],

View File

@@ -14,7 +14,7 @@ class FilterTest < Test::Unit::TestCase
@ran_filter ||= []
@ran_filter << "ensure_login"
end
def clean_up
@ran_after_filter ||= []
@ran_after_filter << "clean_up"
@@ -62,7 +62,7 @@ class FilterTest < Test::Unit::TestCase
render :inline => "something else"
end
end
class ConditionalFilterController < ActionController::Base
def show
render :inline => "ran action"
@@ -86,7 +86,7 @@ class FilterTest < Test::Unit::TestCase
@ran_filter ||= []
@ran_filter << "clean_up_tmp"
end
def rescue_action(e) raise(e) end
end
@@ -94,7 +94,7 @@ class FilterTest < Test::Unit::TestCase
before_filter :ensure_login, :except => [ :show_without_filter, :another_action ]
end
class OnlyConditionSymController < ConditionalFilterController
class OnlyConditionSymController < ConditionalFilterController
before_filter :ensure_login, :only => :show
end
@@ -104,10 +104,10 @@ class FilterTest < Test::Unit::TestCase
class BeforeAndAfterConditionController < ConditionalFilterController
before_filter :ensure_login, :only => :show
after_filter :clean_up_tmp, :only => :show
after_filter :clean_up_tmp, :only => :show
end
class OnlyConditionProcController < ConditionalFilterController
class OnlyConditionProcController < ConditionalFilterController
before_filter(:only => :show) {|c| c.assigns["ran_proc_filter"] = true }
end
@@ -131,6 +131,14 @@ class FilterTest < Test::Unit::TestCase
before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.assigns["ran_proc_filter1"] = true }, :except => :show_without_filter) { |c| c.assigns["ran_proc_filter2"] = true}
end
class EmptyFilterChainController < TestController
self.filter_chain.clear
def show
@action_executed = true
render :text => "yawp!"
end
end
class PrependingController < TestController
prepend_before_filter :wonderful_life
# skip_before_filter :fire_flash
@@ -145,7 +153,7 @@ class FilterTest < Test::Unit::TestCase
class ConditionalSkippingController < TestController
skip_before_filter :ensure_login, :only => [ :login ]
skip_after_filter :clean_up, :only => [ :login ]
before_filter :find_user, :only => [ :change_password ]
def login
@@ -155,7 +163,7 @@ class FilterTest < Test::Unit::TestCase
def change_password
render :inline => "ran action"
end
protected
def find_user
@ran_filter ||= []
@@ -166,15 +174,15 @@ class FilterTest < Test::Unit::TestCase
class ConditionalParentOfConditionalSkippingController < ConditionalFilterController
before_filter :conditional_in_parent, :only => [:show, :another_action]
after_filter :conditional_in_parent, :only => [:show, :another_action]
private
def conditional_in_parent
@ran_filter ||= []
@ran_filter << 'conditional_in_parent'
end
end
class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
skip_before_filter :conditional_in_parent, :only => :another_action
skip_after_filter :conditional_in_parent, :only => :another_action
@@ -197,7 +205,7 @@ class FilterTest < Test::Unit::TestCase
controller.assigns["was_audited"] = true
end
end
class AroundFilter
def before(controller)
@execution_log = "before"
@@ -209,7 +217,7 @@ class FilterTest < Test::Unit::TestCase
controller.assigns["execution_log"] = @execution_log + " and after"
controller.assigns["after_ran"] = true
controller.class.execution_log << " after aroundfilter " if controller.respond_to? :execution_log
end
end
end
class AppendedAroundFilter
@@ -219,12 +227,12 @@ class FilterTest < Test::Unit::TestCase
def after(controller)
controller.class.execution_log << " after appended aroundfilter "
end
end
end
end
class AuditController < ActionController::Base
before_filter(AuditFilter)
def show
render_text "hello"
end
@@ -234,6 +242,14 @@ class FilterTest < Test::Unit::TestCase
around_filter AroundFilter.new
end
class BeforeAfterClassFilterController < PrependingController
begin
filter = AroundFilter.new
before_filter filter
after_filter filter
end
end
class MixedFilterController < PrependingController
cattr_accessor :execution_log
@@ -247,7 +263,7 @@ class FilterTest < Test::Unit::TestCase
after_filter { |c| c.class.execution_log << " after procfilter " }
append_around_filter AppendedAroundFilter.new
end
class MixedSpecializationController < ActionController::Base
class OutOfOrder < StandardError; end
@@ -285,6 +301,101 @@ class FilterTest < Test::Unit::TestCase
end
end
class PrependingBeforeAndAfterController < ActionController::Base
prepend_before_filter :before_all
prepend_after_filter :after_all
before_filter :between_before_all_and_after_all
def before_all
@ran_filter ||= []
@ran_filter << 'before_all'
end
def after_all
@ran_filter ||= []
@ran_filter << 'after_all'
end
def between_before_all_and_after_all
@ran_filter ||= []
@ran_filter << 'between_before_all_and_after_all'
end
def show
render :text => 'hello'
end
end
class NonYieldingAroundFilterController < ActionController::Base
before_filter :filter_one
around_filter :non_yielding_filter
before_filter :filter_two
after_filter :filter_three
def index
render :inline => "index"
end
#make sure the controller complains
def rescue_action(e); raise e; end
private
def filter_one
@filters ||= []
@filters << "filter_one"
end
def filter_two
@filters << "filter_two"
end
def non_yielding_filter
@filters << "zomg it didn't yield"
@filter_return_value
end
def filter_three
@filters << "filter_three"
end
end
def test_non_yielding_around_filters_not_returning_false_do_not_raise
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", true
assert_nothing_raised do
test_process(controller, "index")
end
end
def test_non_yielding_around_filters_returning_false_do_not_raise
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", false
assert_nothing_raised do
test_process(controller, "index")
end
end
def test_after_filters_are_not_run_if_around_filter_returns_false
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", false
test_process(controller, "index")
assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters']
end
def test_after_filters_are_not_run_if_around_filter_does_not_yield
controller = NonYieldingAroundFilterController.new
controller.instance_variable_set "@filter_return_value", true
test_process(controller, "index")
assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters']
end
def test_empty_filter_chain
assert_equal 0, EmptyFilterChainController.filter_chain.size
assert test_process(EmptyFilterChainController).template.assigns['action_executed']
end
def test_added_filter_to_inheritance_graph
assert_equal [ :ensure_login ], TestController.before_filters
end
@@ -292,11 +403,11 @@ class FilterTest < Test::Unit::TestCase
def test_base_class_in_isolation
assert_equal [ ], ActionController::Base.before_filters
end
def test_prepending_filter
assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters
end
def test_running_filters
assert_equal %w( wonderful_life ensure_login ), test_process(PrependingController).template.assigns["ran_filter"]
end
@@ -304,11 +415,11 @@ class FilterTest < Test::Unit::TestCase
def test_running_filters_with_proc
assert test_process(ProcController).template.assigns["ran_proc_filter"]
end
def test_running_filters_with_implicit_proc
assert test_process(ImplicitProcController).template.assigns["ran_proc_filter"]
end
def test_running_filters_with_class
assert test_process(AuditController).template.assigns["was_audited"]
end
@@ -319,7 +430,7 @@ class FilterTest < Test::Unit::TestCase
assert response.template.assigns["ran_class_filter"]
assert response.template.assigns["ran_proc_filter1"]
assert response.template.assigns["ran_proc_filter2"]
response = test_process(AnomolousYetValidConditionController, "show_without_filter")
assert_equal nil, response.template.assigns["ran_filter"]
assert !response.template.assigns["ran_class_filter"]
@@ -373,6 +484,12 @@ class FilterTest < Test::Unit::TestCase
assert controller.template.assigns["after_ran"]
end
def test_before_after_class_filter
controller = test_process(BeforeAfterClassFilterController)
assert controller.template.assigns["before_ran"]
assert controller.template.assigns["after_ran"]
end
def test_having_properties_in_around_filter
controller = test_process(AroundFilterController)
assert_equal "before and after", controller.template.assigns["execution_log"]
@@ -381,10 +498,10 @@ class FilterTest < Test::Unit::TestCase
def test_prepending_and_appending_around_filter
controller = test_process(MixedFilterController)
assert_equal " before aroundfilter before procfilter before appended aroundfilter " +
" after appended aroundfilter after aroundfilter after procfilter ",
" after appended aroundfilter after aroundfilter after procfilter ",
MixedFilterController.execution_log
end
def test_rendering_breaks_filtering_chain
response = test_process(RenderingController)
assert_equal "something else", response.body
@@ -412,6 +529,12 @@ class FilterTest < Test::Unit::TestCase
end
end
def test_running_prepended_before_and_after_filter
assert_equal 3, PrependingBeforeAndAfterController.filter_chain.length
response = test_process(PrependingBeforeAndAfterController)
assert_equal %w( before_all between_before_all_and_after_all after_all ), response.template.assigns["ran_filter"]
end
def test_conditional_skipping_of_filters
assert_nil test_process(ConditionalSkippingController, "login").template.assigns["ran_filter"]
assert_equal %w( ensure_login find_user ), test_process(ConditionalSkippingController, "change_password").template.assigns["ran_filter"]

View File

@@ -11,7 +11,7 @@ require 'stubba'
module ActionController
module Integration
class Session
def process
def process(*args)
end
def generic_url_rewriter
@@ -56,8 +56,7 @@ class SessionTest < Test::Unit::TestCase
@session.expects(:get).with(path,args)
redirects = [true, true, false]
@session.stubs(:redirect?).returns(lambda { redirects.shift })
@session.stubs(:redirect?).returns(true).then.returns(true).then.returns(false)
@session.expects(:follow_redirect!).times(2)
@session.stubs(:status).returns(200)
@@ -69,8 +68,7 @@ class SessionTest < Test::Unit::TestCase
@session.expects(:post).with(path,args)
redirects = [true, true, false]
@session.stubs(:redirect?).returns(lambda { redirects.shift })
@session.stubs(:redirect?).returns(true).then.returns(true).then.returns(false)
@session.expects(:follow_redirect!).times(2)
@session.stubs(:status).returns(200)
@@ -134,15 +132,102 @@ class SessionTest < Test::Unit::TestCase
@session.head(path,params,headers)
end
def test_xml_http_request
def test_xml_http_request_deprecated_call
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
"X-Requested-With" => "XMLHttpRequest",
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
)
@session.expects(:post).with(path,params,headers_after_xhr)
@session.xml_http_request(path,params,headers)
@session.expects(:process).with(:post,path,params,headers_after_xhr)
assert_deprecated { @session.xml_http_request(path,params,headers) }
end
def test_xml_http_request_get
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
"X-Requested-With" => "XMLHttpRequest",
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
)
@session.expects(:process).with(:get,path,params,headers_after_xhr)
@session.xml_http_request(:get,path,params,headers)
end
def test_xml_http_request_post
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
"X-Requested-With" => "XMLHttpRequest",
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
)
@session.expects(:process).with(:post,path,params,headers_after_xhr)
@session.xml_http_request(:post,path,params,headers)
end
def test_xml_http_request_put
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
"X-Requested-With" => "XMLHttpRequest",
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
)
@session.expects(:process).with(:put,path,params,headers_after_xhr)
@session.xml_http_request(:put,path,params,headers)
end
def test_xml_http_request_delete
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
"X-Requested-With" => "XMLHttpRequest",
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
)
@session.expects(:process).with(:delete,path,params,headers_after_xhr)
@session.xml_http_request(:delete,path,params,headers)
end
def test_xml_http_request_head
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
"X-Requested-With" => "XMLHttpRequest",
"Accept" => "text/javascript, text/html, application/xml, text/xml, */*"
)
@session.expects(:process).with(:head,path,params,headers_after_xhr)
@session.xml_http_request(:head,path,params,headers)
end
end
class IntegrationTestTest < Test::Unit::TestCase
def setup
@test = ::ActionController::IntegrationTest.new(:default_test)
@test.class.stubs(:fixture_table_names).returns([])
@session = @test.open_session
end
def test_opens_new_session
@test.class.expects(:fixture_table_names).times(2).returns(['foo'])
session1 = @test.open_session { |sess| }
session2 = @test.open_session # implicit session
assert_equal ::ActionController::Integration::Session, session1.class
assert_equal ::ActionController::Integration::Session, session2.class
assert_not_equal session1, session2
end
end
# Tests that integration tests don't call Controller test methods for processing.
# Integration tests have their own setup and teardown.
class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest
def self.fixture_table_names
[]
end
def test_integration_methods_called
%w( get post head put delete ).each do |verb|
assert_nothing_raised("'#{verb}' should use integration test methods") { send(verb, '/') }
end
end
end
# TODO

View File

@@ -75,6 +75,8 @@ end
class ExemptFromLayoutTest < Test::Unit::TestCase
def setup
@controller = LayoutTest.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_rjs_exempt_from_layout
@@ -103,6 +105,15 @@ class ExemptFromLayoutTest < Test::Unit::TestCase
ActionController::Base.exempt_from_layout /\.rdoc/
assert @controller.send(:template_exempt_from_layout?, 'test.rdoc')
end
def test_rhtml_exempt_from_layout_status_should_prevent_layout_render
ActionController::Base.exempt_from_layout :rhtml
assert @controller.send(:template_exempt_from_layout?, 'test.rhtml')
get :hello
assert_equal 'hello.rhtml', @response.body
ActionController::Base.exempt_from_layout.delete(/\.rhtml$/)
end
end

View File

@@ -20,6 +20,13 @@ class RespondToController < ActionController::Base
end
end
def json_or_yaml
respond_to do |type|
type.json { render :text => "JSON" }
type.yaml { render :text => "YAML" }
end
end
def html_or_xml
respond_to do |type|
type.html { render :text => "HTML" }
@@ -164,6 +171,27 @@ class MimeControllerTest < Test::Unit::TestCase
assert_response 406
end
def test_json_or_yaml
get :json_or_yaml
assert_equal 'JSON', @response.body
get :json_or_yaml, :format => 'json'
assert_equal 'JSON', @response.body
get :json_or_yaml, :format => 'yaml'
assert_equal 'YAML', @response.body
{ 'YAML' => %w(text/yaml),
'JSON' => %w(application/json text/x-json)
}.each do |body, content_types|
content_types.each do |content_type|
@request.env['HTTP_ACCEPT'] = content_type
get :json_or_yaml
assert_equal body, @response.body
end
end
end
def test_js_or_anything
@request.env["HTTP_ACCEPT"] = "text/javascript, */*"
get :js_or_html

View File

@@ -160,6 +160,33 @@ class NewRenderTestController < ActionController::Base
@customers = [ Customer.new("david"), Customer.new("mary") ]
render :text => "How's there? #{render_to_string("test/list")}"
end
def render_to_string_with_assigns
@before = "i'm before the render"
render_to_string :text => "foo"
@after = "i'm after the render"
render :action => "test/hello_world"
end
def render_to_string_with_partial
@partial_only = render_to_string :partial => "partial_only"
@partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }
render :action => "test/hello_world"
end
def render_to_string_with_exception
render_to_string :file => "exception that will not be caught - this will certainly not work", :use_full_path => true
end
def render_to_string_with_caught_exception
@before = "i'm before the render"
begin
render_to_string :file => "exception that will be caught- hope my future instance vars still work!", :use_full_path => true
rescue
end
@after = "i'm after the render"
render :action => "test/hello_world"
end
def accessing_params_in_template
render :inline => "Hello: <%= params[:name] %>"
@@ -187,6 +214,11 @@ class NewRenderTestController < ActionController::Base
render :text => "hello"
redirect_to :action => "double_render"
end
def render_to_string_and_render
@stuff = render_to_string :text => "here is some cached stuff"
render :text => "Hi web users! #{@stuff}"
end
def rendering_with_conflicting_local_vars
@name = "David"
@@ -523,6 +555,28 @@ EOS
assert_not_deprecated { get :hello_in_a_string }
assert_equal "How's there? goodbyeHello: davidHello: marygoodbye\n", @response.body
end
def test_render_to_string_doesnt_break_assigns
get :render_to_string_with_assigns
assert_equal "i'm before the render", assigns(:before)
assert_equal "i'm after the render", assigns(:after)
end
def test_render_to_string_partial
get :render_to_string_with_partial
assert_equal "only partial", assigns(:partial_only)
assert_equal "Hello: david", assigns(:partial_with_locals)
end
def test_bad_render_to_string_still_throws_exception
assert_raises(ActionController::MissingTemplate) { get :render_to_string_with_exception }
end
def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns
assert_nothing_raised { get :render_to_string_with_caught_exception }
assert_equal "i'm before the render", assigns(:before)
assert_equal "i'm after the render", assigns(:after)
end
def test_nested_rendering
get :hello_world
@@ -555,6 +609,12 @@ EOS
def test_render_and_redirect
assert_raises(ActionController::DoubleRenderError) { get :render_and_redirect }
end
# specify the one exception to double render rule - render_to_string followed by render
def test_render_to_string_and_render
get :render_to_string_and_render
assert_equal("Hi web users! here is some cached stuff", @response.body)
end
def test_rendering_with_conflicting_local_vars
get :rendering_with_conflicting_local_vars
@@ -640,24 +700,29 @@ EOS
get :head_with_location_header
assert @response.body.blank?
assert_equal "/foo", @response.headers["Location"]
assert_response :ok
end
def test_head_with_custom_header
get :head_with_custom_header
assert @response.body.blank?
assert_equal "something", @response.headers["X-Custom-Header"]
assert_response :ok
end
def test_head_with_symbolic_status
get :head_with_symbolic_status, :status => "ok"
assert_equal "200 OK", @response.headers["Status"]
assert_response :ok
get :head_with_symbolic_status, :status => "not_found"
assert_equal "404 Not Found", @response.headers["Status"]
assert_response :not_found
ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code|
get :head_with_symbolic_status, :status => status.to_s
assert_equal code, @response.response_code
assert_response status
end
end
@@ -672,6 +737,7 @@ EOS
get :head_with_string_status, :status => "404 Eat Dirt"
assert_equal 404, @response.response_code
assert_equal "Eat Dirt", @response.message
assert_response :not_found
end
def test_head_with_status_code_first
@@ -679,5 +745,6 @@ EOS
assert_equal 403, @response.response_code
assert_equal "Forbidden", @response.message
assert_equal "something", @response.headers["X-Custom-Header"]
assert_response :forbidden
end
end

View File

@@ -39,6 +39,18 @@ class TestController < ActionController::Base
render_text "hello world"
end
def render_json_hello_world
render_json({:hello => 'world'}.to_json)
end
def render_json_hello_world_with_callback
render_json({:hello => 'world'}.to_json, 'alert')
end
def render_symbol_json
render :json => {:hello => 'world'}.to_json
end
def render_custom_code
render_text "hello world", "404 Moved"
end
@@ -117,6 +129,7 @@ class TestController < ActionController::Base
case action_name
when "layout_test": "layouts/standard"
when "builder_layout_test": "layouts/builder"
when "render_symbol_json": "layouts/standard" # to make sure layouts don't interfere
end
end
end
@@ -164,6 +177,24 @@ class RenderTest < Test::Unit::TestCase
assert_equal "hello world", @response.body
end
def test_do_with_render_json
get :render_json_hello_world
assert_equal '{hello: "world"}', @response.body
assert_equal 'application/json', @response.content_type
end
def test_do_with_render_json_with_callback
get :render_json_hello_world_with_callback
assert_equal 'alert({hello: "world"})', @response.body
assert_equal 'application/json', @response.content_type
end
def test_do_with_render_symbol_json
get :render_symbol_json
assert_equal '{hello: "world"}', @response.body
assert_equal 'application/json', @response.content_type
end
def test_do_with_render_custom_code
get :render_custom_code
assert_response 404

View File

@@ -174,48 +174,54 @@ class RequestTest < Test::Unit::TestCase
assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
assert_equal "/path/of/some/uri", @request.path
@request.set_REQUEST_URI nil
@request.relative_url_root = nil
@request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1"
@request.env['SCRIPT_NAME'] = "/path/dispatch.rb"
assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
assert_equal "/of/some/uri", @request.path
@request.set_REQUEST_URI nil
@request.relative_url_root = nil
@request.env['PATH_INFO'] = "/path/of/some/uri"
@request.env['SCRIPT_NAME'] = nil
assert_equal "/path/of/some/uri", @request.request_uri
assert_equal "/path/of/some/uri", @request.path
@request.set_REQUEST_URI nil
@request.relative_url_root = nil
@request.env['PATH_INFO'] = "/"
assert_equal "/", @request.request_uri
assert_equal "/", @request.path
@request.set_REQUEST_URI nil
@request.relative_url_root = nil
@request.env['PATH_INFO'] = "/?m=b"
assert_equal "/?m=b", @request.request_uri
assert_equal "/", @request.path
@request.set_REQUEST_URI nil
@request.relative_url_root = nil
@request.env['PATH_INFO'] = "/"
@request.env['SCRIPT_NAME'] = "/dispatch.cgi"
assert_equal "/", @request.request_uri
assert_equal "/", @request.path
assert_equal "/", @request.path
@request.set_REQUEST_URI nil
@request.relative_url_root = nil
@request.env['PATH_INFO'] = "/hieraki/"
@request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
assert_equal "/hieraki/", @request.request_uri
assert_equal "/", @request.path
assert_equal "/", @request.path
@request.set_REQUEST_URI '/hieraki/dispatch.cgi'
@request.relative_url_root = '/hieraki'
assert_equal "/dispatch.cgi", @request.path
assert_equal "/dispatch.cgi", @request.path
@request.relative_url_root = nil
@request.set_REQUEST_URI '/hieraki/dispatch.cgi'
@request.relative_url_root = '/foo'
assert_equal "/hieraki/dispatch.cgi", @request.path
assert_equal "/hieraki/dispatch.cgi", @request.path
@request.relative_url_root = nil
# This test ensures that Rails uses REQUEST_URI over PATH_INFO
@@ -226,7 +232,7 @@ class RequestTest < Test::Unit::TestCase
assert_equal "/some/path", @request.request_uri
assert_equal "/some/path", @request.path
end
def test_host_with_port
@request.host = "rubyonrails.org"
@@ -274,7 +280,7 @@ class RequestTest < Test::Unit::TestCase
end
def test_symbolized_request_methods
[:head, :get, :post, :put, :delete].each do |method|
[:get, :post, :put, :delete].each do |method|
set_request_method_to method
assert_equal method, @request.method
end
@@ -282,7 +288,7 @@ class RequestTest < Test::Unit::TestCase
def test_allow_method_hacking_on_post
set_request_method_to :post
[:head, :get, :put, :delete].each do |method|
[:get, :put, :delete].each do |method|
@request.instance_eval { @parameters = { :_method => method } ; @request_method = nil }
assert_equal method, @request.method
end
@@ -290,11 +296,18 @@ class RequestTest < Test::Unit::TestCase
def test_restrict_method_hacking
@request.instance_eval { @parameters = { :_method => 'put' } }
[:head, :get, :put, :delete].each do |method|
[:get, :put, :delete].each do |method|
set_request_method_to method
assert_equal method, @request.method
end
end
def test_head_masquarading_as_get
set_request_method_to :head
assert_equal :get, @request.method
assert @request.get?
assert @request.head?
end
protected
def set_request_method_to(method)

View File

@@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../abstract_unit'
class ResourcesController < ActionController::Base
def index() render :nothing => true end
alias_method :show, :index
def rescue_action(e) raise e end
end
@@ -9,6 +10,9 @@ class ThreadsController < ResourcesController; end
class MessagesController < ResourcesController; end
class CommentsController < ResourcesController; end
class AccountController < ResourcesController; end
class AdminController < ResourcesController; end
class ProductsController < ResourcesController; end
class ResourcesTest < Test::Unit::TestCase
def test_should_arrange_actions
@@ -24,6 +28,23 @@ class ResourcesTest < Test::Unit::TestCase
assert_resource_methods [:new, :preview, :draft], resource, :new, :get
end
def test_should_resource_controller_name_equal_resource_name_by_default
resource = ActionController::Resources::Resource.new(:messages, {})
assert_equal 'messages', resource.controller
end
def test_should_resource_controller_name_equal_controller_option
resource = ActionController::Resources::Resource.new(:messages, :controller => 'posts')
assert_equal 'posts', resource.controller
end
def test_should_all_singleton_paths_be_the_same
[ :path, :nesting_path_prefix, :member_path ].each do |method|
resource = ActionController::Resources::SingletonResource.new(:messages, :path_prefix => 'admin')
assert_equal 'admin/messages', resource.send(method)
end
end
def test_default_restful_routes
with_restful_routing :messages do
assert_simply_restful_for :messages
@@ -43,16 +64,22 @@ class ResourcesTest < Test::Unit::TestCase
end
end
def test_multile_with_path_prefix
def test_multiple_with_path_prefix
with_restful_routing :messages, :comments, :path_prefix => '/thread/:thread_id' do
assert_simply_restful_for :messages, :path_prefix => 'thread/5/', :options => { :thread_id => '5' }
assert_simply_restful_for :comments, :path_prefix => 'thread/5/', :options => { :thread_id => '5' }
end
end
def test_with_name_prefix
with_restful_routing :messages, :name_prefix => 'post_' do
assert_simply_restful_for :messages, :name_prefix => 'post_'
end
end
def test_with_collection_action
rss_options = {:action => 'rss'}
rss_path = "/messages;rss"
rss_path = "/messages/rss"
actions = { 'a' => :put, 'b' => :post, 'c' => :delete }
with_restful_routing :messages, :collection => { :rss => :get }.merge(actions) do
@@ -60,14 +87,14 @@ class ResourcesTest < Test::Unit::TestCase
assert_routing rss_path, options.merge(rss_options)
actions.each do |action, method|
assert_recognizes(options.merge(:action => action), :path => "/messages;#{action}", :method => method)
assert_recognizes(options.merge(:action => action), :path => "/messages/#{action}", :method => method)
end
end
assert_restful_named_routes_for :messages do |options|
assert_named_route rss_path, :rss_messages_path, rss_options
actions.keys.each do |action|
assert_named_route "/messages;#{action}", "#{action}_messages_path", :action => action
assert_named_route "/messages/#{action}", "#{action}_messages_path", :action => action
end
end
end
@@ -77,7 +104,7 @@ class ResourcesTest < Test::Unit::TestCase
[:put, :post].each do |method|
with_restful_routing :messages, :member => { :mark => method } do
mark_options = {:action => 'mark', :id => '1'}
mark_path = "/messages/1;mark"
mark_path = "/messages/1/mark"
assert_restful_routes_for :messages do |options|
assert_recognizes(options.merge(mark_options), :path => mark_path, :method => method)
end
@@ -94,7 +121,7 @@ class ResourcesTest < Test::Unit::TestCase
with_restful_routing :messages, :member => { :mark => method, :unmark => method } do
%w(mark unmark).each do |action|
action_options = {:action => action, :id => '1'}
action_path = "/messages/1;#{action}"
action_path = "/messages/1/#{action}"
assert_restful_routes_for :messages do |options|
assert_recognizes(options.merge(action_options), :path => action_path, :method => method)
end
@@ -107,11 +134,10 @@ class ResourcesTest < Test::Unit::TestCase
end
end
def test_with_new_action
with_restful_routing :messages, :new => { :preview => :post } do
preview_options = {:action => 'preview'}
preview_path = "/messages/new;preview"
preview_path = "/messages/new/preview"
assert_restful_routes_for :messages do |options|
assert_recognizes(options.merge(preview_options), :path => preview_path, :method => :post)
end
@@ -153,9 +179,11 @@ class ResourcesTest < Test::Unit::TestCase
assert_simply_restful_for :threads
assert_simply_restful_for :messages,
:path_prefix => 'threads/1/',
:name_prefix => 'thread_',
:options => { :thread_id => '1' }
assert_simply_restful_for :comments,
:path_prefix => 'threads/1/messages/2/',
:name_prefix => 'thread_message_',
:options => { :thread_id => '1', :message_id => '2' }
end
end
@@ -172,6 +200,296 @@ class ResourcesTest < Test::Unit::TestCase
end
end
def test_should_create_singleton_resource_routes
with_singleton_resources :account do
assert_singleton_restful_for :account
end
end
def test_should_create_multiple_singleton_resource_routes
with_singleton_resources :account, :admin do
assert_singleton_restful_for :account
assert_singleton_restful_for :admin
end
end
def test_should_create_nested_singleton_resource_routes
with_routing do |set|
set.draw do |map|
map.resource :admin do |admin|
admin.resource :account
end
end
assert_singleton_restful_for :admin
assert_singleton_restful_for :account, :path_prefix => 'admin/', :name_prefix => 'admin_'
end
end
def test_singleton_resource_with_member_action
[:put, :post].each do |method|
with_singleton_resources :account, :member => { :reset => method } do
reset_options = {:action => 'reset'}
reset_path = "/account/reset"
assert_singleton_routes_for :account do |options|
assert_recognizes(options.merge(reset_options), :path => reset_path, :method => method)
end
assert_singleton_named_routes_for :account do |options|
assert_named_route reset_path, :reset_account_path, reset_options
end
end
end
end
def test_singleton_resource_with_two_member_actions_with_same_method
[:put, :post].each do |method|
with_singleton_resources :account, :member => { :reset => method, :disable => method } do
%w(reset disable).each do |action|
action_options = {:action => action}
action_path = "/account/#{action}"
assert_singleton_routes_for :account do |options|
assert_recognizes(options.merge(action_options), :path => action_path, :method => method)
end
assert_singleton_named_routes_for :account do |options|
assert_named_route action_path, "#{action}_account_path".to_sym, action_options
end
end
end
end
end
def test_should_nest_resources_in_singleton_resource
with_routing do |set|
set.draw do |map|
map.resource :account do |account|
account.resources :messages
end
end
assert_singleton_restful_for :account
assert_simply_restful_for :messages, :path_prefix => 'account/', :name_prefix => 'account_'
end
end
def test_should_nest_resources_in_singleton_resource_with_path_prefix
with_routing do |set|
set.draw do |map|
map.resource(:account, :path_prefix => ':site_id') do |account|
account.resources :messages
end
end
assert_singleton_restful_for :account, :path_prefix => '7/', :options => { :site_id => '7' }
assert_simply_restful_for :messages, :path_prefix => '7/account/', :name_prefix => 'account_', :options => { :site_id => '7' }
end
end
def test_should_nest_singleton_resource_in_resources
with_routing do |set|
set.draw do |map|
map.resources :threads do |thread|
thread.resource :admin
end
end
assert_simply_restful_for :threads
assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :name_prefix => 'thread_', :options => { :thread_id => '5' }
end
end
def test_should_not_allow_delete_or_put_on_collection_path
controller_name = :messages
with_restful_routing controller_name do
options = { :controller => controller_name.to_s }
collection_path = "/#{controller_name}"
assert_raises(ActionController::RoutingError) do
assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put)
end
assert_raises(ActionController::RoutingError) do
assert_recognizes(options.merge(:action => 'destroy'), :path => collection_path, :method => :delete)
end
end
end
def test_resource_action_separator
with_routing do |set|
set.draw do |map|
map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id'
map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin'
end
action_separator = ActionController::Base.resource_action_separator
assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' }
assert_named_route "/threads/1/messages#{action_separator}search", "search_thread_messages_path", {}
assert_named_route "/threads/1/messages/new", "new_thread_message_path", {}
assert_named_route "/threads/1/messages/new#{action_separator}preview", "preview_new_thread_message_path", {}
assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/'
assert_named_route "/admin/account#{action_separator}login", "login_admin_account_path", {}
assert_named_route "/admin/account/new", "new_admin_account_path", {}
assert_named_route "/admin/account/new#{action_separator}preview", "preview_new_admin_account_path", {}
end
end
def test_new_style_named_routes_for_resource
with_routing do |set|
set.draw do |map|
map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id'
end
assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' }
assert_named_route "/threads/1/messages/search", "search_thread_messages_path", {}
assert_named_route "/threads/1/messages/new", "new_thread_message_path", {}
assert_named_route "/threads/1/messages/new/preview", "preview_new_thread_message_path", {}
end
end
def test_new_style_named_routes_for_singleton_resource
with_routing do |set|
set.draw do |map|
map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin'
end
assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/'
assert_named_route "/admin/account/login", "login_admin_account_path", {}
assert_named_route "/admin/account/new", "new_admin_account_path", {}
assert_named_route "/admin/account/new/preview", "preview_new_admin_account_path", {}
end
end
def test_should_add_deprecated_named_routes_for_resource
with_routing do |set|
set.draw do |map|
map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id'
end
assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' }
assert_deprecated do
assert_named_route "/threads/1/messages/search", "thread_search_messages_path", {}
assert_named_route "/threads/1/messages/new", "thread_new_message_path", {}
assert_named_route "/threads/1/messages/new/preview", "thread_preview_new_message_path", {}
end
end
end
def test_should_add_deprecated_named_routes_for_singleton_resource
with_routing do |set|
set.draw do |map|
map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin'
end
assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/'
assert_deprecated do
assert_named_route "/admin/account/login", "admin_login_account_path", {}
assert_named_route "/admin/account/new", "admin_new_account_path", {}
assert_named_route "/admin/account/new/preview", "admin_preview_new_account_path", {}
end
end
end
def test_should_add_deprecated_named_routes_for_nested_resources
with_routing do |set|
set.draw do |map|
map.resources :threads do |map|
map.resources :messages do |map|
map.resources :comments
end
end
end
assert_simply_restful_for :threads
assert_simply_restful_for :messages,
:path_prefix => 'threads/1/',
:name_prefix => 'thread_',
:options => { :thread_id => '1' }
assert_simply_restful_for :comments,
:path_prefix => 'threads/1/messages/2/',
:name_prefix => 'thread_message_',
:options => { :thread_id => '1', :message_id => '2' }
assert_deprecated do
assert_named_route "/threads/1/messages", "messages_path", {}
assert_named_route "/threads/1/messages/1", "message_path", {:thread_id => '1', :id => '1'}
assert_named_route "/threads/1/messages/new", "new_message_path", {:thread_id => '1'}
assert_named_route "/threads/1/messages/1/edit", "edit_message_path", {:thread_id => '1', :id => '1'}
end
end
end
def test_should_add_deprecated_named_routes_for_nested_singleton_resources
with_routing do |set|
set.draw do |map|
map.resource :admin do |admin|
admin.resource :account
end
end
assert_singleton_restful_for :admin
assert_singleton_restful_for :account, :path_prefix => 'admin/', :name_prefix => 'admin_'
assert_deprecated do
assert_named_route "/admin/account", "account_path", {}
assert_named_route "/admin/account/new", "new_account_path", {}
assert_named_route "/admin/account/edit", "edit_account_path", {}
end
end
end
def test_should_add_deprecated_named_routes_for_nested_resources_in_singleton_resource
with_routing do |set|
set.draw do |map|
map.resource :account do |account|
account.resources :messages
end
end
assert_singleton_restful_for :account
assert_simply_restful_for :messages, :path_prefix => 'account/', :name_prefix => 'account_'
assert_deprecated do
assert_named_route "/account/messages", "messages_path", {}
assert_named_route "/account/messages/1", "message_path", {:id => '1'}
assert_named_route "/account/messages/new", "new_message_path", {}
assert_named_route "/account/messages/1/edit", "edit_message_path", {:id => '1'}
end
end
end
def test_should_add_deprecated_named_routes_for_nested_singleton_resource_in_resources
with_routing do |set|
set.draw do |map|
map.resources :threads do |thread|
thread.resource :admin
end
end
assert_simply_restful_for :threads
assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :name_prefix => 'thread_', :options => { :thread_id => '5' }
assert_deprecated do
assert_named_route "/threads/5/admin", "admin_path", {}
assert_named_route "/threads/5/admin/new", "new_admin_path", {}
assert_named_route "/threads/5/admin/edit", "edit_admin_path", {}
end
end
end
def test_should_add_deprecated_formatted_routes
with_routing do |set|
set.draw do |map|
map.resources :products, :collection => { :specials => :get }, :member => { :thumbnail => :get }
map.resource :account, :member => { :icon => :get }
end
assert_restful_routes_for :products do |options|
assert_recognizes options.merge({ :action => 'specials', :format => 'xml' }), :path => '/products.xml;specials', :method => :get
assert_recognizes options.merge({ :action => 'thumbnail', :format => 'jpg', :id => '1' }), :path => '/products/1.jpg;thumbnail', :method => :get
end
assert_singleton_restful_for :account do |options|
assert_recognizes options.merge({ :action => 'icon', :format => 'jpg' }), :path => '/account.jpg;icon', :method => :get
end
end
end
protected
def with_restful_routing(*args)
with_routing do |set|
@@ -180,39 +498,59 @@ class ResourcesTest < Test::Unit::TestCase
end
end
def with_singleton_resources(*args)
with_routing do |set|
set.draw { |map| map.resource(*args) }
yield
end
end
# runs assert_restful_routes_for and assert_restful_named_routes for on the controller_name and options, without passing a block.
def assert_simply_restful_for(controller_name, options = {})
assert_restful_routes_for controller_name, options
assert_restful_named_routes_for controller_name, options
end
def assert_singleton_restful_for(singleton_name, options = {})
assert_singleton_routes_for singleton_name, options
assert_singleton_named_routes_for singleton_name, options
end
def assert_restful_routes_for(controller_name, options = {})
(options[:options] ||= {})[:controller] = controller_name.to_s
collection_path = "/#{options[:path_prefix]}#{controller_name}"
member_path = "#{collection_path}/1"
new_path = "#{collection_path}/new"
collection_path = "/#{options[:path_prefix]}#{controller_name}"
member_path = "#{collection_path}/1"
new_path = "#{collection_path}/new"
edit_member_path = "#{member_path}/edit"
formatted_edit_member_path = "#{member_path}/edit.xml"
with_options(options[:options]) do |controller|
controller.assert_routing collection_path, :action => 'index'
controller.assert_routing "#{collection_path}.xml" , :action => 'index', :format => 'xml'
controller.assert_routing new_path, :action => 'new'
controller.assert_routing member_path, :action => 'show', :id => '1'
controller.assert_routing "#{member_path};edit", :action => 'edit', :id => '1'
controller.assert_routing edit_member_path, :action => 'edit', :id => '1'
controller.assert_routing "#{collection_path}.xml", :action => 'index', :format => 'xml'
controller.assert_routing "#{new_path}.xml", :action => 'new', :format => 'xml'
controller.assert_routing "#{member_path}.xml", :action => 'show', :id => '1', :format => 'xml'
controller.assert_routing formatted_edit_member_path, :action => 'edit', :id => '1', :format => 'xml'
end
assert_recognizes(
options[:options].merge(:action => 'create'),
:path => collection_path, :method => :post)
assert_recognizes(options[:options].merge(:action => 'index'), :path => collection_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'new'), :path => new_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'create'), :path => collection_path, :method => :post)
assert_recognizes(options[:options].merge(:action => 'show', :id => '1'), :path => member_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'edit', :id => '1'), :path => edit_member_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'update', :id => '1'), :path => member_path, :method => :put)
assert_recognizes(options[:options].merge(:action => 'destroy', :id => '1'), :path => member_path, :method => :delete)
assert_recognizes(
options[:options].merge(:action => 'update', :id => '1'),
:path => member_path, :method => :put)
assert_recognizes(
options[:options].merge(:action => 'destroy', :id => '1'),
:path => member_path, :method => :delete)
assert_recognizes(options[:options].merge(:action => 'index', :format => 'xml'), :path => "#{collection_path}.xml", :method => :get)
assert_recognizes(options[:options].merge(:action => 'new', :format => 'xml'), :path => "#{new_path}.xml", :method => :get)
assert_recognizes(options[:options].merge(:action => 'create', :format => 'xml'), :path => "#{collection_path}.xml", :method => :post)
assert_recognizes(options[:options].merge(:action => 'show', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :get)
assert_recognizes(options[:options].merge(:action => 'edit', :id => '1', :format => 'xml'), :path => formatted_edit_member_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'update', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :put)
assert_recognizes(options[:options].merge(:action => 'destroy', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :delete)
yield options[:options] if block_given?
end
@@ -232,16 +570,72 @@ class ResourcesTest < Test::Unit::TestCase
options[:options].delete :action
full_prefix = "/#{options[:path_prefix]}#{controller_name}"
name_prefix = options[:name_prefix]
assert_named_route "#{full_prefix}", "#{controller_name}_path", options[:options]
assert_named_route "#{full_prefix}.xml", "formatted_#{controller_name}_path", options[:options].merge(:format => 'xml')
assert_named_route "#{full_prefix}/new", "new_#{singular_name}_path", options[:options]
assert_named_route "#{full_prefix}/1", "#{singular_name}_path", options[:options].merge(:id => '1')
assert_named_route "#{full_prefix}/1;edit", "edit_#{singular_name}_path", options[:options].merge(:id => '1')
assert_named_route "#{full_prefix}/1.xml", "formatted_#{singular_name}_path", options[:options].merge(:format => 'xml', :id => '1')
assert_named_route "#{full_prefix}", "#{name_prefix}#{controller_name}_path", options[:options]
assert_named_route "#{full_prefix}/new", "new_#{name_prefix}#{singular_name}_path", options[:options]
assert_named_route "#{full_prefix}/1", "#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1')
assert_named_route "#{full_prefix}/1/edit", "edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1')
assert_named_route "#{full_prefix}.xml", "formatted_#{name_prefix}#{controller_name}_path", options[:options].merge( :format => 'xml')
assert_named_route "#{full_prefix}/new.xml", "formatted_new_#{name_prefix}#{singular_name}_path", options[:options].merge( :format => 'xml')
assert_named_route "#{full_prefix}/1.xml", "formatted_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml')
assert_named_route "#{full_prefix}/1/edit.xml", "formatted_edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml')
yield options[:options] if block_given?
end
def assert_singleton_routes_for(singleton_name, options = {})
(options[:options] ||= {})[:controller] ||= singleton_name.to_s
full_path = "/#{options[:path_prefix]}#{singleton_name}"
new_path = "#{full_path}/new"
edit_path = "#{full_path}/edit"
formatted_edit_path = "#{full_path}/edit.xml"
with_options options[:options] do |controller|
controller.assert_routing full_path, :action => 'show'
controller.assert_routing new_path, :action => 'new'
controller.assert_routing edit_path, :action => 'edit'
controller.assert_routing "#{full_path}.xml", :action => 'show', :format => 'xml'
controller.assert_routing "#{new_path}.xml", :action => 'new', :format => 'xml'
controller.assert_routing formatted_edit_path, :action => 'edit', :format => 'xml'
end
assert_recognizes(options[:options].merge(:action => 'show'), :path => full_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'new'), :path => new_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'edit'), :path => edit_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'create'), :path => full_path, :method => :post)
assert_recognizes(options[:options].merge(:action => 'update'), :path => full_path, :method => :put)
assert_recognizes(options[:options].merge(:action => 'destroy'), :path => full_path, :method => :delete)
assert_recognizes(options[:options].merge(:action => 'show', :format => 'xml'), :path => "#{full_path}.xml", :method => :get)
assert_recognizes(options[:options].merge(:action => 'new', :format => 'xml'), :path => "#{new_path}.xml", :method => :get)
assert_recognizes(options[:options].merge(:action => 'edit', :format => 'xml'), :path => formatted_edit_path, :method => :get)
assert_recognizes(options[:options].merge(:action => 'create', :format => 'xml'), :path => "#{full_path}.xml", :method => :post)
assert_recognizes(options[:options].merge(:action => 'update', :format => 'xml'), :path => "#{full_path}.xml", :method => :put)
assert_recognizes(options[:options].merge(:action => 'destroy', :format => 'xml'), :path => "#{full_path}.xml", :method => :delete)
yield options[:options] if block_given?
end
def assert_singleton_named_routes_for(singleton_name, options = {})
(options[:options] ||= {})[:controller] ||= singleton_name.to_s
@controller = "#{options[:options][:controller].camelize}Controller".constantize.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
get :show, options[:options]
options[:options].delete :action
full_path = "/#{options[:path_prefix]}#{singleton_name}"
full_name = "#{options[:name_prefix]}#{singleton_name}"
assert_named_route "#{full_path}", "#{full_name}_path", options[:options]
assert_named_route "#{full_path}/new", "new_#{full_name}_path", options[:options]
assert_named_route "#{full_path}/edit", "edit_#{full_name}_path", options[:options]
assert_named_route "#{full_path}.xml", "formatted_#{full_name}_path", options[:options].merge(:format => 'xml')
assert_named_route "#{full_path}/new.xml", "formatted_new_#{full_name}_path", options[:options].merge(:format => 'xml')
assert_named_route "#{full_path}/edit.xml", "formatted_edit_#{full_name}_path", options[:options].merge(:format => 'xml')
end
def assert_named_route(expected, route, options)
actual = @controller.send(route, options) rescue $!.class.name
assert_equal expected, actual, "Error on route: #{route}(#{options.inspect})"

View File

@@ -236,7 +236,39 @@ class LegacyRouteSetTests < Test::Unit::TestCase
map.connect ':controller/:action/:id'
end
end
def test_should_list_options_diff_when_routing_requirements_dont_match
rs.draw do |map|
map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
end
exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") }
assert_match /^post_url failed to generate/, exception.message
from_match = exception.message.match(/from \{[^\}]+\}/).to_s
assert_match /:bad_param=>"foo"/, from_match
assert_match /:action=>"show"/, from_match
assert_match /:controller=>"post"/, from_match
expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s
assert_no_match /:bad_param=>"foo"/, expected_match
assert_match /:action=>"show"/, expected_match
assert_match /:controller=>"post"/, expected_match
diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s
assert_match /:bad_param=>"foo"/, diff_match
assert_no_match /:action=>"show"/, diff_match
assert_no_match /:controller=>"post"/, diff_match
end
# this specifies the case where your formerly would get a very confusing error message with an empty diff
def test_should_have_better_error_message_when_options_diff_is_empty
rs.draw do |map|
map.content '/content/:query', :controller => 'content', :action => 'show'
end
exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") }
expected_message = "content_url failed to generate from #{{:action=>"show", :controller=>"content"}.inspect} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: [\"content\", :query] - are they all satisifed?"
assert_equal expected_message, exception.message
end
def test_dynamic_path_allowed
rs.draw do |map|
map.connect '*path', :controller => 'content', :action => 'show_file'
@@ -376,7 +408,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase
def test_named_url_with_no_action_specified
rs.draw do |map|
map.root '', :controller => 'content'
map.home '', :controller => 'content'
map.connect ':controller/:action/:id'
end
@@ -384,14 +416,14 @@ class LegacyRouteSetTests < Test::Unit::TestCase
assert_equal '/', rs.generate(:controller => 'content')
x = setup_for_named_route.new
assert_equal({:controller => 'content', :action => 'index', :use_route => :root, :only_path => false},
x.send(:root_url))
assert_equal({:controller => 'content', :action => 'index', :use_route => :home, :only_path => false},
x.send(:home_url))
end
def test_url_generated_when_forgetting_action
[{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash|
rs.draw do |map|
map.root '', hash
map.home '', hash
map.connect ':controller/:action/:id'
end
assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'})
@@ -853,6 +885,12 @@ class RouteTest < Test::Unit::TestCase
{ :controller => "users", :action => "show", :format => "html" },
route.defaults)
end
def test_builder_complains_without_controller
assert_raises(ArgumentError) do
ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index"
end
end
def test_significant_keys_for_default_route
keys = default_route.significant_keys.sort_by {|k| k.to_s }
@@ -908,7 +946,7 @@ class RouteTest < Test::Unit::TestCase
end
def test_expand_array_build_query_string
assert_equal '?x[]=1&x[]=2', order_query_string(@route.build_query_string(:x => [1, 2]))
assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2]))
end
def test_escape_spaces_build_query_string_selected_keys
@@ -1576,6 +1614,18 @@ class RouteSetTest < Test::Unit::TestCase
Object.send(:remove_const, :PeopleController)
end
def test_deprecation_warning_for_root_route
Object.const_set(:PeopleController, Class.new)
set.draw do |map|
assert_deprecated do
map.root('', :controller => "people")
end
end
ensure
Object.send(:remove_const, :PeopleController)
end
def test_generate_with_default_action
set.draw do |map|
map.connect "/people", :controller => "people"
@@ -1667,16 +1717,30 @@ class RouteSetTest < Test::Unit::TestCase
)
end
def test_query_params_will_be_shown_when_recalled
set.draw do |map|
map.connect 'show_post/:parameter', :controller => 'post', :action => 'show'
map.connect ':controller/:action/:id'
end
assert_equal '/post/edit?parameter=1', set.generate(
{:action => 'edit', :parameter => 1},
{:controller => 'post', :action => 'show', :parameter => 1}
)
end
end
class RoutingTest < Test::Unit::TestCase
def test_possible_controllers
true_controller_paths = ActionController::Routing.controller_paths
ActionController::Routing.use_controllers! nil
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures')
silence_warnings do
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures')
end
ActionController::Routing.controller_paths = [
RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib'
]
@@ -1734,4 +1798,4 @@ class RoutingTest < Test::Unit::TestCase
assert_equal %w(vendor\\rails\\railties\\builtin\\rails_info vendor\\rails\\actionpack\\lib app\\controllers app\\helpers app\\models lib .), paths
end
end
end

View File

@@ -63,6 +63,14 @@ class SendFileTest < Test::Unit::TestCase
assert_equal file_data, response.body
end
def test_headers_after_send_shouldnt_include_charset
response = process('data')
assert_equal "application/octet-stream", response.headers["Content-Type"]
response = process('file')
assert_equal "application/octet-stream", response.headers["Content-Type"]
end
# Test that send_file_headers! is setting the correct HTTP headers.
def test_send_file_headers!
options = {

View File

@@ -0,0 +1,92 @@
require File.dirname(__FILE__) + '/../abstract_unit'
class SessionFixationTest < Test::Unit::TestCase
class MockCGI < CGI #:nodoc:
attr_accessor :stdoutput, :env_table
def initialize(env, data = '')
self.env_table = env
self.stdoutput = StringIO.new
super(StringIO.new(data))
end
end
class TestController < ActionController::Base
session :session_key => '_myapp_session_id', :secret => 'secret', :except => :default_session_key
session :cookie_only => false, :only => :allow_session_fixation
def default_session_key
render :text => "default_session_key"
end
def custom_session_key
render :text => "custom_session_key: #{params[:id]}"
end
def allow_session_fixation
render :text => "allow_session_fixation"
end
def rescue_action(e) raise end
end
def setup
@controller = TestController.new
end
def test_should_be_able_to_make_a_successful_request
cgi = mock_cgi_for_request_to(:custom_session_key, :id => 1)
assert_nothing_raised do
@controller.send(:process, mock_request(cgi), ActionController::CgiResponse.new(cgi))
end
assert_equal 'custom_session_key: 1', @controller.response.body
assert_not_nil @controller.session
end
def test_should_catch_session_fixation_attempt
cgi = mock_cgi_for_request_to(:custom_session_key, :_myapp_session_id => 42)
assert_raises ActionController::CgiRequest::SessionFixationAttempt do
@controller.send(:process, mock_request(cgi), ActionController::CgiResponse.new(cgi))
end
assert_nil @controller.session
end
def test_should_not_catch_session_fixation_attempt_when_cookie_only_setting_is_disabled
cgi = mock_cgi_for_request_to(:allow_session_fixation, :_myapp_session_id => 42)
assert_nothing_raised do
@controller.send(:process, mock_request(cgi), ActionController::CgiResponse.new(cgi))
end
assert !@controller.response.body.blank?
assert_not_nil @controller.session
end
def test_should_catch_session_fixation_attempt_with_default_session_key
ActionController::Base.session_store = :p_store # using the default session_key is not possible with cookie store
cgi = mock_cgi_for_request_to(:default_session_key, :_session_id => 42)
assert_raises ActionController::CgiRequest::SessionFixationAttempt do
@controller.send(:process, mock_request(cgi) , ActionController::CgiResponse.new(cgi))
end
assert @controller.response.body.blank?
assert_nil @controller.session
end
private
def mock_cgi_for_request_to(action, params = {})
MockCGI.new({
"REQUEST_METHOD" => "GET",
"QUERY_STRING" => "action=#{action}&#{params.to_query}",
"REQUEST_URI" => "/",
"SERVER_PORT" => "80",
"HTTP_HOST" => "testdomain.com" }, '')
end
def mock_request(cgi)
ActionController::CgiRequest.new(cgi, {})
end
end

View File

@@ -44,6 +44,49 @@ class SessionManagementTest < Test::Unit::TestCase
end
end
class AssociationCachingTestController < ActionController::Base
class ObjectWithAssociationCache
def initialize
@cached_associations = false
end
def fetch_associations
@cached_associations = true
end
def clear_association_cache
@cached_associations = false
end
def has_cached_associations?
@cached_associations
end
end
def show
session[:object] = ObjectWithAssociationCache.new
session[:object].fetch_associations
if session[:object].has_cached_associations?
render :text => "has cached associations"
else
render :text => "does not have cached associations"
end
end
def tell
if session[:object]
if session[:object].has_cached_associations?
render :text => "has cached associations"
else
render :text => "does not have cached associations"
end
else
render :text => "there is no object"
end
end
end
def setup
@request, @response = ActionController::TestRequest.new,
ActionController::TestResponse.new
@@ -91,4 +134,23 @@ class SessionManagementTest < Test::Unit::TestCase
assert_equal CGI::Session::ActiveRecordStore, ActionController::Base.session_store
end
end
def test_process_cleanup_with_session_management_support
@controller = AssociationCachingTestController.new
get :show
assert_equal "has cached associations", @response.body
get :tell
assert_equal "does not have cached associations", @response.body
end
def test_session_is_enabled
@controller = TestController.new
get :show
assert_nothing_raised do
assert_equal false, @controller.session_enabled?
end
get :tell
assert @controller.session_enabled?
end
end

View File

@@ -66,6 +66,11 @@ HTML
redirect_to :controller => 'fail', :id => 5
end
def create
headers['Location'] = 'created resource'
head :created
end
private
def rescue_action(e)
raise e
@@ -81,7 +86,7 @@ HTML
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
ActionController::Routing::Routes.reload
ActionController::Routing.use_controllers! %w(content admin/user)
ActionController::Routing.use_controllers! %w(content admin/user test_test/test)
end
def teardown
@@ -463,6 +468,36 @@ HTML
end
end
def test_redirect_url_only_cares_about_location_header
get :create
assert_response :created
# Redirect url doesn't care that it wasn't a :redirect response.
assert_equal 'created resource', @response.redirect_url
assert_equal @response.redirect_url, redirect_to_url
# Must be a :redirect response.
assert_raise(Test::Unit::AssertionFailedError) do
assert_redirected_to 'created resource'
end
end
def test_request_uri_updates
get :test_params
uri = @request.request_uri
assert_equal @request.env['REQUEST_URI'], uri
get :test_uri
assert_not_equal uri, @request.request_uri
uri = @request.request_uri
assert_equal @request.env['REQUEST_URI'], uri
get :test_uri, :testing => true
assert_not_equal uri, @request.request_uri
uri = @request.request_uri
assert_equal @request.env['REQUEST_URI'], uri
end
protected
def with_foo_routing
with_routing do |set|

View File

@@ -17,15 +17,12 @@ class UrlRewriterTests < Test::Unit::TestCase
assert_match %r(/hi/hi/2$), u
end
private
def split_query_string(str)
[str[0].chr] + str[1..-1].split(/&/).sort
end
def assert_query_equal(q1, q2)
assert_equal(split_query_string(q1), split_query_string(q2))
end
def test_anchor
assert_equal(
'http://test.host/c/a/i#anchor',
@rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => 'anchor')
)
end
end
class UrlWriterTests < Test::Unit::TestCase
@@ -75,10 +72,16 @@ class UrlWriterTests < Test::Unit::TestCase
W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https')
)
end
def test_anchor
assert_equal('/c/a#anchor',
W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => 'anchor')
)
end
def test_named_route
ActionController::Routing::Routes.draw do |map|
map.home '/home/sweet/home/:user'
map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index'
map.connect ':controller/:action/:id'
end
@@ -96,7 +99,7 @@ class UrlWriterTests < Test::Unit::TestCase
def test_only_path
ActionController::Routing::Routes.draw do |map|
map.home '/home/sweet/home/:user'
map.home '/home/sweet/home/:user', :controller => 'home', :action => 'index'
map.connect ':controller/:action/:id'
end
@@ -111,5 +114,58 @@ class UrlWriterTests < Test::Unit::TestCase
ensure
ActionController::Routing::Routes.load!
end
def test_one_parameter
assert_equal('/c/a?param=val',
W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :param => 'val')
)
end
def test_two_parameters
url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :p1 => 'X1', :p2 => 'Y2')
params = extract_params(url)
assert_equal params[0], { :p1 => 'X1' }.to_query
assert_equal params[1], { :p2 => 'Y2' }.to_query
end
def test_hash_parameter
url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:name => 'Bob', :category => 'prof'})
params = extract_params(url)
assert_equal params[0], { 'query[category]' => 'prof' }.to_query
assert_equal params[1], { 'query[name]' => 'Bob' }.to_query
end
def test_array_parameter
url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => ['Bob', 'prof'])
params = extract_params(url)
assert_equal params[0], { 'query[]' => 'Bob' }.to_query
assert_equal params[1], { 'query[]' => 'prof' }.to_query
end
def test_hash_recursive_parameters
url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:person => {:name => 'Bob', :position => 'prof'}, :hobby => 'piercing'})
params = extract_params(url)
assert_equal params[0], { 'query[hobby]' => 'piercing' }.to_query
assert_equal params[1], { 'query[person][name]' => 'Bob' }.to_query
assert_equal params[2], { 'query[person][position]' => 'prof' }.to_query
end
def test_hash_recursive_and_array_parameters
url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :id => 101, :query => {:person => {:name => 'Bob', :position => ['prof', 'art director']}, :hobby => 'piercing'})
assert_match %r(^/c/a/101), url
params = extract_params(url)
assert_equal params[0], { 'query[hobby]' => 'piercing' }.to_query
assert_equal params[1], { 'query[person][name]' => 'Bob' }.to_query
assert_equal params[2], { 'query[person][position][]' => 'art director' }.to_query
assert_equal params[3], { 'query[person][position][]' => 'prof' }.to_query
end
def test_path_generation_for_symbol_parameter_keys
assert_generates("/image", :controller=> :image)
end
private
def extract_params(url)
url.split('?', 2).last.split('&')
end
end

View File

@@ -34,9 +34,16 @@ class VerificationTest < Test::Unit::TestCase
verify :only => :must_be_post, :method => :post, :render => { :status => 405, :text => "Must be post" }, :add_headers => { "Allow" => "POST" }
verify :only => :guarded_one_for_named_route_test, :params => "one",
:redirect_to => :foo_url
def guarded_one
render :text => "#{params[:one]}"
end
def guarded_one_for_named_route_test
render :text => "#{params[:one]}"
end
def guarded_with_flash
render :text => "#{params[:one]}"
@@ -94,6 +101,14 @@ class VerificationTest < Test::Unit::TestCase
@controller = TestController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
ActionController::Routing::Routes.add_named_route :foo, '/foo', :controller => 'test', :action => 'foo'
end
def test_no_deprecation_warning_for_named_route
assert_not_deprecated do
get :guarded_one_for_named_route_test, :two => "not one"
assert_redirected_to '/foo'
end
end
def test_guarded_one_with_prereqs

Binary file not shown.

View File

@@ -0,0 +1 @@
# Test file for javascript_include_tag

View File

@@ -1,3 +1,4 @@
xml.html do
xml.p "Hello"
end
end
"String return value"

File diff suppressed because one or more lines are too long

View File

@@ -34,6 +34,7 @@ class AssetTagHelperTest < Test::Unit::TestCase
AutoDiscoveryToTag = {
%(auto_discovery_link_tag) => %(<link href="http://www.example.com" rel="alternate" title="RSS" type="application/rss+xml" />),
%(auto_discovery_link_tag(:rss)) => %(<link href="http://www.example.com" rel="alternate" title="RSS" type="application/rss+xml" />),
%(auto_discovery_link_tag(:atom)) => %(<link href="http://www.example.com" rel="alternate" title="ATOM" type="application/atom+xml" />),
%(auto_discovery_link_tag(:rss, :action => "feed")) => %(<link href="http://www.example.com" rel="alternate" title="RSS" type="application/rss+xml" />),
%(auto_discovery_link_tag(:rss, "http://localhost/feed")) => %(<link href="http://localhost/feed" rel="alternate" title="RSS" type="application/rss+xml" />),
@@ -47,11 +48,13 @@ class AssetTagHelperTest < Test::Unit::TestCase
JavascriptPathToTag = {
%(javascript_path("xmlhr")) => %(/javascripts/xmlhr.js),
%(javascript_path("super/xmlhr")) => %(/javascripts/super/xmlhr.js)
%(javascript_path("super/xmlhr")) => %(/javascripts/super/xmlhr.js),
%(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js)
}
JavascriptIncludeToTag = {
%(javascript_include_tag("xmlhr")) => %(<script src="/javascripts/xmlhr.js" type="text/javascript"></script>),
%(javascript_include_tag("xmlhr.js")) => %(<script src="/javascripts/xmlhr.js" type="text/javascript"></script>),
%(javascript_include_tag("xmlhr", :lang => "vbscript")) => %(<script lang="vbscript" src="/javascripts/xmlhr.js" type="text/javascript"></script>),
%(javascript_include_tag("common.javascript", "/elsewhere/cools")) => %(<script src="/javascripts/common.javascript" type="text/javascript"></script>\n<script src="/elsewhere/cools.js" type="text/javascript"></script>),
%(javascript_include_tag(:defaults)) => %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>),
@@ -61,12 +64,14 @@ class AssetTagHelperTest < Test::Unit::TestCase
StylePathToTag = {
%(stylesheet_path("style")) => %(/stylesheets/style.css),
%(stylesheet_path("style.css")) => %(/stylesheets/style.css),
%(stylesheet_path('dir/file')) => %(/stylesheets/dir/file.css),
%(stylesheet_path('/dir/file')) => %(/dir/file.css)
%(stylesheet_path('/dir/file.rcss')) => %(/dir/file.rcss)
}
StyleLinkToTag = {
%(stylesheet_link_tag("style")) => %(<link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />),
%(stylesheet_link_tag("style.css")) => %(<link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />),
%(stylesheet_link_tag("/dir/file")) => %(<link href="/dir/file.css" media="screen" rel="Stylesheet" type="text/css" />),
%(stylesheet_link_tag("dir/file")) => %(<link href="/stylesheets/dir/file.css" media="screen" rel="Stylesheet" type="text/css" />),
%(stylesheet_link_tag("style", :media => "all")) => %(<link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" />),
@@ -75,18 +80,28 @@ class AssetTagHelperTest < Test::Unit::TestCase
}
ImagePathToTag = {
%(image_path("xml")) => %(/images/xml.png),
%(image_path("xml.png")) => %(/images/xml.png),
%(image_path("dir/xml.png")) => %(/images/dir/xml.png),
%(image_path("/dir/xml.png")) => %(/dir/xml.png)
}
ImageLinkToTag = {
%(image_tag("xml")) => %(<img alt="Xml" src="/images/xml.png" />),
%(image_tag("rss", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/images/rss.png" />),
%(image_tag("gold", :size => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />),
%(image_tag("symbolize", "size" => "45x70")) => %(<img alt="Symbolize" height="70" src="/images/symbolize.png" width="45" />),
%(image_tag("http://www.rubyonrails.com/images/rails")) => %(<img alt="Rails" src="http://www.rubyonrails.com/images/rails.png" />)
%(image_tag("xml.png")) => %(<img alt="Xml" src="/images/xml.png" />),
%(image_tag("rss.gif", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/images/rss.gif" />),
%(image_tag("gold.png", :size => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />),
%(image_tag("gold.png", "size" => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />),
%(image_tag("error.png", "size" => "45")) => %(<img alt="Error" src="/images/error.png" />),
%(image_tag("error.png", "size" => "45 x 70")) => %(<img alt="Error" src="/images/error.png" />),
%(image_tag("error.png", "size" => "x")) => %(<img alt="Error" src="/images/error.png" />),
%(image_tag("http://www.rubyonrails.com/images/rails.png")) => %(<img alt="Rails" src="http://www.rubyonrails.com/images/rails.png" />)
}
def test_auto_discovery
DeprecatedImagePathToTag = {
%(image_path("xml")) => %(/images/xml.png)
}
def test_auto_discovery_link_tag
AutoDiscoveryToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -94,8 +109,12 @@ class AssetTagHelperTest < Test::Unit::TestCase
JavascriptPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_javascript_include
def test_javascript_include_tag
JavascriptIncludeToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
ENV["RAILS_ASSET_ID"] = "1"
assert_dom_equal(%(<script src="/javascripts/prototype.js?1" type="text/javascript"></script>\n<script src="/javascripts/effects.js?1" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js?1" type="text/javascript"></script>\n<script src="/javascripts/controls.js?1" type="text/javascript"></script>\n<script src="/javascripts/application.js?1" type="text/javascript"></script>), javascript_include_tag(:defaults))
end
def test_register_javascript_include_default
@@ -105,23 +124,25 @@ class AssetTagHelperTest < Test::Unit::TestCase
assert_dom_equal %(<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/slider.js" type="text/javascript"></script>\n<script src="/javascripts/lib1.js" type="text/javascript"></script>\n<script src="/elsewhere/blub/lib2.js" type="text/javascript"></script>), javascript_include_tag(:defaults)
end
def test_style_path
def test_stylesheet_path
StylePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_style_link
def test_stylesheet_link_tag
StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_image_path
ImagePathToTag.each do |method, tag|
assert_deprecated(/image_path/) { assert_dom_equal(tag, eval(method)) }
end
ImagePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_image_tag
ImageLinkToTag.each do |method, tag|
assert_deprecated(/image_path/) { assert_dom_equal(tag, eval(method)) }
ImageLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_should_deprecate_image_filename_with_no_extension
DeprecatedImagePathToTag.each do |method, tag|
assert_deprecated("image_path") { assert_dom_equal(tag, eval(method)) }
end
end
@@ -131,12 +152,12 @@ class AssetTagHelperTest < Test::Unit::TestCase
assert_equal %(<img alt="Rails" src="/images/rails.png?#{expected_time}" />), image_tag("rails.png")
end
def test_skipping_asset_id_on_complete_url
def test_should_skip_asset_id_on_complete_url
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
assert_equal %(<img alt="Rails" src="http://www.example.com/rails.png" />), image_tag("http://www.example.com/rails.png")
end
def test_preset_asset_id
def test_should_use_preset_asset_id
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
ENV["RAILS_ASSET_ID"] = "4500"
assert_equal %(<img alt="Rails" src="/images/rails.png?4500" />), image_tag("rails.png")
@@ -144,17 +165,20 @@ class AssetTagHelperTest < Test::Unit::TestCase
def test_preset_empty_asset_id
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
# on windows, setting ENV["XXX"] to "" makes ENV["XXX"] return nil
if RUBY_PLATFORM =~ /win32/
ENV["RAILS_ASSET_ID"] = " "
else
ENV["RAILS_ASSET_ID"] = ""
end
assert_equal %(<img alt="Rails" src="/images/rails.png" />), image_tag("rails.png")
end
def test_url_dup_image_tag
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
img_url = '/images/rails.png'
url_copy = img_url.dup
image_tag(img_url)
assert_equal url_copy, img_url
def test_should_not_modify_source_string
source = '/images/rails.png'
copy = source.dup
image_tag(source)
assert_equal copy, source
end
end
@@ -168,13 +192,13 @@ class AssetTagHelperNonVhostTest < Test::Unit::TestCase
attr_accessor :request
def url_for(options, *parameters_for_method_reference)
"http://www.example.com/calloboration/hieraki"
"http://www.example.com/collaboration/hieraki"
end
end.new
@request = Class.new do
def relative_url_root
"/calloboration/hieraki"
"/collaboration/hieraki"
end
end.new
@@ -183,89 +207,31 @@ class AssetTagHelperNonVhostTest < Test::Unit::TestCase
ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
end
AutoDiscoveryToTag = {
%(auto_discovery_link_tag(:rss, :action => "feed")) => %(<link href="http://www.example.com/calloboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />),
%(auto_discovery_link_tag(:atom)) => %(<link href="http://www.example.com/calloboration/hieraki" rel="alternate" title="ATOM" type="application/atom+xml" />),
%(auto_discovery_link_tag) => %(<link href="http://www.example.com/calloboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />),
}
JavascriptPathToTag = {
%(javascript_path("xmlhr")) => %(/calloboration/hieraki/javascripts/xmlhr.js),
}
JavascriptIncludeToTag = {
%(javascript_include_tag("xmlhr")) => %(<script src="/calloboration/hieraki/javascripts/xmlhr.js" type="text/javascript"></script>),
%(javascript_include_tag("common.javascript", "/elsewhere/cools")) => %(<script src="/calloboration/hieraki/javascripts/common.javascript" type="text/javascript"></script>\n<script src="/calloboration/hieraki/elsewhere/cools.js" type="text/javascript"></script>),
%(javascript_include_tag(:defaults)) => %(<script src="/calloboration/hieraki/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/effects.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/controls.js" type="text/javascript"></script>)
}
StylePathToTag = {
%(stylesheet_path("style")) => %(/calloboration/hieraki/stylesheets/style.css),
}
StyleLinkToTag = {
%(stylesheet_link_tag("style")) => %(<link href="/calloboration/hieraki/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />),
%(stylesheet_link_tag("random.styles", "/css/stylish")) => %(<link href="/calloboration/hieraki/stylesheets/random.styles" media="screen" rel="Stylesheet" type="text/css" />\n<link href="/calloboration/hieraki/css/stylish.css" media="screen" rel="Stylesheet" type="text/css" />)
}
ImagePathToTag = {
%(image_path("xml")) => %(/calloboration/hieraki/images/xml.png),
}
ImageLinkToTag = {
%(image_tag("xml")) => %(<img alt="Xml" src="/calloboration/hieraki/images/xml.png" />),
%(image_tag("rss", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/calloboration/hieraki/images/rss.png" />),
%(image_tag("gold", :size => "45x70")) => %(<img alt="Gold" height="70" src="/calloboration/hieraki/images/gold.png" width="45" />),
%(image_tag("symbolize", "size" => "45x70")) => %(<img alt="Symbolize" height="70" src="/calloboration/hieraki/images/symbolize.png" width="45" />)
}
def test_auto_discovery
AutoDiscoveryToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_javascript_path
JavascriptPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_javascript_include
JavascriptIncludeToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
def test_should_compute_proper_path
assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag)
assert_dom_equal(%(/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(/collaboration/hieraki/images/xml.png), image_path("xml.png"))
end
def test_register_javascript_include_default
ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'slider'
assert_dom_equal %(<script src="/calloboration/hieraki/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/effects.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/controls.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/slider.js" type="text/javascript"></script>), javascript_include_tag(:defaults)
ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'lib1', '/elsewhere/blub/lib2'
assert_dom_equal %(<script src="/calloboration/hieraki/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/effects.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/controls.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/slider.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/javascripts/lib1.js" type="text/javascript"></script>\n<script src="/calloboration/hieraki/elsewhere/blub/lib2.js" type="text/javascript"></script>), javascript_include_tag(:defaults)
def test_should_ignore_relative_root_path_on_complete_url
assert_dom_equal(%(http://www.example.com/images/xml.png), image_path("http://www.example.com/images/xml.png"))
end
def test_style_path
StylePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_style_link
StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
def test_image_path
ImagePathToTag.each { |method, tag| assert_deprecated(/image_path/) { assert_dom_equal(tag, eval(method)) } }
end
def test_image_tag
ImageLinkToTag.each do |method, tag|
assert_deprecated(/image_path/) { assert_dom_equal(tag, eval(method)) }
end
# Assigning a default alt tag should not cause an exception to be raised
assert_nothing_raised { image_tag('') }
end
def test_stylesheet_with_asset_host_already_encoded
ActionController::Base.asset_host = "http://foo.example.com"
result = stylesheet_link_tag("http://bar.example.com/stylesheets/style.css")
assert_dom_equal(
%(<link href="http://bar.example.com/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />),
result)
def test_should_compute_proper_path_with_asset_host
ActionController::Base.asset_host = "http://assets.example.com"
assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag)
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png"))
ensure
ActionController::Base.asset_host = ""
end
def test_should_ignore_asset_host_on_complete_url
ActionController::Base.asset_host = "http://assets.example.com"
assert_dom_equal(%(<link href="http://bar.example.com/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />), stylesheet_link_tag("http://bar.example.com/stylesheets/style.css"))
ensure
ActionController::Base.asset_host = ""
end
end

View File

@@ -71,7 +71,12 @@ class CompiledTemplateTests < Test::Unit::TestCase
end
def test_compile_time
`echo '#{@a}' > #{@a}; echo '#{@b}' > #{@b}; ln -s #{@a} #{@s}`
File.open(@a, "w"){|f| f.puts @a}
File.open(@b, "w"){|f| f.puts @b}
# windows doesn't support symlinks (even under cygwin)
windows = (RUBY_PLATFORM =~ /win32/)
`ln -s #{@a} #{@s}` unless windows
v = ActionView::Base.new
v.base_path = '.'
@@ -79,47 +84,54 @@ class CompiledTemplateTests < Test::Unit::TestCase
sleep 1
t = Time.now
sleep 1
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
v.compile_and_render_template(:rhtml, '', @s) unless windows
a_n = v.method_names[@a]
b_n = v.method_names[@b]
s_n = v.method_names[@s]
s_n = v.method_names[@s] unless windows
ct_a = v.compile_time[a_n]
ct_b = v.compile_time[b_n]
ct_s = v.compile_time[s_n] unless windows
# all of the files have changed since last compile
assert v.compile_time[a_n] > t
assert v.compile_time[b_n] > t
assert v.compile_time[s_n] > t
assert v.compile_time[s_n] > t unless windows
sleep 1
t = Time.now
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
v.compile_and_render_template(:rhtml, '', @s) unless windows
# none of the files have changed since last compile
assert v.compile_time[a_n] < t
assert v.compile_time[b_n] < t
assert v.compile_time[s_n] < t
# so they should not have been recmpiled
assert_equal ct_a, v.compile_time[a_n]
assert_equal ct_b, v.compile_time[b_n]
assert_equal ct_s, v.compile_time[s_n] unless windows
`rm #{@s}; ln -s #{@b} #{@s}`
`rm #{@s}; ln -s #{@b} #{@s}` unless windows
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
v.compile_and_render_template(:rhtml, '', @s) unless windows
# the symlink has changed since last compile
assert v.compile_time[a_n] < t
assert v.compile_time[b_n] < t
assert v.compile_time[s_n] > t
assert_equal ct_a, v.compile_time[a_n]
assert_equal ct_b, v.compile_time[b_n]
assert v.compile_time[s_n] > t unless windows
sleep 1
`touch #{@b}`
FileUtils.touch @b
t = Time.now
sleep 1
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
v.compile_and_render_template(:rhtml, '', @s) unless windows
# the file at the end of the symlink has changed since last compile
# both the symlink and the file at the end of it should be recompiled
assert v.compile_time[a_n] < t
assert v.compile_time[b_n] > t
assert v.compile_time[s_n] > t
assert v.compile_time[s_n] > t unless windows
end
end

File diff suppressed because it is too large Load Diff

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