mirror of
https://github.com/github/rails.git
synced 2026-01-13 08:38:05 -05:00
Compare commits
699 Commits
3-2-github
...
v3.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
186e3c71f9 | ||
|
|
31b6a6a78b | ||
|
|
029c8ff46c | ||
|
|
65fdd284e1 | ||
|
|
1540bf5816 | ||
|
|
4369f132a6 | ||
|
|
c41d9813be | ||
|
|
7487767c31 | ||
|
|
28f9d60f77 | ||
|
|
dbc0023d6d | ||
|
|
ccc8d9ce54 | ||
|
|
43b0fd7918 | ||
|
|
86534a35f9 | ||
|
|
13f10ac4ea | ||
|
|
4c3edae2bd | ||
|
|
5d9219b1b5 | ||
|
|
70e4403e46 | ||
|
|
41e5e4a7bd | ||
|
|
bad920f423 | ||
|
|
45c3abadfa | ||
|
|
205b24064e | ||
|
|
4ffd31e195 | ||
|
|
020f74b152 | ||
|
|
7a1f22ff33 | ||
|
|
06402b03ea | ||
|
|
0db841223a | ||
|
|
34015296e0 | ||
|
|
45525713f9 | ||
|
|
422831872e | ||
|
|
e777b914c8 | ||
|
|
1287fddff6 | ||
|
|
467d5844eb | ||
|
|
afc16f6dce | ||
|
|
3551e254d2 | ||
|
|
9078041ee8 | ||
|
|
9ccaf47012 | ||
|
|
10fc93b89e | ||
|
|
fc95196df0 | ||
|
|
01ed7005e1 | ||
|
|
f8b7c74f9b | ||
|
|
4266e3e91a | ||
|
|
bdec56cbe7 | ||
|
|
b870193345 | ||
|
|
ed62b96e23 | ||
|
|
d54ab371df | ||
|
|
30ae44a326 | ||
|
|
be63e03fba | ||
|
|
86f66e9097 | ||
|
|
0de95dfb2c | ||
|
|
d5fd83f4c7 | ||
|
|
3e86e4b34e | ||
|
|
55a8bd666d | ||
|
|
1b66a646db | ||
|
|
2e4e1ed916 | ||
|
|
387a1a6365 | ||
|
|
7611a0925c | ||
|
|
bf875b273d | ||
|
|
b0f6349a07 | ||
|
|
844b9a5018 | ||
|
|
f1c13b0dd7 | ||
|
|
4b33bd9888 | ||
|
|
c7fac8c6ea | ||
|
|
ad2c0bdb9b | ||
|
|
f676beb647 | ||
|
|
ea1fde6ae7 | ||
|
|
d4b7fa5fb6 | ||
|
|
7ab940c7ad | ||
|
|
e6abfc46bf | ||
|
|
a56142cc6b | ||
|
|
b91371763e | ||
|
|
a682986d0d | ||
|
|
2c8bff3513 | ||
|
|
5cb1dad228 | ||
|
|
6c8982fa13 | ||
|
|
918bf847d8 | ||
|
|
3ca1bc381f | ||
|
|
eca3791d0f | ||
|
|
b5efa8fc67 | ||
|
|
c95f155731 | ||
|
|
29b3af539b | ||
|
|
3bc12d3ee6 | ||
|
|
ae7a354110 | ||
|
|
4d2a53d9ea | ||
|
|
4772abc7d8 | ||
|
|
4fd9c20fb3 | ||
|
|
c681df48e3 | ||
|
|
ddf73603c1 | ||
|
|
f73a3e6838 | ||
|
|
0d23c2160d | ||
|
|
63b0d0e9d2 | ||
|
|
5f6a02f4ba | ||
|
|
909c860a42 | ||
|
|
e9d593bc18 | ||
|
|
ec23bc15ba | ||
|
|
7ca9dcd434 | ||
|
|
1a618e98e0 | ||
|
|
5a4a2323b0 | ||
|
|
c53f301b48 | ||
|
|
f294540154 | ||
|
|
4480521df9 | ||
|
|
adea1467f6 | ||
|
|
14b33a4eb7 | ||
|
|
141cba8f1d | ||
|
|
0891f49075 | ||
|
|
37431bb34e | ||
|
|
f7faa86690 | ||
|
|
10d3ab79dc | ||
|
|
85ffbfef9c | ||
|
|
869118aaae | ||
|
|
1556e0874d | ||
|
|
0a8eaff3d1 | ||
|
|
dba7de0da0 | ||
|
|
0c56a27926 | ||
|
|
448a187606 | ||
|
|
0b46f72226 | ||
|
|
d0d1acab58 | ||
|
|
3021297e89 | ||
|
|
b4954e81c1 | ||
|
|
83d5180bec | ||
|
|
4245dcd521 | ||
|
|
3a6acb6162 | ||
|
|
61fc0f0ba0 | ||
|
|
b4b4a2aa28 | ||
|
|
0b9eced70d | ||
|
|
d066ad638a | ||
|
|
981942a326 | ||
|
|
2ded862226 | ||
|
|
5e685caf1c | ||
|
|
fc9e9ed406 | ||
|
|
d75244785f | ||
|
|
003d67efb2 | ||
|
|
c4528deec1 | ||
|
|
1e50fae259 | ||
|
|
9eeb24cd57 | ||
|
|
b9fd742bb6 | ||
|
|
53def60d83 | ||
|
|
444aa9c735 | ||
|
|
af53ed89c4 | ||
|
|
accc5676d6 | ||
|
|
3e958a5bf7 | ||
|
|
13a4d1436f | ||
|
|
cec7129729 | ||
|
|
da927d2e16 | ||
|
|
c13aaaa2f0 | ||
|
|
4a77431b9a | ||
|
|
86571a1f43 | ||
|
|
e5da873db1 | ||
|
|
e99c894767 | ||
|
|
2380c71601 | ||
|
|
ebfbb2a2e3 | ||
|
|
fef42738d7 | ||
|
|
f283812bed | ||
|
|
3569bde28e | ||
|
|
f9b5f63319 | ||
|
|
87104a71a9 | ||
|
|
fc1c799241 | ||
|
|
b0b2d41a48 | ||
|
|
7e73344f7a | ||
|
|
ea6305411f | ||
|
|
2221b701b4 | ||
|
|
fc1bd2bba4 | ||
|
|
de3c0d7eb4 | ||
|
|
43f404ed6e | ||
|
|
b08175825e | ||
|
|
5704aa2e1a | ||
|
|
1a2b28c9d9 | ||
|
|
9ddda10b67 | ||
|
|
f640af5a7a | ||
|
|
a35c8c6426 | ||
|
|
e080144242 | ||
|
|
8ae8125e75 | ||
|
|
ddc2f2ee50 | ||
|
|
a01547cc12 | ||
|
|
2e0114182c | ||
|
|
439a0ceb43 | ||
|
|
3daf8228f9 | ||
|
|
1685bd2e10 | ||
|
|
ede0466d13 | ||
|
|
bf388f37ac | ||
|
|
93096aedcb | ||
|
|
c493624fc2 | ||
|
|
6059c9679e | ||
|
|
721f43498a | ||
|
|
e6e90839d0 | ||
|
|
ecbfed2f83 | ||
|
|
409bd22a2d | ||
|
|
1e687e98ac | ||
|
|
cab12076d7 | ||
|
|
1efeb5c935 | ||
|
|
10d9740827 | ||
|
|
40bc0cb34d | ||
|
|
9e5545cd66 | ||
|
|
fae57ef4f5 | ||
|
|
9edaf10fee | ||
|
|
c2c6f12c84 | ||
|
|
2525bfc5dd | ||
|
|
e0411f3412 | ||
|
|
61e70bf623 | ||
|
|
6643929d5a | ||
|
|
b32bd08622 | ||
|
|
9e32b1cbe5 | ||
|
|
a56df5b052 | ||
|
|
e677275068 | ||
|
|
f38c46cfcf | ||
|
|
a88af8a669 | ||
|
|
d5e916563e | ||
|
|
d3ffea25b2 | ||
|
|
2f618bf7da | ||
|
|
f90a29853f | ||
|
|
59ef0a2a50 | ||
|
|
15fd9a21dc | ||
|
|
19b71233fe | ||
|
|
262319ab01 | ||
|
|
268319c8ba | ||
|
|
c8bf9674dd | ||
|
|
c8b34f2d9f | ||
|
|
0387d5b6f2 | ||
|
|
23f728abd5 | ||
|
|
4d023a6970 | ||
|
|
e41add0d30 | ||
|
|
8a68862020 | ||
|
|
49d54b4fb6 | ||
|
|
e66c1cee86 | ||
|
|
8105bc022e | ||
|
|
abb99e3ac0 | ||
|
|
e1e39a9a7b | ||
|
|
27cfb3e7bb | ||
|
|
093a30a019 | ||
|
|
68e1b5a397 | ||
|
|
109c37b73f | ||
|
|
bdba74819c | ||
|
|
8d14fa8959 | ||
|
|
1a61a797aa | ||
|
|
b0f059136b | ||
|
|
684bb86266 | ||
|
|
2db30351ed | ||
|
|
3c36c12a65 | ||
|
|
8765e06937 | ||
|
|
7a6c715517 | ||
|
|
bfd4022075 | ||
|
|
a0fc2f7b74 | ||
|
|
9d36e2ad2c | ||
|
|
39cb27b414 | ||
|
|
68034efea1 | ||
|
|
164e3b6612 | ||
|
|
ab59522ea1 | ||
|
|
e125bf264e | ||
|
|
b79a782a05 | ||
|
|
301462c89b | ||
|
|
7d54fba421 | ||
|
|
5391dd3821 | ||
|
|
a23bf047b6 | ||
|
|
b5a17d7648 | ||
|
|
4ef2dead68 | ||
|
|
41807eb152 | ||
|
|
75b985e4e8 | ||
|
|
91693ddfe4 | ||
|
|
14f1b09b46 | ||
|
|
3479c1ea62 | ||
|
|
89cc7426dd | ||
|
|
1817ae327e | ||
|
|
c510870a8f | ||
|
|
ceb193a201 | ||
|
|
f6d5ff2f00 | ||
|
|
b8ff3df6a4 | ||
|
|
465dd6f0e9 | ||
|
|
2ef60690ff | ||
|
|
ac89275f1d | ||
|
|
298da5b8a9 | ||
|
|
993572472a | ||
|
|
ab1ab5fcec | ||
|
|
d30fb467c9 | ||
|
|
172377df45 | ||
|
|
733e928234 | ||
|
|
742da4b0d4 | ||
|
|
2820addea7 | ||
|
|
7108daf20e | ||
|
|
a9b5b19d9a | ||
|
|
ed9d30981f | ||
|
|
3de55aafbf | ||
|
|
378728b5d1 | ||
|
|
662ce52ed7 | ||
|
|
ad781a175c | ||
|
|
16cff17e53 | ||
|
|
5297e641cd | ||
|
|
7ddf663c75 | ||
|
|
41e0f68474 | ||
|
|
a746090a31 | ||
|
|
1276c28336 | ||
|
|
9a28d42d60 | ||
|
|
442e4d087b | ||
|
|
b1c104296e | ||
|
|
ef66a08160 | ||
|
|
33b954005c | ||
|
|
3091cb386f | ||
|
|
d73fcfeb52 | ||
|
|
b8899bba12 | ||
|
|
a461c2b595 | ||
|
|
c72140198d | ||
|
|
bd1059f5ad | ||
|
|
7020c92e0f | ||
|
|
817b8f0ac4 | ||
|
|
8c49666474 | ||
|
|
9fe7ef65ea | ||
|
|
935fa9d6d5 | ||
|
|
f0113e59c2 | ||
|
|
02daf68e6a | ||
|
|
1c7a7545eb | ||
|
|
29887510bf | ||
|
|
2ad2bd3644 | ||
|
|
d7201210ba | ||
|
|
dcce930a8f | ||
|
|
b1291836c3 | ||
|
|
6a60387dce | ||
|
|
233e0e8ce8 | ||
|
|
5c06777293 | ||
|
|
86a96fb17c | ||
|
|
20866a5c95 | ||
|
|
3e931b1961 | ||
|
|
36e625df83 | ||
|
|
b227a9a948 | ||
|
|
7221d6a841 | ||
|
|
aefa11be11 | ||
|
|
bf87528b53 | ||
|
|
93a716fb9c | ||
|
|
9441eabbbf | ||
|
|
3b6d7f0df8 | ||
|
|
c25c81e7c9 | ||
|
|
d1eb9ff8b1 | ||
|
|
3df90defa8 | ||
|
|
2adad2a0cc | ||
|
|
9c5248f6f2 | ||
|
|
fed73ffecf | ||
|
|
69ae216bcf | ||
|
|
8cba115301 | ||
|
|
54b193fe16 | ||
|
|
5fc006a9a4 | ||
|
|
4144eace88 | ||
|
|
3746453c3a | ||
|
|
c2a87b45b8 | ||
|
|
031b60d270 | ||
|
|
63306de3e7 | ||
|
|
b29eb89be8 | ||
|
|
c1bafe07a9 | ||
|
|
e7b1b3f610 | ||
|
|
3e786065f5 | ||
|
|
67b4c42b89 | ||
|
|
bab620fe5c | ||
|
|
d37a44e42c | ||
|
|
c1915f5ff3 | ||
|
|
6ba646329b | ||
|
|
9017e1f03f | ||
|
|
6655a3c248 | ||
|
|
46fddc305a | ||
|
|
3e7f7668fc | ||
|
|
3a96fa485c | ||
|
|
e709c97e08 | ||
|
|
050a345972 | ||
|
|
e8d2002f21 | ||
|
|
05bb9cae95 | ||
|
|
6ed616d51a | ||
|
|
d9a323ea81 | ||
|
|
676b5bf970 | ||
|
|
fcdedb2c00 | ||
|
|
99a87e9dd0 | ||
|
|
9891ca89c6 | ||
|
|
e38fa05781 | ||
|
|
c7106e827e | ||
|
|
3d0c92868c | ||
|
|
a8a9f00058 | ||
|
|
ca73b5ba65 | ||
|
|
9f9c50f917 | ||
|
|
b63b6c4033 | ||
|
|
647ed22aad | ||
|
|
851552bd80 | ||
|
|
829df8007d | ||
|
|
a2c547f592 | ||
|
|
15e9b53a57 | ||
|
|
90d4a19285 | ||
|
|
0f94ca31b1 | ||
|
|
ef01f8840b | ||
|
|
3edd3d052e | ||
|
|
331234e0ab | ||
|
|
cc5a9c642b | ||
|
|
bf35d1e7c0 | ||
|
|
7f83aefd38 | ||
|
|
0c87873455 | ||
|
|
8da45763b2 | ||
|
|
5502a78c3e | ||
|
|
6c84fd80b7 | ||
|
|
c144f50347 | ||
|
|
e2d73f01a9 | ||
|
|
ba03dd4774 | ||
|
|
dbbf198f5c | ||
|
|
3ba8e31005 | ||
|
|
e8a083ecc2 | ||
|
|
39f2f18679 | ||
|
|
983a5e2970 | ||
|
|
2af7f29203 | ||
|
|
a2d3e6e29f | ||
|
|
473feeb32d | ||
|
|
d806aa2b68 | ||
|
|
daf2f95830 | ||
|
|
52e962086d | ||
|
|
b78011314e | ||
|
|
9df512be94 | ||
|
|
ace0f87056 | ||
|
|
1c2a2f711d | ||
|
|
a3161096c2 | ||
|
|
217fb3e9b5 | ||
|
|
dcdb8bae38 | ||
|
|
27512c2161 | ||
|
|
60685475dc | ||
|
|
3ecbae0672 | ||
|
|
59cd141c81 | ||
|
|
d7f1226412 | ||
|
|
6a035099b2 | ||
|
|
3b3cfa44f6 | ||
|
|
908544c90e | ||
|
|
2722c82f6e | ||
|
|
d810854d42 | ||
|
|
e12ff5b3bd | ||
|
|
61292a1f87 | ||
|
|
8bad8ac758 | ||
|
|
241dfa3c90 | ||
|
|
9ba46cf15a | ||
|
|
3dc9880866 | ||
|
|
da7a28027a | ||
|
|
bfe956d785 | ||
|
|
e991f39709 | ||
|
|
aec084955d | ||
|
|
55c1f351c4 | ||
|
|
d887dbc2d6 | ||
|
|
37467bf0fc | ||
|
|
30dcac2926 | ||
|
|
5deeb43fca | ||
|
|
78f6f0dc4b | ||
|
|
174d5cd7ee | ||
|
|
2ae4f01650 | ||
|
|
3a831cb7d6 | ||
|
|
0d7b8f8c83 | ||
|
|
91916e6c3c | ||
|
|
6b54a6a8ff | ||
|
|
6d1e87b16b | ||
|
|
7830f8d9f8 | ||
|
|
d8196bf994 | ||
|
|
aa384de7dd | ||
|
|
78486cb9c5 | ||
|
|
6579173814 | ||
|
|
a32f46d0ce | ||
|
|
c857bd23c0 | ||
|
|
5ccdb362b4 | ||
|
|
7a7012c717 | ||
|
|
8feb2856ea | ||
|
|
5708412052 | ||
|
|
822fa17c6c | ||
|
|
04aa14f8d7 | ||
|
|
bc61196bf5 | ||
|
|
aafb29073a | ||
|
|
880eaa145e | ||
|
|
fc6db6226f | ||
|
|
8931dd17a9 | ||
|
|
c8b84a1c8c | ||
|
|
36fcc99cce | ||
|
|
a1ca2e0a38 | ||
|
|
6a1ea881cf | ||
|
|
1cc653f9b3 | ||
|
|
eeb9b379f9 | ||
|
|
ce04ea973c | ||
|
|
ab64dc9c20 | ||
|
|
f10fb1c4e9 | ||
|
|
2570fda5ab | ||
|
|
b97ad85d44 | ||
|
|
d125687b97 | ||
|
|
2c81a31039 | ||
|
|
bedf6a0061 | ||
|
|
6edae4553e | ||
|
|
8235c9288f | ||
|
|
6ca6ef2ab0 | ||
|
|
0579963a38 | ||
|
|
7cb44a5092 | ||
|
|
df0a7bfb8f | ||
|
|
2106782828 | ||
|
|
e88f8bee5e | ||
|
|
11e9883f19 | ||
|
|
b4e5da6bde | ||
|
|
7dbc99ef0d | ||
|
|
d0e3323d5b | ||
|
|
68e2d1e496 | ||
|
|
9011f8f49c | ||
|
|
b4a520874a | ||
|
|
47f6d8b880 | ||
|
|
612c233a28 | ||
|
|
8f72ddc12b | ||
|
|
47280f083a | ||
|
|
c6391e6676 | ||
|
|
20088f6fff | ||
|
|
d033b237c4 | ||
|
|
809a04ba8f | ||
|
|
ac66de4a82 | ||
|
|
e509d4afc9 | ||
|
|
ad063263bc | ||
|
|
8f2b2781b0 | ||
|
|
6b52a58f72 | ||
|
|
1031fe1478 | ||
|
|
758f01d49e | ||
|
|
21c9795c15 | ||
|
|
49e406efb7 | ||
|
|
1ef9b98a31 | ||
|
|
bef90f8449 | ||
|
|
64f4dc68f6 | ||
|
|
a16ec2f4cf | ||
|
|
6fb6ddb9a7 | ||
|
|
632a224bd1 | ||
|
|
6580c6df36 | ||
|
|
ddce48a355 | ||
|
|
06632578c2 | ||
|
|
2f6383e340 | ||
|
|
7e85b16518 | ||
|
|
12f7f7a714 | ||
|
|
82eff0ffe9 | ||
|
|
588ac71213 | ||
|
|
0a41ece3e3 | ||
|
|
c40856c46c | ||
|
|
23303d6ab7 | ||
|
|
017840beb8 | ||
|
|
92f4cca4a3 | ||
|
|
82a58abe05 | ||
|
|
90176a6f15 | ||
|
|
4b21dfe9a7 | ||
|
|
c11ba424e7 | ||
|
|
21063e5e27 | ||
|
|
22d242c2ca | ||
|
|
6f478b0698 | ||
|
|
fc43c62fc6 | ||
|
|
b9281e8e2c | ||
|
|
5f5c508444 | ||
|
|
020aeb6192 | ||
|
|
141634ddc6 | ||
|
|
14be1789b7 | ||
|
|
1d2e075bf1 | ||
|
|
d1480926e8 | ||
|
|
047e411fd2 | ||
|
|
452a56ad51 | ||
|
|
83cb532009 | ||
|
|
c330e96a6e | ||
|
|
a34dce9717 | ||
|
|
b8ec4eaac5 | ||
|
|
688368100a | ||
|
|
19fb031d84 | ||
|
|
dbe5ae488e | ||
|
|
1091a6e9b7 | ||
|
|
8520045200 | ||
|
|
ebf7447b34 | ||
|
|
10177d3a38 | ||
|
|
f224c66a91 | ||
|
|
88fc37ff03 | ||
|
|
bdeeca358b | ||
|
|
5f7bfb1c3a | ||
|
|
ae7732f957 | ||
|
|
df8a941a43 | ||
|
|
6d68cde2c5 | ||
|
|
0f1b9bbbf8 | ||
|
|
477a9d4d86 | ||
|
|
a036999ed1 | ||
|
|
707248a629 | ||
|
|
ecf59b4776 | ||
|
|
677564f8f7 | ||
|
|
f6f7ae4020 | ||
|
|
b3ece73114 | ||
|
|
76c91a237c | ||
|
|
05ba082c6a | ||
|
|
3270c58ebb | ||
|
|
ccd4364a13 | ||
|
|
6373dd466f | ||
|
|
59e63e76c3 | ||
|
|
433d7a26fe | ||
|
|
79e15f0340 | ||
|
|
3698da65e5 | ||
|
|
108179b068 | ||
|
|
bacf78150c | ||
|
|
e86b758592 | ||
|
|
abd973689d | ||
|
|
fb6edb1769 | ||
|
|
e4283007d6 | ||
|
|
91ae6e9933 | ||
|
|
fe2d65864e | ||
|
|
9df227983f | ||
|
|
d03a1249a0 | ||
|
|
9528aa9f86 | ||
|
|
4dcce5d06e | ||
|
|
ab68d4b52e | ||
|
|
1e6e868d8c | ||
|
|
198bffe3be | ||
|
|
06af291346 | ||
|
|
30ea923040 | ||
|
|
7325dd21b3 | ||
|
|
f2d22ecbb3 | ||
|
|
1c970b8394 | ||
|
|
c8509d5303 | ||
|
|
36cb62eb9d | ||
|
|
bfd728182c | ||
|
|
ff760dd6ce | ||
|
|
5352a89d50 | ||
|
|
a56ee4c9a2 | ||
|
|
dac2b37b03 | ||
|
|
8464ee0650 | ||
|
|
e1b85c3bda | ||
|
|
1fbcd5f5fc | ||
|
|
43b8722f4b | ||
|
|
d9b77ddecd | ||
|
|
6f88b82263 | ||
|
|
b2eaac24c3 | ||
|
|
5859f5eee1 | ||
|
|
63ffec85b7 | ||
|
|
ca3fc4b325 | ||
|
|
aaa52c6d1f | ||
|
|
68bed3a4ad | ||
|
|
8968eecb93 | ||
|
|
3c404c56eb | ||
|
|
cbf89a378c | ||
|
|
2d681838c0 | ||
|
|
b02751c961 | ||
|
|
3ccf3504d2 | ||
|
|
98384b1ce8 | ||
|
|
a263a8ffd5 | ||
|
|
dd7e872e85 | ||
|
|
f85b206e7a | ||
|
|
22cbc3f0fa | ||
|
|
efb2bd0409 | ||
|
|
195e891954 | ||
|
|
28d82bd2e9 | ||
|
|
4d4b865b11 | ||
|
|
5c109e243f | ||
|
|
f7996be0c7 | ||
|
|
d55491c844 | ||
|
|
4b18d3c210 | ||
|
|
783dc5207b | ||
|
|
78c7705b32 | ||
|
|
5aec933385 | ||
|
|
413c9c8235 | ||
|
|
91930dc30b | ||
|
|
001a574785 | ||
|
|
a897a1f4a3 | ||
|
|
8fb0c9f509 | ||
|
|
0bb8d0561a | ||
|
|
bed98b9bf2 | ||
|
|
148dd2eac6 | ||
|
|
06e4c48815 | ||
|
|
0a86cb5972 | ||
|
|
e34fb808db | ||
|
|
2005f8234a | ||
|
|
05a49c7718 | ||
|
|
902d732617 | ||
|
|
84d5461d43 | ||
|
|
18bcc548bf | ||
|
|
ba9602b9e7 | ||
|
|
906ef233e4 | ||
|
|
4da32babdf | ||
|
|
87365272e9 | ||
|
|
f316a851dd | ||
|
|
19c77a0d2b | ||
|
|
2498cdaf14 | ||
|
|
963638aac8 | ||
|
|
fbc40a4d94 | ||
|
|
32d840d98a | ||
|
|
bd1cf94a29 | ||
|
|
d599e94e45 | ||
|
|
91e4249c02 | ||
|
|
07c5e5416b | ||
|
|
8158afa47e | ||
|
|
9269e55b1f | ||
|
|
b46b5a6d54 | ||
|
|
46a1da7c79 | ||
|
|
8b7219b9d6 | ||
|
|
109dc3c39c | ||
|
|
af8e085190 | ||
|
|
146a013c42 | ||
|
|
84703be5ff | ||
|
|
43cc69cb65 | ||
|
|
01186652cc | ||
|
|
7a1bba4799 | ||
|
|
4474470ffd | ||
|
|
9ae7f04cd6 | ||
|
|
1318bf6e33 | ||
|
|
5987fd4c79 | ||
|
|
677e1e58b6 | ||
|
|
3b170b2e14 | ||
|
|
79583ca9b1 | ||
|
|
257e9c4ec4 | ||
|
|
a44779e9bb | ||
|
|
503931df05 | ||
|
|
e1142dfcae | ||
|
|
1466f312ba | ||
|
|
2c8a4a53a8 | ||
|
|
fb2b8fec24 | ||
|
|
db1c484c55 | ||
|
|
807239f5a1 | ||
|
|
f73e9d2df8 |
43
Gemfile
43
Gemfile
@@ -1,17 +1,16 @@
|
||||
source 'http://rubygems.org'
|
||||
|
||||
if ENV['AREL']
|
||||
gem "arel", :path => ENV['AREL']
|
||||
else
|
||||
gem "arel", :git => "git://github.com/rails/arel.git"
|
||||
end
|
||||
|
||||
gem "rails", :path => File.dirname(__FILE__)
|
||||
|
||||
gem "rake", ">= 0.8.7"
|
||||
gem "mocha", ">= 0.9.8"
|
||||
gem "rdoc", ">= 2.5.9"
|
||||
gem "horo"
|
||||
gem "rdoc", ">= 2.5.10"
|
||||
gem "horo", ">= 1.0.2"
|
||||
|
||||
# for perf tests
|
||||
gem "faker"
|
||||
gem "rbench"
|
||||
gem "addressable"
|
||||
|
||||
# AS
|
||||
gem "memcache-client", ">= 1.8.5"
|
||||
@@ -22,6 +21,11 @@ gem "text-format", "~> 1.0.0"
|
||||
platforms :mri_18 do
|
||||
gem "system_timer"
|
||||
gem "ruby-debug", ">= 0.10.3"
|
||||
gem 'ruby-prof'
|
||||
end
|
||||
|
||||
platforms :mri_19 do
|
||||
gem "ruby-debug19"
|
||||
end
|
||||
|
||||
platforms :ruby do
|
||||
@@ -35,6 +39,7 @@ platforms :ruby do
|
||||
group :db do
|
||||
gem "pg", ">= 0.9.0"
|
||||
gem "mysql", ">= 2.8.1"
|
||||
gem "mysql2", ">= 0.2.6"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,17 +48,29 @@ platforms :jruby do
|
||||
|
||||
gem "activerecord-jdbcsqlite3-adapter"
|
||||
|
||||
# This is needed by now to let tests work on JRuby
|
||||
# TODO: When the JRuby guys merge jruby-openssl in
|
||||
# jruby this will be removed
|
||||
gem "jruby-openssl"
|
||||
|
||||
group :db do
|
||||
gem "activerecord-jdbcmysql-adapter"
|
||||
gem "activerecord-jdbcpostgresql-adapter"
|
||||
end
|
||||
end
|
||||
|
||||
env 'CI' do
|
||||
gem "nokogiri", ">= 1.4.3.1"
|
||||
env :AREL do
|
||||
gem "arel", :path => ENV['AREL']
|
||||
end
|
||||
|
||||
platforms :ruby_18 do
|
||||
# fcgi gem doesn't compile on 1.9
|
||||
gem "fcgi", ">= 0.8.8"
|
||||
# gems that are necessary for ActiveRecord tests with Oracle database
|
||||
if ENV['ORACLE_ENHANCED_PATH'] || ENV['ORACLE_ENHANCED']
|
||||
platforms :ruby do
|
||||
gem 'ruby-oci8', ">= 2.0.4"
|
||||
end
|
||||
if ENV['ORACLE_ENHANCED_PATH']
|
||||
gem 'activerecord-oracle_enhanced-adapter', :path => ENV['ORACLE_ENHANCED_PATH']
|
||||
else
|
||||
gem "activerecord-oracle_enhanced-adapter", :git => "git://github.com/rsim/oracle-enhanced.git"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.0.rc
|
||||
3.0.2
|
||||
|
||||
33
README.rdoc
33
README.rdoc
@@ -1,6 +1,6 @@
|
||||
== Welcome to Rails
|
||||
== Welcome to \Rails
|
||||
|
||||
Rails is a web-application framework that includes everything needed to create
|
||||
\Rails is a web-application framework that includes everything needed to create
|
||||
database-backed web applications according to the Model-View-Control pattern.
|
||||
|
||||
This pattern splits the view (also called the presentation) into "dumb"
|
||||
@@ -11,30 +11,30 @@ persist themselves to a database. The controller handles the incoming requests
|
||||
(such as Save New Account, Update Product, Show Post) by manipulating the model
|
||||
and directing data to the view.
|
||||
|
||||
In Rails, the model is handled by what's called an object-relational mapping
|
||||
In \Rails, the model is handled by what's called an object-relational mapping
|
||||
layer entitled Active Record. This layer allows you to present the data from
|
||||
database rows as objects and embellish these data objects with business logic
|
||||
methods. You can read more about Active Record in
|
||||
link:files/vendor/rails/activerecord/README.html.
|
||||
methods. You can read more about Active Record in its
|
||||
{README}[link:files/activerecord/README_rdoc.html].
|
||||
|
||||
The controller and view are handled by the Action Pack, which handles both
|
||||
layers by its two parts: Action View and Action Controller. These two layers
|
||||
are bundled in a single package due to their heavy interdependence. This is
|
||||
unlike the relationship between the Active Record and Action Pack that is much
|
||||
more separate. Each of these packages can be used independently outside of
|
||||
Rails. You can read more about Action Pack in
|
||||
link:files/vendor/rails/actionpack/README.html.
|
||||
\Rails. You can read more about Action Pack in its
|
||||
{README}[link:files/actionpack/README_rdoc.html].
|
||||
|
||||
|
||||
== Getting Started
|
||||
|
||||
1. Install Rails at the command prompt if you haven't yet:
|
||||
1. Install \Rails at the command prompt if you haven't yet:
|
||||
|
||||
gem install rails
|
||||
|
||||
2. At the command prompt, create a new Rails application:
|
||||
2. At the command prompt, create a new \Rails application:
|
||||
|
||||
rails new myapp
|
||||
rails new myapp
|
||||
|
||||
where "myapp" is the application name.
|
||||
|
||||
@@ -48,20 +48,21 @@ link:files/vendor/rails/actionpack/README.html.
|
||||
|
||||
"Welcome aboard: You're riding Ruby on Rails!"
|
||||
|
||||
5. Follow the guidelines to start developing your application. You can find
|
||||
the following resources handy:
|
||||
5. Follow the guidelines to start developing your application. You can find the following resources handy:
|
||||
|
||||
* The README file created within your application.
|
||||
* The {Getting Started Guide}[http://guides.rubyonrails.org/getting_started.html].
|
||||
* The {Ruby on Rails Tutorial Book}[http://railstutorial.org/book].
|
||||
* The {Getting Started with Rails}[http://guides.rubyonrails.org/getting_started.html].
|
||||
* The {Ruby on Rails Tutorial}[http://railstutorial.org/book].
|
||||
* The {Ruby on Rails guides}[http://guides.rubyonrails.org/getting_started.html].
|
||||
* The {API documentation}[http://api.rubyonrails.org].
|
||||
|
||||
|
||||
== Contributing
|
||||
|
||||
We encourage you to contribute to Ruby on Rails! Please check out the {Contributing to Rails
|
||||
We encourage you to contribute to Ruby on \Rails! Please check out the {Contributing to Rails
|
||||
guide}[http://edgeguides.rubyonrails.org/contributing_to_rails.html] for guidelines about how
|
||||
to proceed. {Join us}[http://contributors.rubyonrails.org]!
|
||||
|
||||
== License
|
||||
|
||||
Ruby on Rails is released under the MIT license.
|
||||
Ruby on \Rails is released under the MIT license.
|
||||
|
||||
37
Rakefile
37
Rakefile
@@ -1,10 +1,35 @@
|
||||
gem 'rdoc', '>= 2.5.9'
|
||||
gem 'rdoc', '>= 2.5.10'
|
||||
require 'rdoc'
|
||||
|
||||
require 'rake'
|
||||
require 'rdoc/task'
|
||||
require 'rake/gempackagetask'
|
||||
|
||||
# RDoc skips some files in the Rails tree due to its binary? predicate. This is a quick
|
||||
# hack for edge docs, until we decide which is the correct way to address this issue.
|
||||
# If not fixed in RDoc itself, via an option or something, we should probably move this
|
||||
# to railties and use it also in doc:rails.
|
||||
def hijack_rdoc!
|
||||
require "rdoc/parser"
|
||||
class << RDoc::Parser
|
||||
def binary?(file)
|
||||
s = File.read(file, 1024) or return false
|
||||
|
||||
if s[0, 2] == Marshal.dump('')[0, 2] then
|
||||
true
|
||||
elsif file =~ /erb\.rb$/ then
|
||||
false
|
||||
elsif s.index("\x00") then # ORIGINAL is s.scan(/<%|%>/).length >= 4 || s.index("\x00")
|
||||
true
|
||||
elsif 0.respond_to? :fdiv then
|
||||
s.count("^ -~\t\r\n").fdiv(s.size) > 0.3
|
||||
else # HACK 1.8.6
|
||||
(s.count("^ -~\t\r\n").to_f / s.size) > 0.3
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PROJECTS = %w(activesupport activemodel actionpack actionmailer activeresource activerecord railties)
|
||||
|
||||
desc 'Run all tests by default'
|
||||
@@ -63,6 +88,8 @@ end
|
||||
|
||||
desc "Generate documentation for the Rails framework"
|
||||
RDoc::Task.new do |rdoc|
|
||||
hijack_rdoc!
|
||||
|
||||
rdoc.rdoc_dir = 'doc/rdoc'
|
||||
rdoc.title = "Ruby on Rails Documentation"
|
||||
|
||||
@@ -90,6 +117,7 @@ RDoc::Task.new do |rdoc|
|
||||
|
||||
rdoc.rdoc_files.include('actionpack/README.rdoc')
|
||||
rdoc.rdoc_files.include('actionpack/CHANGELOG')
|
||||
rdoc.rdoc_files.include('actionpack/lib/abstract_controller/**/*.rb')
|
||||
rdoc.rdoc_files.include('actionpack/lib/action_controller/**/*.rb')
|
||||
rdoc.rdoc_files.include('actionpack/lib/action_dispatch/**/*.rb')
|
||||
rdoc.rdoc_files.include('actionpack/lib/action_view/**/*.rb')
|
||||
@@ -116,12 +144,7 @@ task :rdoc do
|
||||
FileUtils.copy "activerecord/examples/associations.png", "doc/rdoc/files/examples/associations.png"
|
||||
end
|
||||
|
||||
desc "Publish API docs for Rails as a whole and for each component"
|
||||
task :pdoc => :rdoc do
|
||||
require 'rake/contrib/sshpublisher'
|
||||
Rake::SshDirPublisher.new("rails@api.rubyonrails.org", "public_html/api", "doc/rdoc").upload
|
||||
end
|
||||
|
||||
desc 'Bump all versions to match version.rb'
|
||||
task :update_versions do
|
||||
require File.dirname(__FILE__) + "/version"
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
*Rails 3.0.0 [release candidate] (July 26th, 2010)*
|
||||
*Rails 3.0.2 (November 15, 2010)*
|
||||
|
||||
* No material changes
|
||||
* No changes.
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 4] (June 8th, 2010)*
|
||||
*Rails 3.0.1 (October 15, 2010)*
|
||||
|
||||
* No Changes.
|
||||
|
||||
|
||||
*Rails 3.0.0 (August 29, 2010)*
|
||||
|
||||
* subject is automatically looked up on I18n using mailer_name and action_name as scope as in t(".subject") [JK]
|
||||
|
||||
@@ -11,16 +16,10 @@
|
||||
|
||||
* Added ability to pass Proc objects to the defaults hash [ML]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
|
||||
|
||||
* Removed all quoting.rb type files from ActionMailer and put Mail 2.2.0 in instead [ML]
|
||||
|
||||
* Lot of updates to various test cases that now work better with the new Mail and so have different expectations
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* Added interceptors and observers from Mail [ML]
|
||||
|
||||
ActionMailer::Base.register_interceptor calls Mail.register_interceptor
|
||||
@@ -38,9 +37,6 @@
|
||||
|
||||
* Whole new API added with tests. See base.rb for full details. Old API is deprecated.
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* The Mail::Message class has helped methods for all the field types that return 'common' defaults for the common use case, so to get the subject, mail.subject will give you a string, mail.date will give you a DateTime object, mail.from will give you an array of address specs (mikel@test.lindsaar.net) etc. If you want to access the field object itself, call mail[:field_name] which will return the field object you want, which you can then chain, like mail[:from].formatted
|
||||
|
||||
* Mail#content_type now returns the content_type field as a string. If you want the mime type of a mail, then you call Mail#mime_type (eg, text/plain), if you want the parameters of the content type field, you call Mail#content_type_parameters which gives you a hash, eg {'format' => 'flowed', 'charset' => 'utf-8'}
|
||||
@@ -181,7 +177,7 @@
|
||||
|
||||
* ActionMailer::Base documentation rewrite. Closes #4991 [Kevin Clark, Marcel Molina Jr.]
|
||||
|
||||
* Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
|
||||
* Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
|
||||
|
||||
* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
|
||||
|
||||
@@ -327,7 +323,7 @@
|
||||
|
||||
* Added that deliver_* will now return the email that was sent
|
||||
|
||||
* Added that quoting to UTF-8 only happens if the characters used are in that range #955 [Jamis Buck]
|
||||
* Added that quoting to UTF-8 only happens if the characters used are in that range #955 [Jamis Buck]
|
||||
|
||||
* Fixed quoting for all address headers, not just to #955 [Jamis Buck]
|
||||
|
||||
@@ -366,7 +362,7 @@
|
||||
@body = "Nothing to see here."
|
||||
@charset = "iso-8859-1"
|
||||
end
|
||||
|
||||
|
||||
def unencoded_subject(recipient)
|
||||
@recipients = recipient
|
||||
@subject = "testing unencoded subject"
|
||||
@@ -375,7 +371,7 @@
|
||||
@encode_subject = false
|
||||
@charset = "iso-8859-1"
|
||||
end
|
||||
|
||||
|
||||
|
||||
*0.6.1* (January 18th, 2005)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ are used to consolidate code for sending out forgotten passwords, welcome
|
||||
wishes on signup, invoices for billing, and any other use case that requires
|
||||
a written notification to either a person or another system.
|
||||
|
||||
Action Mailer is in essence a wrapper around Action Controller and the
|
||||
Action Mailer is in essence a wrapper around Action Controller and the
|
||||
Mail gem. It provides a way to make emails using templates in the same
|
||||
way that Action Controller renders views using templates.
|
||||
|
||||
@@ -23,7 +23,7 @@ This can be as simple as:
|
||||
|
||||
class Notifier < ActionMailer::Base
|
||||
delivers_from 'system@loudthinking.com'
|
||||
|
||||
|
||||
def welcome(recipient)
|
||||
@recipient = recipient
|
||||
mail(:to => recipient,
|
||||
@@ -36,13 +36,13 @@ ERb) that has the instance variables that are declared in the mailer action.
|
||||
|
||||
So the corresponding body template for the method above could look like this:
|
||||
|
||||
Hello there,
|
||||
Hello there,
|
||||
|
||||
Mr. <%= @recipient %>
|
||||
|
||||
Thank you for signing up!
|
||||
|
||||
And if the recipient was given as "david@loudthinking.com", the email
|
||||
|
||||
And if the recipient was given as "david@loudthinking.com", the email
|
||||
generated would look like this:
|
||||
|
||||
Date: Mon, 25 Jan 2010 22:48:09 +1100
|
||||
@@ -55,7 +55,7 @@ generated would look like this:
|
||||
charset="US-ASCII";
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
Hello there,
|
||||
Hello there,
|
||||
|
||||
Mr. david@loudthinking.com
|
||||
|
||||
@@ -65,8 +65,8 @@ simply call the method and optionally call +deliver+ on the return value.
|
||||
|
||||
Calling the method returns a Mail Message object:
|
||||
|
||||
message = Notifier.welcome #=> Returns a Mail::Message object
|
||||
message.deliver #=> delivers the email
|
||||
message = Notifier.welcome # => Returns a Mail::Message object
|
||||
message.deliver # => delivers the email
|
||||
|
||||
Or you can just chain the methods together like:
|
||||
|
||||
@@ -75,7 +75,7 @@ Or you can just chain the methods together like:
|
||||
== Receiving emails
|
||||
|
||||
To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes a
|
||||
tmail object as its single parameter. The Action Mailer framework has a corresponding class method,
|
||||
tmail object as its single parameter. The Action Mailer framework has a corresponding class method,
|
||||
which is also called <tt>receive</tt>, that accepts a raw, unprocessed email as a string, which it then turns
|
||||
into the tmail object and calls the receive instance method.
|
||||
|
||||
@@ -90,7 +90,7 @@ Example:
|
||||
|
||||
if email.has_attachments?
|
||||
for attachment in email.attachments
|
||||
page.attachments.create({
|
||||
page.attachments.create({
|
||||
:file => attachment, :description => email.subject
|
||||
})
|
||||
end
|
||||
@@ -98,13 +98,13 @@ Example:
|
||||
end
|
||||
end
|
||||
|
||||
This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the
|
||||
This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the
|
||||
trivial case like this:
|
||||
|
||||
rails runner 'Mailman.receive(STDIN.read)'
|
||||
|
||||
However, invoking Rails in the runner for each mail to be received is very resource intensive. A single
|
||||
instance of Rails should be run within a daemon if it is going to be utilized to process more than just
|
||||
However, invoking Rails in the runner for each mail to be received is very resource intensive. A single
|
||||
instance of Rails should be run within a daemon if it is going to be utilized to process more than just
|
||||
a limited number of email.
|
||||
|
||||
== Configuration
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
gem 'rdoc', '>= 2.5.9'
|
||||
require 'rdoc'
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rdoc/task'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
|
||||
@@ -25,19 +22,6 @@ namespace :test do
|
||||
end
|
||||
end
|
||||
|
||||
# Generate the RDoc documentation
|
||||
RDoc::Task.new { |rdoc|
|
||||
rdoc.rdoc_dir = 'doc'
|
||||
rdoc.title = "Action Mailer -- Easy email delivery and testing"
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.options << '-f' << 'horo'
|
||||
rdoc.options << '--main' << 'README.rdoc'
|
||||
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include('lib/action_mailer.rb')
|
||||
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
|
||||
rdoc.rdoc_files.include('lib/action_mailer/delivery_method/*.rb')
|
||||
}
|
||||
|
||||
spec = eval(File.read('actionmailer.gemspec'))
|
||||
|
||||
Rake::GemPackageTask.new(spec) do |p|
|
||||
|
||||
@@ -20,5 +20,5 @@ Gem::Specification.new do |s|
|
||||
s.has_rdoc = true
|
||||
|
||||
s.add_dependency('actionpack', version)
|
||||
s.add_dependency('mail', '~> 2.2.5')
|
||||
s.add_dependency('mail', '~> 2.2.9')
|
||||
end
|
||||
|
||||
@@ -26,6 +26,7 @@ $:.unshift(actionpack_path) if File.directory?(actionpack_path) && !$:.include?(
|
||||
|
||||
require 'abstract_controller'
|
||||
require 'action_view'
|
||||
require 'action_mailer/version'
|
||||
|
||||
# Common Active Support usage in Action Mailer
|
||||
require 'active_support/core_ext/class'
|
||||
|
||||
@@ -187,31 +187,31 @@ module ActionMailer #:nodoc:
|
||||
# with the filename +free_book.pdf+.
|
||||
#
|
||||
# = Inline Attachments
|
||||
#
|
||||
# You can also specify that a file should be displayed inline with other HTML. This is useful
|
||||
#
|
||||
# You can also specify that a file should be displayed inline with other HTML. This is useful
|
||||
# if you want to display a corporate logo or a photo.
|
||||
#
|
||||
#
|
||||
# class ApplicationMailer < ActionMailer::Base
|
||||
# def welcome(recipient)
|
||||
# attachments.inline['photo.png'] = File.read('path/to/photo.png')
|
||||
# mail(:to => recipient, :subject => "Here is what we look like")
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
# And then to reference the image in the view, you create a <tt>welcome.html.erb</tt> file and
|
||||
# make a call to +image_tag+ passing in the attachment you want to display and then call
|
||||
# make a call to +image_tag+ passing in the attachment you want to display and then call
|
||||
# +url+ on the attachment to get the relative content id path for the image source:
|
||||
#
|
||||
#
|
||||
# <h1>Please Don't Cringe</h1>
|
||||
#
|
||||
#
|
||||
# <%= image_tag attachments['photo.png'].url -%>
|
||||
#
|
||||
#
|
||||
# As we are using Action View's +image_tag+ method, you can pass in any other options you want:
|
||||
#
|
||||
#
|
||||
# <h1>Please Don't Cringe</h1>
|
||||
#
|
||||
#
|
||||
# <%= image_tag attachments['photo.png'].url, :alt => 'Our Photo', :class => 'photo' -%>
|
||||
#
|
||||
#
|
||||
# = Observing and Intercepting Mails
|
||||
#
|
||||
# Action Mailer provides hooks into the Mail observer and interceptor methods. These allow you to
|
||||
@@ -446,6 +446,33 @@ module ActionMailer #:nodoc:
|
||||
super
|
||||
end
|
||||
|
||||
class DeprecatedHeaderProxy < ActiveSupport::BasicObject
|
||||
def initialize(message)
|
||||
@message = message
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
unless value.is_a?(::String)
|
||||
::ActiveSupport::Deprecation.warn("Using a non-String object for a header's value is deprecated. " \
|
||||
"You specified #{value.inspect} (a #{value.class}) for #{key}", caller)
|
||||
|
||||
value = value.to_s
|
||||
end
|
||||
|
||||
@message[key] = value
|
||||
end
|
||||
|
||||
def headers(hash = {})
|
||||
hash.each_pair do |k,v|
|
||||
self[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
def method_missing(meth, *args, &block)
|
||||
@message.send(meth, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
# Allows you to pass random and unusual headers to the new +Mail::Message+ object
|
||||
# which will add them to itself.
|
||||
#
|
||||
@@ -462,9 +489,9 @@ module ActionMailer #:nodoc:
|
||||
# X-Special-Domain-Specific-Header: SecretValue
|
||||
def headers(args=nil)
|
||||
if args
|
||||
@_message.headers(args)
|
||||
DeprecatedHeaderProxy.new(@_message).headers(args)
|
||||
else
|
||||
@_message
|
||||
DeprecatedHeaderProxy.new(@_message)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -46,11 +46,11 @@ module ActionMailer
|
||||
# as alias and the default options supplied:
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
#
|
||||
# add_delivery_method :sendmail, Mail::Sendmail,
|
||||
# :location => '/usr/sbin/sendmail',
|
||||
# :arguments => '-i -t'
|
||||
#
|
||||
#
|
||||
def add_delivery_method(symbol, klass, default_options={})
|
||||
class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")
|
||||
send(:"#{symbol}_settings=", default_options)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'active_support/core_ext/object/try'
|
||||
|
||||
module ActionMailer
|
||||
# This is the API which is deprecated and is going to be removed on Rails 3.1 release.
|
||||
# Part of the old API will be deprecated after 3.1, for a smoother deprecation process.
|
||||
@@ -94,6 +96,12 @@ module ActionMailer
|
||||
def render(*args)
|
||||
options = args.last.is_a?(Hash) ? args.last : {}
|
||||
|
||||
if file = options[:file] and !file.index("/")
|
||||
ActiveSupport::Deprecation.warn("render :file is deprecated except for absolute paths. " \
|
||||
"Please use render :template instead")
|
||||
options[:prefix] = _prefix
|
||||
end
|
||||
|
||||
if options[:body].is_a?(Hash)
|
||||
ActiveSupport::Deprecation.warn(':body in render deprecated. Please use instance ' <<
|
||||
'variables as assigns instead', caller[0,1])
|
||||
|
||||
@@ -15,11 +15,11 @@ module ActionMailer
|
||||
:columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
|
||||
).format
|
||||
}.join("\n")
|
||||
|
||||
|
||||
# Make list points stand on their own line
|
||||
formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
|
||||
formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
|
||||
|
||||
|
||||
formatted
|
||||
end
|
||||
|
||||
|
||||
@@ -116,36 +116,36 @@ module ActionMailer
|
||||
|
||||
def normalize_nonfile_hash(params)
|
||||
content_disposition = "attachment;"
|
||||
|
||||
|
||||
mime_type = params.delete(:mime_type)
|
||||
|
||||
|
||||
if content_type = params.delete(:content_type)
|
||||
content_type = "#{mime_type || content_type};"
|
||||
end
|
||||
|
||||
params[:body] = params.delete(:data) if params[:data]
|
||||
|
||||
{ :content_type => content_type,
|
||||
:content_disposition => content_disposition }.merge(params)
|
||||
end
|
||||
|
||||
def normalize_file_hash(params)
|
||||
filename = File.basename(params.delete(:filename))
|
||||
content_disposition = "attachment; filename=\"#{File.basename(filename)}\""
|
||||
|
||||
mime_type = params.delete(:mime_type)
|
||||
|
||||
if (content_type = params.delete(:content_type)) && (content_type !~ /filename=/)
|
||||
content_type = "#{mime_type || content_type}; filename=\"#{filename}\""
|
||||
end
|
||||
|
||||
params[:body] = params.delete(:data) if params[:data]
|
||||
|
||||
|
||||
{ :content_type => content_type,
|
||||
:content_disposition => content_disposition }.merge(params)
|
||||
end
|
||||
|
||||
def create_mail
|
||||
def normalize_file_hash(params)
|
||||
filename = File.basename(params.delete(:filename))
|
||||
content_disposition = "attachment; filename=\"#{File.basename(filename)}\""
|
||||
|
||||
mime_type = params.delete(:mime_type)
|
||||
|
||||
if (content_type = params.delete(:content_type)) && (content_type !~ /filename=/)
|
||||
content_type = "#{mime_type || content_type}; filename=\"#{filename}\""
|
||||
end
|
||||
|
||||
params[:body] = params.delete(:data) if params[:data]
|
||||
|
||||
{ :content_type => content_type,
|
||||
:content_disposition => content_disposition }.merge(params)
|
||||
end
|
||||
|
||||
def create_mail
|
||||
m = @_message
|
||||
|
||||
set_fields!({:subject => subject, :to => recipients, :from => from,
|
||||
@@ -178,14 +178,14 @@ module ActionMailer
|
||||
|
||||
wrap_delivery_behavior!
|
||||
m.content_transfer_encoding = '8bit' unless m.body.only_us_ascii?
|
||||
|
||||
|
||||
@_message
|
||||
end
|
||||
|
||||
|
||||
# Set up the default values for the various instance variables of this
|
||||
# mailer. Subclasses may override this method to provide different
|
||||
# defaults.
|
||||
def initialize_defaults(method_name)
|
||||
def initialize_defaults(method_name)
|
||||
@charset ||= self.class.default[:charset].try(:dup)
|
||||
@content_type ||= self.class.default[:content_type].try(:dup)
|
||||
@implicit_parts_order ||= self.class.default[:parts_order].try(:dup)
|
||||
@@ -201,7 +201,7 @@ module ActionMailer
|
||||
@body ||= {}
|
||||
end
|
||||
|
||||
def create_parts
|
||||
def create_parts
|
||||
if String === @body
|
||||
@parts.unshift create_inline_part(@body)
|
||||
elsif @parts.empty? || @parts.all? { |p| p.content_disposition =~ /^attachment/ }
|
||||
@@ -220,7 +220,7 @@ module ActionMailer
|
||||
end
|
||||
end
|
||||
|
||||
def create_inline_part(body, mime_type=nil)
|
||||
def create_inline_part(body, mime_type=nil)
|
||||
ct = mime_type || "text/plain"
|
||||
main_type, sub_type = split_content_type(ct.to_s)
|
||||
|
||||
@@ -242,11 +242,11 @@ module ActionMailer
|
||||
m.reply_to ||= headers.delete(:reply_to) if headers[:reply_to]
|
||||
end
|
||||
|
||||
def split_content_type(ct)
|
||||
def split_content_type(ct)
|
||||
ct.to_s.split("/")
|
||||
end
|
||||
|
||||
def parse_content_type(defaults=nil)
|
||||
def parse_content_type(defaults=nil)
|
||||
if @content_type.blank?
|
||||
[ nil, {} ]
|
||||
else
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
module Mail
|
||||
class Message
|
||||
|
||||
|
||||
def set_content_type(*args)
|
||||
ActiveSupport::Deprecation.warn('Message#set_content_type is deprecated, please just call ' <<
|
||||
'Message#content_type with the same arguments', caller[0,2])
|
||||
content_type(*args)
|
||||
end
|
||||
|
||||
|
||||
alias :old_transfer_encoding :transfer_encoding
|
||||
def transfer_encoding(value = nil)
|
||||
if value
|
||||
@@ -29,6 +29,6 @@ module Mail
|
||||
'please call Message#filename', caller[0,2])
|
||||
filename
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
@@ -2,9 +2,8 @@ module ActionMailer
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "rc"
|
||||
TINY = 2
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ class <%= class_name %> < ActionMailer::Base
|
||||
# Subject can be set in your I18n file at config/locales/en.yml
|
||||
# with the following lookup:
|
||||
#
|
||||
# en.<%= file_name %>.<%= action %>.subject
|
||||
# en.<%= file_path.gsub("/",".") %>.<%= action %>.subject
|
||||
#
|
||||
def <%= action %>
|
||||
@greeting = "Hi"
|
||||
|
||||
@@ -11,8 +11,18 @@ ensure
|
||||
$VERBOSE = old
|
||||
end
|
||||
|
||||
|
||||
require 'active_support/core_ext/kernel/reporting'
|
||||
|
||||
require 'active_support/core_ext/string/encoding'
|
||||
if "ruby".encoding_aware?
|
||||
# These are the normal settings that will be set up by Railties
|
||||
# TODO: Have these tests support other combinations of these values
|
||||
silence_warnings do
|
||||
Encoding.default_internal = "UTF-8"
|
||||
Encoding.default_external = "UTF-8"
|
||||
end
|
||||
end
|
||||
|
||||
silence_warnings do
|
||||
# These external dependencies have warnings :/
|
||||
require 'text/format'
|
||||
@@ -67,4 +77,4 @@ end
|
||||
|
||||
def restore_delivery_method
|
||||
ActionMailer::Base.delivery_method = @old_delivery_method
|
||||
end
|
||||
end
|
||||
|
||||
@@ -76,6 +76,11 @@ class BaseTest < ActiveSupport::TestCase
|
||||
assert_equal("Not SPAM", email['X-SPAM'].decoded)
|
||||
end
|
||||
|
||||
test "deprecated non-String custom headers" do
|
||||
email = assert_deprecated { BaseMailer.welcome_with_fixnum_header }
|
||||
assert_equal("2", email['X-SPAM-COUNT'].decoded)
|
||||
end
|
||||
|
||||
test "can pass random headers in as a hash to mail" do
|
||||
hash = {'X-Special-Domain-Specific-Header' => "SecretValue",
|
||||
'In-Reply-To' => '1234@mikel.me.com' }
|
||||
@@ -148,7 +153,7 @@ class BaseTest < ActiveSupport::TestCase
|
||||
assert_equal("application/pdf", email.parts[1].mime_type)
|
||||
assert_equal("VGhpcyBpcyB0ZXN0IEZpbGUgY29udGVudA==\r\n", email.parts[1].body.encoded)
|
||||
end
|
||||
|
||||
|
||||
test "can embed an inline attachment" do
|
||||
email = BaseMailer.inline_attachment
|
||||
# Need to call #encoded to force the JIT sort on parts
|
||||
@@ -209,6 +214,12 @@ class BaseTest < ActiveSupport::TestCase
|
||||
assert_equal "New Subject!", email.subject
|
||||
end
|
||||
|
||||
test "translations are scoped properly" do
|
||||
I18n.backend.store_translations('en', :base_mailer => {:email_with_translations => {:greet_user => "Hello %{name}!"}})
|
||||
email = BaseMailer.email_with_translations
|
||||
assert_equal 'Hello lifo!', email.body.encoded
|
||||
end
|
||||
|
||||
# Implicit multipart
|
||||
test "implicit multipart" do
|
||||
email = BaseMailer.implicit_multipart
|
||||
@@ -413,7 +424,7 @@ class BaseTest < ActiveSupport::TestCase
|
||||
BaseMailer.welcome.deliver
|
||||
assert_equal(1, BaseMailer.deliveries.length)
|
||||
end
|
||||
|
||||
|
||||
test "calling deliver, ActionMailer should yield back to mail to let it call :do_delivery on itself" do
|
||||
mail = Mail::Message.new
|
||||
mail.expects(:do_delivery).once
|
||||
@@ -428,6 +439,13 @@ class BaseTest < ActiveSupport::TestCase
|
||||
assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded)
|
||||
end
|
||||
|
||||
test "render :file uses render :template semantics and is deprecated" do
|
||||
mail = nil
|
||||
assert_deprecated { mail = BaseMailer.implicit_different_template_with_file('implicit_multipart').deliver }
|
||||
assert_equal("HTML Implicit Multipart", mail.html_part.body.decoded)
|
||||
assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded)
|
||||
end
|
||||
|
||||
test "you can specify a different template for explicit render" do
|
||||
mail = BaseMailer.explicit_different_template('explicit_multipart_templates').deliver
|
||||
assert_equal("HTML Explicit Multipart Templates", mail.html_part.body.decoded)
|
||||
@@ -447,7 +465,7 @@ class BaseTest < ActiveSupport::TestCase
|
||||
mail = BaseMailer.welcome_from_another_path(['unknown/invalid', 'another.path/base_mailer']).deliver
|
||||
assert_equal("Welcome from another path", mail.body.encoded)
|
||||
end
|
||||
|
||||
|
||||
test "assets tags should use ActionMailer's asset_host settings" do
|
||||
ActionMailer::Base.config.asset_host = "http://global.com"
|
||||
ActionMailer::Base.config.assets_dir = "global/"
|
||||
@@ -456,7 +474,7 @@ class BaseTest < ActiveSupport::TestCase
|
||||
|
||||
assert_equal(%{<img alt="Dummy" src="http://global.com/images/dummy.png" />}, mail.body.to_s.strip)
|
||||
end
|
||||
|
||||
|
||||
test "assets tags should use a Mailer's asset_host settings when available" do
|
||||
ActionMailer::Base.config.asset_host = "global.com"
|
||||
ActionMailer::Base.config.assets_dir = "global/"
|
||||
@@ -469,12 +487,12 @@ class BaseTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
# Before and After hooks
|
||||
|
||||
|
||||
class MyObserver
|
||||
def self.delivered_email(mail)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
test "you can register an observer to the mail object that gets informed on email delivery" do
|
||||
ActionMailer::Base.register_observer(MyObserver)
|
||||
mail = BaseMailer.welcome
|
||||
@@ -493,7 +511,7 @@ class BaseTest < ActiveSupport::TestCase
|
||||
MyInterceptor.expects(:delivering_email).with(mail)
|
||||
mail.deliver
|
||||
end
|
||||
|
||||
|
||||
test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do
|
||||
mail1 = ProcMailer.welcome
|
||||
yesterday = 1.day.ago
|
||||
@@ -501,12 +519,24 @@ class BaseTest < ActiveSupport::TestCase
|
||||
mail2 = ProcMailer.welcome
|
||||
assert(mail1['X-Proc-Method'].to_s.to_i > mail2['X-Proc-Method'].to_s.to_i)
|
||||
end
|
||||
|
||||
|
||||
test "we can call other defined methods on the class as needed" do
|
||||
mail = ProcMailer.welcome
|
||||
assert_equal("Thanks for signing up this afternoon", mail.subject)
|
||||
end
|
||||
|
||||
test "action methods should be refreshed after defining new method" do
|
||||
class FooMailer < ActionMailer::Base
|
||||
# this triggers action_methods
|
||||
self.respond_to?(:foo)
|
||||
|
||||
def notify
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal ["notify"], FooMailer.action_methods
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Execute the block setting the given values and restoring old values after
|
||||
|
||||
@@ -128,7 +128,7 @@ class MailDeliveryTest < ActiveSupport::TestCase
|
||||
Mail::Message.any_instance.expects(:deliver!).never
|
||||
DeliveryMailer.welcome.deliver
|
||||
end
|
||||
|
||||
|
||||
test "does not append the deliveries collection if told not to perform the delivery" do
|
||||
DeliveryMailer.perform_deliveries = false
|
||||
DeliveryMailer.deliveries.clear
|
||||
@@ -160,7 +160,7 @@ class MailDeliveryTest < ActiveSupport::TestCase
|
||||
DeliveryMailer.welcome.deliver
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
test "does not increment the deliveries collection on bogus deliveries" do
|
||||
DeliveryMailer.delivery_method = BogusDelivery
|
||||
DeliveryMailer.raise_delivery_errors = false
|
||||
@@ -168,5 +168,5 @@ class MailDeliveryTest < ActiveSupport::TestCase
|
||||
DeliveryMailer.welcome.deliver
|
||||
assert_equal(0, DeliveryMailer.deliveries.length)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
1
actionmailer/test/fixtures/base_mailer/email_with_translations.html.erb
vendored
Normal file
1
actionmailer/test/fixtures/base_mailer/email_with_translations.html.erb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<%= t('.greet_user', :name => 'lifo') %>
|
||||
2
actionmailer/test/fixtures/raw_email10
vendored
2
actionmailer/test/fixtures/raw_email10
vendored
@@ -15,6 +15,6 @@ Content-Type: text/plain; charset=X-UNKNOWN
|
||||
Test test. Hi. Waving. m
|
||||
|
||||
----------------------------------------------------------------
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Envoyé par le service de messagerie texte de Bell Mobilité.
|
||||
----------------------------------------------------------------
|
||||
|
||||
2
actionmailer/test/fixtures/raw_email2
vendored
2
actionmailer/test/fixtures/raw_email2
vendored
@@ -32,7 +32,7 @@ To: xxxxx xxxx <xxxxx@xxxxxxxxx.com>
|
||||
Subject: Fwd: Signed email causes file attachments
|
||||
In-Reply-To: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="----=_Part_5028_7368284.1115579351471"
|
||||
References: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
|
||||
|
||||
2
actionmailer/test/fixtures/raw_email3
vendored
2
actionmailer/test/fixtures/raw_email3
vendored
@@ -31,7 +31,7 @@ Reply-To: Test Tester <xxxx@xxxx.com>
|
||||
To: xxxx@xxxx.com, xxxx@xxxx.com
|
||||
Subject: Another PDF
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="----=_Part_2192_32400445.1115745999735"
|
||||
X-Virus-Scanned: amavisd-new at textdrive.com
|
||||
|
||||
|
||||
2
actionmailer/test/fixtures/raw_email5
vendored
2
actionmailer/test/fixtures/raw_email5
vendored
@@ -14,6 +14,6 @@ Importance: normal
|
||||
Test test. Hi. Waving. m
|
||||
|
||||
----------------------------------------------------------------
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Envoyé par le service de messagerie texte de Bell Mobilité.
|
||||
----------------------------------------------------------------
|
||||
|
||||
2
actionmailer/test/fixtures/raw_email6
vendored
2
actionmailer/test/fixtures/raw_email6
vendored
@@ -15,6 +15,6 @@ Content-Type: text/plain; charset=us-ascii
|
||||
Test test. Hi. Waving. m
|
||||
|
||||
----------------------------------------------------------------
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Envoyé par le service de messagerie texte de Bell Mobilité.
|
||||
----------------------------------------------------------------
|
||||
|
||||
2
actionmailer/test/fixtures/raw_email8
vendored
2
actionmailer/test/fixtures/raw_email8
vendored
@@ -8,7 +8,7 @@ To: xxxxx xxxx <xxxxx@xxxxxxxxx.com>
|
||||
Subject: Fwd: Signed email causes file attachments
|
||||
In-Reply-To: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="----=_Part_5028_7368284.1115579351471"
|
||||
References: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
|
||||
|
||||
10
actionmailer/test/fixtures/raw_email9
vendored
10
actionmailer/test/fixtures/raw_email9
vendored
@@ -10,19 +10,19 @@ Date: Wed, 23 Feb 2005 18:20:17 -0400
|
||||
From: "xxx xxx" <xxx@xxx.xxx>
|
||||
Message-ID: <4D6AA7EB.6490534@xxx.xxx>
|
||||
To: xxx@xxx.com
|
||||
Subject: Stop adware/spyware once and for all.
|
||||
Subject: Stop adware/spyware once and for all.
|
||||
X-Scanned-By: MIMEDefang 2.11 (www dot roaringpenguin dot com slash mimedefang)
|
||||
|
||||
You are infected with:
|
||||
You are infected with:
|
||||
Ad Ware and Spy Ware
|
||||
|
||||
Get your free scan and removal download now,
|
||||
before it gets any worse.
|
||||
Get your free scan and removal download now,
|
||||
before it gets any worse.
|
||||
|
||||
http://xxx.xxx.info?aid=3D13&?stat=3D4327kdzt
|
||||
|
||||
|
||||
|
||||
|
||||
no more? (you will still be infected)
|
||||
no more? (you will still be infected)
|
||||
http://xxx.xxx.info/discon/?xxx@xxx.com
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Hello there,
|
||||
Hello there,
|
||||
|
||||
Mr. <%= @recipient %>
|
||||
@@ -1,6 +1,6 @@
|
||||
%p Hello there,
|
||||
%p Hello there,
|
||||
|
||||
%p
|
||||
%p
|
||||
Mr.
|
||||
= @recipient
|
||||
from haml
|
||||
@@ -1,6 +1,6 @@
|
||||
%p Hello there,
|
||||
%p Hello there,
|
||||
|
||||
%p
|
||||
%p
|
||||
Mr.
|
||||
= @recipient
|
||||
from haml
|
||||
@@ -1,3 +1,3 @@
|
||||
Hello there,
|
||||
Hello there,
|
||||
|
||||
Mr. <%= @recipient %>
|
||||
@@ -1,4 +1,4 @@
|
||||
Hello there,
|
||||
Hello there,
|
||||
|
||||
Mr. <%= @recipient %>. Please see our greeting at <%= @welcome_url %> <%= welcome_url %>
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@ class BaseMailer < ActionMailer::Base
|
||||
mail({:subject => "The first email on new API!"}.merge!(hash))
|
||||
end
|
||||
|
||||
def welcome_with_fixnum_header(hash = {})
|
||||
headers['X-SPAM-COUNT'] = 2
|
||||
mail({:template_name => "welcome", :subject => "The first email on new API!"}.merge!(hash))
|
||||
end
|
||||
|
||||
def welcome_with_headers(hash = {})
|
||||
headers hash
|
||||
mail
|
||||
@@ -98,6 +103,13 @@ class BaseMailer < ActionMailer::Base
|
||||
mail(:template_name => template_name)
|
||||
end
|
||||
|
||||
def implicit_different_template_with_file(template_name='')
|
||||
mail do |format|
|
||||
format.text { render :file => template_name }
|
||||
format.html { render :file => template_name }
|
||||
end
|
||||
end
|
||||
|
||||
def explicit_different_template(template_name='')
|
||||
mail do |format|
|
||||
format.text { render :template => "#{mailer_name}/#{template_name}" }
|
||||
@@ -111,4 +123,8 @@ class BaseMailer < ActionMailer::Base
|
||||
format.html { render :layout => layout_name }
|
||||
end
|
||||
end
|
||||
|
||||
def email_with_translations
|
||||
body render("email_with_translations.html")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,11 +6,11 @@ class ProcMailer < ActionMailer::Base
|
||||
def welcome
|
||||
mail
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def give_a_greeting
|
||||
"Thanks for signing up this afternoon"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -112,7 +112,7 @@ class RenderHelperTest < Test::Unit::TestCase
|
||||
|
||||
def test_file_template
|
||||
mail = RenderMailer.file_template
|
||||
assert_equal "Hello there, \n\nMr. test@localhost", mail.body.to_s.strip
|
||||
assert_equal "Hello there,\n\nMr. test@localhost", mail.body.to_s.strip
|
||||
end
|
||||
|
||||
def test_rxml_template
|
||||
|
||||
@@ -106,7 +106,7 @@ class TestMailer < ActionMailer::Base
|
||||
cc "Foo áëô îü <extended@example.net>"
|
||||
bcc "Foo áëô îü <extended@example.net>"
|
||||
charset "UTF-8"
|
||||
|
||||
|
||||
body "åœö blah"
|
||||
end
|
||||
|
||||
@@ -359,7 +359,7 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
assert_equal "text/plain", created.parts[0].parts[0].mime_type
|
||||
assert_equal "text/html", created.parts[0].parts[1].mime_type
|
||||
assert_equal "application/octet-stream", created.parts[1].mime_type
|
||||
|
||||
|
||||
end
|
||||
|
||||
def test_nested_parts_with_body
|
||||
@@ -392,14 +392,14 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
expected = new_mail
|
||||
expected.to = @recipient
|
||||
expected.subject = "[Signed up] Welcome #{@recipient}"
|
||||
expected.body = "Hello there, \n\nMr. #{@recipient}"
|
||||
expected.body = "Hello there,\n\nMr. #{@recipient}"
|
||||
expected.from = "system@loudthinking.com"
|
||||
expected.date = Time.now
|
||||
|
||||
created = nil
|
||||
assert_nothing_raised { created = TestMailer.signed_up(@recipient) }
|
||||
assert_not_nil created
|
||||
|
||||
|
||||
expected.message_id = '<123@456>'
|
||||
created.message_id = '<123@456>'
|
||||
|
||||
@@ -420,7 +420,7 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
expected = new_mail
|
||||
expected.to = @recipient
|
||||
expected.subject = "[Signed up] Welcome #{@recipient}"
|
||||
expected.body = "Hello there, \n\nMr. #{@recipient}"
|
||||
expected.body = "Hello there,\n\nMr. #{@recipient}"
|
||||
expected.from = "system@loudthinking.com"
|
||||
expected.date = Time.local(2004, 12, 12)
|
||||
|
||||
@@ -503,7 +503,7 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
delivered = ActionMailer::Base.deliveries.first
|
||||
expected.message_id = '<123@456>'
|
||||
delivered.message_id = '<123@456>'
|
||||
|
||||
|
||||
assert_equal expected.encoded, delivered.encoded
|
||||
end
|
||||
|
||||
@@ -546,10 +546,10 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
created = TestMailer.different_reply_to @recipient
|
||||
end
|
||||
assert_not_nil created
|
||||
|
||||
|
||||
expected.message_id = '<123@456>'
|
||||
created.message_id = '<123@456>'
|
||||
|
||||
|
||||
assert_equal expected.encoded, created.encoded
|
||||
|
||||
assert_nothing_raised do
|
||||
@@ -558,10 +558,10 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
|
||||
delivered = ActionMailer::Base.deliveries.first
|
||||
assert_not_nil delivered
|
||||
|
||||
|
||||
expected.message_id = '<123@456>'
|
||||
delivered.message_id = '<123@456>'
|
||||
|
||||
|
||||
assert_equal expected.encoded, delivered.encoded
|
||||
end
|
||||
|
||||
@@ -581,7 +581,7 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
created = TestMailer.iso_charset @recipient
|
||||
end
|
||||
assert_not_nil created
|
||||
|
||||
|
||||
expected.message_id = '<123@456>'
|
||||
created.message_id = '<123@456>'
|
||||
|
||||
@@ -596,7 +596,7 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
|
||||
expected.message_id = '<123@456>'
|
||||
delivered.message_id = '<123@456>'
|
||||
|
||||
|
||||
assert_equal expected.encoded, delivered.encoded
|
||||
end
|
||||
|
||||
@@ -631,7 +631,7 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||
|
||||
expected.message_id = '<123@456>'
|
||||
delivered.message_id = '<123@456>'
|
||||
|
||||
|
||||
assert_equal expected.encoded, delivered.encoded
|
||||
end
|
||||
|
||||
@@ -761,10 +761,10 @@ EOF
|
||||
|
||||
delivered = ActionMailer::Base.deliveries.first
|
||||
assert_not_nil delivered
|
||||
|
||||
|
||||
expected.message_id = '<123@456>'
|
||||
delivered.message_id = '<123@456>'
|
||||
|
||||
|
||||
assert_equal expected.encoded, delivered.encoded
|
||||
end
|
||||
|
||||
@@ -887,7 +887,7 @@ EOF
|
||||
assert_equal "iso-8859-1", mail.parts[1].charset
|
||||
|
||||
assert_equal "image/jpeg", mail.parts[2].mime_type
|
||||
|
||||
|
||||
assert_equal "attachment", mail.parts[2][:content_disposition].disposition_type
|
||||
assert_equal "foo.jpg", mail.parts[2][:content_disposition].filename
|
||||
assert_equal "foo.jpg", mail.parts[2][:content_type].filename
|
||||
@@ -1005,7 +1005,7 @@ EOF
|
||||
attachment = mail.attachments.last
|
||||
|
||||
expected = "01 Quien Te Dij\212at. Pitbull.mp3"
|
||||
|
||||
|
||||
if expected.respond_to?(:force_encoding)
|
||||
result = attachment.filename.dup
|
||||
expected.force_encoding(Encoding::ASCII_8BIT)
|
||||
|
||||
@@ -31,5 +31,5 @@ class TmailCompatTest < ActiveSupport::TestCase
|
||||
end
|
||||
assert_equal mail.content_transfer_encoding, "base64"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -68,7 +68,7 @@ class ActionMailerUrlTest < ActionMailer::TestCase
|
||||
expected = new_mail
|
||||
expected.to = @recipient
|
||||
expected.subject = "[Signed up] Welcome #{@recipient}"
|
||||
expected.body = "Hello there, \n\nMr. #{@recipient}. Please see our greeting at http://example.com/welcome/greeting http://www.basecamphq.com/welcome\n\n<img alt=\"Somelogo\" src=\"/images/somelogo.png\" />"
|
||||
expected.body = "Hello there,\n\nMr. #{@recipient}. Please see our greeting at http://example.com/welcome/greeting http://www.basecamphq.com/welcome\n\n<img alt=\"Somelogo\" src=\"/images/somelogo.png\" />"
|
||||
expected.from = "system@loudthinking.com"
|
||||
expected.date = Time.local(2004, 12, 12)
|
||||
|
||||
@@ -83,7 +83,7 @@ class ActionMailerUrlTest < ActionMailer::TestCase
|
||||
assert_nothing_raised { UrlTestMailer.signed_up_with_url(@recipient).deliver }
|
||||
assert_not_nil ActionMailer::Base.deliveries.first
|
||||
delivered = ActionMailer::Base.deliveries.first
|
||||
|
||||
|
||||
delivered.message_id = '<123@456>'
|
||||
assert_equal expected.encoded, delivered.encoded
|
||||
end
|
||||
|
||||
@@ -32,7 +32,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||
self.class.determine_default_mailer("NotAMailerTest")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_charset_is_utf_8
|
||||
assert_equal "UTF-8", charset
|
||||
end
|
||||
@@ -44,14 +44,14 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_repeated_assert_emails_calls
|
||||
assert_nothing_raised do
|
||||
assert_emails 1 do
|
||||
TestHelperMailer.test.deliver
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
assert_nothing_raised do
|
||||
assert_emails 2 do
|
||||
TestHelperMailer.test.deliver
|
||||
@@ -59,20 +59,20 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_assert_emails_with_no_block
|
||||
assert_nothing_raised do
|
||||
TestHelperMailer.test.deliver
|
||||
assert_emails 1
|
||||
end
|
||||
|
||||
|
||||
assert_nothing_raised do
|
||||
TestHelperMailer.test.deliver
|
||||
TestHelperMailer.test.deliver
|
||||
assert_emails 3
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_assert_no_emails
|
||||
assert_nothing_raised do
|
||||
assert_no_emails do
|
||||
@@ -80,17 +80,17 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_assert_emails_too_few_sent
|
||||
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||
assert_emails 2 do
|
||||
TestHelperMailer.test.deliver
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
assert_match(/2 .* but 1/, error.message)
|
||||
end
|
||||
|
||||
|
||||
def test_assert_emails_too_many_sent
|
||||
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||
assert_emails 1 do
|
||||
@@ -98,17 +98,17 @@ class TestHelperMailerTest < ActionMailer::TestCase
|
||||
TestHelperMailer.test.deliver
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
assert_match(/1 .* but 2/, error.message)
|
||||
end
|
||||
|
||||
|
||||
def test_assert_no_emails_failure
|
||||
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||
assert_no_emails do
|
||||
TestHelperMailer.test.deliver
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
assert_match(/0 .* but 1/, error.message)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,22 @@
|
||||
*Rails 3.0.0 [release candidate] (July 26th, 2010)*
|
||||
*Rails 3.0.2 (November 15, 2010)*
|
||||
|
||||
* The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson]
|
||||
|
||||
|
||||
*Rails 3.0.1 (October 15, 2010)*
|
||||
|
||||
* No changes.
|
||||
|
||||
|
||||
*Rails 3.0.0 (August 29, 2010)*
|
||||
|
||||
* Symbols and strings in routes should yield the same behavior. Note this may break existing apps that were using symbols with the new routes API [José Valim]
|
||||
|
||||
* Add clear_helpers as a way to clean up all helpers added to this controller, maintaing just the helper with the same name as the controller. [José Valim]
|
||||
|
||||
* Support routing constraints in functional tests. [Andrew White]
|
||||
|
||||
* Add a header that tells Internet Explorer (all versions) to use the best available standards support. [Yehuda Katz]
|
||||
|
||||
* Allow stylesheet/javascript extensions to be changed through railties. [Josh Kalderimis]
|
||||
|
||||
@@ -26,16 +44,13 @@
|
||||
resources :comments
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
You can now use comment_path for /comments/1 instead of post_comment_path for /posts/1/comments/1.
|
||||
|
||||
* Add support for multi-subdomain session by setting cookie host in session cookie so you can share session between www.example.com, example.com and user.example.com. #4818 [Guillermo Álvarez]
|
||||
|
||||
* Removed textilize, textilize_without_paragraph and markdown helpers. [Santiago Pastorino]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 4] (June 8th, 2010)*
|
||||
|
||||
* Remove middleware laziness [José Valim]
|
||||
|
||||
* Make session stores rely on request.cookie_jar and change set_session semantics to return the cookie value instead of a boolean. [José Valim]
|
||||
@@ -52,9 +67,6 @@
|
||||
|
||||
* Changed translate helper so that it doesn’t mark every translation as safe HTML. Only keys with a "_html" suffix and keys named "html" are considered to be safe HTML. All other translations are left untouched. [Craig Davey]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
|
||||
|
||||
* New option :as added to form_for allows to change the object name. The old <% form_for :client, @post %> becomes <% form_for @post, :as => :client %> [spastorino]
|
||||
|
||||
* Removed verify method in controllers. [JV]
|
||||
@@ -89,9 +101,6 @@
|
||||
"HEAD" and #request_method returns "GET" in HEAD requests). This
|
||||
is for compatibility with Rack::Request [YK]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* #concat is now deprecated in favor of using <%= %> helpers [YK]
|
||||
|
||||
* Block helpers now return Strings, so you can use <%= form_for @foo do |f| %>.
|
||||
@@ -110,7 +119,7 @@
|
||||
* ActionDispatch::Request#content_type returns a String to be compatible with
|
||||
Rack::Request. Use #content_mime_type for the Mime::Type instance [YK]
|
||||
|
||||
* Updated Prototype to 1.6.1 and Scriptaculous to 1.8.3 [ML]
|
||||
* Updated Prototype to 1.6.1 and Scriptaculous to 1.8.3 [ML]
|
||||
|
||||
* Change the preferred way that URL helpers are included into a class[YK & CL]
|
||||
|
||||
@@ -120,9 +129,6 @@
|
||||
# for just url_for
|
||||
include Rails.application.router.url_for
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
||||
|
||||
* Fixed that PrototypeHelper#update_page should return html_safe [DHH]
|
||||
|
||||
* Fixed that much of DateHelper wouldn't return html_safe? strings [DHH]
|
||||
@@ -144,7 +150,6 @@
|
||||
|
||||
* Added ActionController::Base#notice/= and ActionController::Base#alert/= as a convenience accessors in both the controller and the view for flash[:notice]/= and flash[:alert]/= [DHH]
|
||||
|
||||
|
||||
* Introduce grouped_collection_select helper. #1249 [Dan Codeape, Erik Ostrom]
|
||||
|
||||
* Make sure javascript_include_tag/stylesheet_link_tag does not append ".js" or ".css" onto external urls. #1664 [Matthew Rudy Jacobs]
|
||||
|
||||
@@ -102,10 +102,10 @@ A short rundown of some of the major features:
|
||||
class WeblogController < ActionController::Base
|
||||
# filters as methods
|
||||
before_filter :authenticate, :cache, :audit
|
||||
|
||||
|
||||
# filter as a proc
|
||||
after_filter { |c| c.response.body = Gzip::compress(c.response.body) }
|
||||
|
||||
|
||||
# class filter
|
||||
after_filter LocalizeFilter
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
== Running with Rake
|
||||
|
||||
The easiest way to run the unit tests is through Rake. The default task runs
|
||||
the entire test suite for all classes. For more information, checkout the
|
||||
the entire test suite for all classes. For more information, checkout the
|
||||
full array of rake tasks with "rake -T"
|
||||
|
||||
Rake can be found at http://rake.rubyforge.org
|
||||
@@ -16,7 +16,7 @@ you can do so with something like:
|
||||
== Dependency on ActiveRecord and database setup
|
||||
|
||||
Test cases in the test/controller/active_record/ directory depend on having
|
||||
activerecord and sqlite installed. If ActiveRecord is not in
|
||||
activerecord and sqlite installed. If ActiveRecord is not in
|
||||
actionpack/../activerecord directory, or the sqlite rubygem is not installed,
|
||||
these tests are skipped.
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
gem 'rdoc', '>= 2.5.9'
|
||||
require 'rdoc'
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rdoc/task'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
|
||||
@@ -36,24 +33,6 @@ Rake::TestTask.new(:test_active_record_integration) do |t|
|
||||
t.test_files = Dir.glob("test/activerecord/*_test.rb")
|
||||
end
|
||||
|
||||
# Genereate the RDoc documentation
|
||||
|
||||
RDoc::Task.new { |rdoc|
|
||||
rdoc.rdoc_dir = 'doc'
|
||||
rdoc.title = "Action Pack -- On rails from request to response"
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.options << '-f' << 'horo'
|
||||
rdoc.options << '--main' << 'README.rdoc'
|
||||
if ENV['DOC_FILES']
|
||||
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
|
||||
else
|
||||
rdoc.rdoc_files.include('README.rdoc', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include(Dir['lib/**/*.rb'] -
|
||||
Dir['lib/*/vendor/**/*.rb'])
|
||||
rdoc.rdoc_files.exclude('lib/actionpack.rb')
|
||||
end
|
||||
}
|
||||
|
||||
spec = eval(File.read('actionpack.gemspec'))
|
||||
|
||||
Rake::GemPackageTask.new(spec) do |p|
|
||||
|
||||
@@ -24,8 +24,8 @@ Gem::Specification.new do |s|
|
||||
s.add_dependency('builder', '~> 2.1.2')
|
||||
s.add_dependency('i18n', '~> 0.4.1')
|
||||
s.add_dependency('rack', '~> 1.2.1')
|
||||
s.add_dependency('rack-test', '~> 0.5.4')
|
||||
s.add_dependency('rack-mount', '~> 0.6.9')
|
||||
s.add_dependency('tzinfo', '~> 0.3.22')
|
||||
s.add_dependency('rack-test', '~> 0.5.6')
|
||||
s.add_dependency('rack-mount', '~> 0.6.13')
|
||||
s.add_dependency('tzinfo', '~> 0.3.23')
|
||||
s.add_dependency('erubis', '~> 2.6.6')
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@ activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
|
||||
require 'action_pack'
|
||||
require 'active_support/concern'
|
||||
require 'active_support/ruby/shim'
|
||||
require 'active_support/dependencies/autoload'
|
||||
require 'active_support/core_ext/class/attribute'
|
||||
|
||||
@@ -6,9 +6,14 @@ module AbstractController
|
||||
class Error < StandardError; end
|
||||
class ActionNotFound < StandardError; end
|
||||
|
||||
# <tt>AbstractController::Base</tt> is a low-level API. Nobody should be
|
||||
# using it directly, and subclasses (like ActionController::Base) are
|
||||
# expected to provide their own +render+ method, since rendering means
|
||||
# different things depending on the context.
|
||||
class Base
|
||||
attr_internal :response_body
|
||||
attr_internal :action_name
|
||||
attr_internal :formats
|
||||
|
||||
include ActiveSupport::Configurable
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
@@ -36,13 +41,12 @@ module AbstractController
|
||||
controller.public_instance_methods(true)
|
||||
end
|
||||
|
||||
# The list of hidden actions to an empty Array. Defaults to an
|
||||
# empty Array. This can be modified by other modules or subclasses
|
||||
# The list of hidden actions to an empty array. Defaults to an
|
||||
# empty array. This can be modified by other modules or subclasses
|
||||
# to specify particular actions as hidden.
|
||||
#
|
||||
# ==== Returns
|
||||
# Array[String]:: An array of method names that should not be
|
||||
# considered actions.
|
||||
# * <tt>array</tt> - An array of method names that should not be considered actions.
|
||||
def hidden_actions
|
||||
[]
|
||||
end
|
||||
@@ -54,8 +58,7 @@ module AbstractController
|
||||
# itself. Finally, #hidden_actions are removed.
|
||||
#
|
||||
# ==== Returns
|
||||
# Array[String]:: A list of all methods that should be considered
|
||||
# actions.
|
||||
# * <tt>array</tt> - A list of all methods that should be considered actions.
|
||||
def action_methods
|
||||
@action_methods ||= begin
|
||||
# All public instance methods of this class, including ancestors
|
||||
@@ -72,15 +75,27 @@ module AbstractController
|
||||
end
|
||||
end
|
||||
|
||||
# action_methods are cached and there is sometimes need to refresh
|
||||
# them. clear_action_methods! allows you to do that, so next time
|
||||
# you run action_methods, they will be recalculated
|
||||
def clear_action_methods!
|
||||
@action_methods = nil
|
||||
end
|
||||
|
||||
# Returns the full controller name, underscored, without the ending Controller.
|
||||
# For instance, MyApp::MyPostsController would return "my_app/my_posts" for
|
||||
# controller_name.
|
||||
#
|
||||
# ==== Returns
|
||||
# String
|
||||
# * <tt>string</tt>
|
||||
def controller_path
|
||||
@controller_path ||= name.sub(/Controller$/, '').underscore unless anonymous?
|
||||
end
|
||||
|
||||
def method_added(name)
|
||||
super
|
||||
clear_action_methods!
|
||||
end
|
||||
end
|
||||
|
||||
abstract!
|
||||
@@ -92,12 +107,12 @@ module AbstractController
|
||||
# ActionNotFound error is raised.
|
||||
#
|
||||
# ==== Returns
|
||||
# self
|
||||
# * <tt>self</tt>
|
||||
def process(action, *args)
|
||||
@_action_name = action_name = action.to_s
|
||||
|
||||
unless action_name = method_for_action(action_name)
|
||||
raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}"
|
||||
raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}"
|
||||
end
|
||||
|
||||
@_response_body = nil
|
||||
@@ -121,10 +136,10 @@ module AbstractController
|
||||
# can be considered an action.
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<String>:: The name of an action to be tested
|
||||
# * <tt>name</tt> - The name of an action to be tested
|
||||
#
|
||||
# ==== Returns
|
||||
# TrueClass, FalseClass
|
||||
# * <tt>TrueClass</tt>, <tt>FalseClass</tt>
|
||||
def action_method?(name)
|
||||
self.class.action_methods.include?(name)
|
||||
end
|
||||
@@ -168,11 +183,11 @@ module AbstractController
|
||||
# returns nil, an ActionNotFound exception will be raised.
|
||||
#
|
||||
# ==== Parameters
|
||||
# action_name<String>:: An action name to find a method name for
|
||||
# * <tt>action_name</tt> - An action name to find a method name for
|
||||
#
|
||||
# ==== Returns
|
||||
# String:: The name of the method that handles the action
|
||||
# nil:: No method name could be found. Raise ActionNotFound.
|
||||
# * <tt>string</tt> - The name of the method that handles the action
|
||||
# * <tt>nil</tt> - No method name could be found. Raise ActionNotFound.
|
||||
def method_for_action(action_name)
|
||||
if action_method?(action_name) then action_name
|
||||
elsif respond_to?(:action_missing, true) then "_handle_action_missing"
|
||||
|
||||
@@ -28,9 +28,8 @@ module AbstractController
|
||||
# a Rails process.
|
||||
#
|
||||
# ==== Options
|
||||
# :only<#to_s>:: The callback should be run only for this action
|
||||
# :except<#to_s>:: The callback should be run for all actions
|
||||
# except this action
|
||||
# * <tt>only</tt> - The callback should be run only for this action
|
||||
# * <tt>except<tt> - The callback should be run for all actions except this action
|
||||
def _normalize_callback_options(options)
|
||||
if only = options[:only]
|
||||
only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ")
|
||||
@@ -45,7 +44,7 @@ module AbstractController
|
||||
# Skip before, after, and around filters matching any of the names
|
||||
#
|
||||
# ==== Parameters
|
||||
# *names<Object>:: A list of valid names that could be used for
|
||||
# * <tt>names</tt> - A list of valid names that could be used for
|
||||
# callbacks. Note that skipping uses Ruby equality, so it's
|
||||
# impossible to skip a callback defined using an anonymous proc
|
||||
# using #skip_filter
|
||||
@@ -60,13 +59,13 @@ module AbstractController
|
||||
# the normalization across several methods that use it.
|
||||
#
|
||||
# ==== Parameters
|
||||
# callbacks<Array[*Object, Hash]>:: A list of callbacks, with an optional
|
||||
# * <tt>callbacks</tt> - An array of callbacks, with an optional
|
||||
# options hash as the last parameter.
|
||||
# block<Proc>:: A proc that should be added to the callbacks.
|
||||
# * <tt>block</tt> - A proc that should be added to the callbacks.
|
||||
#
|
||||
# ==== Block Parameters
|
||||
# name<Symbol>:: The callback to be added
|
||||
# options<Hash>:: A list of options to be used when adding the callback
|
||||
# * <tt>name</tt> - The callback to be added
|
||||
# * <tt>options</tt> - A hash of options to be used when adding the callback
|
||||
def _insert_callbacks(callbacks, block)
|
||||
options = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
|
||||
_normalize_callback_options(options)
|
||||
@@ -82,27 +81,29 @@ module AbstractController
|
||||
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
||||
# Append a before, after or around filter. See _insert_callbacks
|
||||
# for details on the allowed parameters.
|
||||
def #{filter}_filter(*names, &blk)
|
||||
_insert_callbacks(names, blk) do |name, options|
|
||||
set_callback(:process_action, :#{filter}, name, options)
|
||||
end
|
||||
end
|
||||
def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk)
|
||||
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options}
|
||||
options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after}
|
||||
set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before_filter, name, options)
|
||||
end # end
|
||||
end # end
|
||||
|
||||
# Prepend a before, after or around filter. See _insert_callbacks
|
||||
# for details on the allowed parameters.
|
||||
def prepend_#{filter}_filter(*names, &blk)
|
||||
_insert_callbacks(names, blk) do |name, options|
|
||||
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true))
|
||||
end
|
||||
end
|
||||
def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk)
|
||||
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
|
||||
options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after}
|
||||
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
|
||||
end # end
|
||||
end # end
|
||||
|
||||
# Skip a before, after or around filter. See _insert_callbacks
|
||||
# for details on the allowed parameters.
|
||||
def skip_#{filter}_filter(*names, &blk)
|
||||
_insert_callbacks(names, blk) do |name, options|
|
||||
skip_callback(:process_action, :#{filter}, name, options)
|
||||
end
|
||||
end
|
||||
def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk)
|
||||
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
|
||||
skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options)
|
||||
end # end
|
||||
end # end
|
||||
|
||||
# *_filter is the same as append_*_filter
|
||||
alias_method :append_#{filter}_filter, :#{filter}_filter
|
||||
|
||||
@@ -9,6 +9,9 @@ module AbstractController
|
||||
included do
|
||||
class_attribute :_helpers
|
||||
self._helpers = Module.new
|
||||
|
||||
class_attribute :_helper_methods
|
||||
self._helper_methods = Array.new
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
@@ -40,10 +43,13 @@ module AbstractController
|
||||
# <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
|
||||
#
|
||||
# ==== Parameters
|
||||
# meths<Array[#to_s]>:: The name of a method on the controller
|
||||
# * <tt>method[, method]</tt> - A name or names of a method on the controller
|
||||
# to be made available on the view.
|
||||
def helper_method(*meths)
|
||||
meths.flatten.each do |meth|
|
||||
meths.flatten!
|
||||
self._helper_methods += meths
|
||||
|
||||
meths.each do |meth|
|
||||
_helpers.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
|
||||
def #{meth}(*args, &blk)
|
||||
controller.send(%(#{meth}), *args, &blk)
|
||||
@@ -55,8 +61,8 @@ module AbstractController
|
||||
# The +helper+ class method can take a series of helper module names, a block, or both.
|
||||
#
|
||||
# ==== Parameters
|
||||
# *args<Array[Module, Symbol, String, :all]>
|
||||
# block<Block>:: A block defining helper methods
|
||||
# * <tt>*args</tt> - Module, Symbol, String, :all
|
||||
# * <tt>block</tt> - A block defining helper methods
|
||||
#
|
||||
# ==== Examples
|
||||
# When the argument is a module it will be included directly in the template class.
|
||||
@@ -95,12 +101,23 @@ module AbstractController
|
||||
_helpers.module_eval(&block) if block_given?
|
||||
end
|
||||
|
||||
# Clears up all existing helpers in this class, only keeping the helper
|
||||
# with the same name as this class.
|
||||
def clear_helpers
|
||||
inherited_helper_methods = _helper_methods
|
||||
self._helpers = Module.new
|
||||
self._helper_methods = Array.new
|
||||
|
||||
inherited_helper_methods.each { |meth| helper_method meth }
|
||||
default_helper_module! unless anonymous?
|
||||
end
|
||||
|
||||
private
|
||||
# Makes all the (instance) methods in the helper module available to templates
|
||||
# rendered through this controller.
|
||||
#
|
||||
# ==== Parameters
|
||||
# mod<Module>:: The module to include into the current helper module
|
||||
# * <tt>module</tt> - The module to include into the current helper module
|
||||
# for the class
|
||||
def add_template_helper(mod)
|
||||
_helpers.module_eval { include mod }
|
||||
@@ -118,10 +135,10 @@ module AbstractController
|
||||
# are returned.
|
||||
#
|
||||
# ==== Parameters
|
||||
# args<Array[String, Symbol, Module]>:: A list of helpers
|
||||
# * <tt>args</tt> - An array of helpers
|
||||
#
|
||||
# ==== Returns
|
||||
# Array[Module]:: A normalized list of modules for the list of
|
||||
# * <tt>Array</tt> - A normalized list of modules for the list of
|
||||
# helpers provided.
|
||||
def modules_for_helpers(args)
|
||||
args.flatten.map! do |arg|
|
||||
|
||||
@@ -114,11 +114,13 @@ module AbstractController
|
||||
#
|
||||
# class WeblogController < ActionController::Base
|
||||
# layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }
|
||||
# end
|
||||
#
|
||||
# Of course, the most common way of specifying a layout is still just as a plain template name:
|
||||
#
|
||||
# class WeblogController < ActionController::Base
|
||||
# layout "weblog_standard"
|
||||
# end
|
||||
#
|
||||
# If no directory is specified for the template name, the template will by default be looked for in <tt>app/views/layouts/</tt>.
|
||||
# Otherwise, it will be looked up relative to the template root.
|
||||
@@ -183,7 +185,7 @@ module AbstractController
|
||||
# layout.
|
||||
#
|
||||
# ==== Returns
|
||||
# Boolean:: True if the action has a layout, false otherwise.
|
||||
# * <tt> Boolean</tt> - True if the action has a layout, false otherwise.
|
||||
def action_has_layout?
|
||||
return unless super
|
||||
|
||||
@@ -209,11 +211,11 @@ module AbstractController
|
||||
# true:: raise an ArgumentError
|
||||
#
|
||||
# ==== Parameters
|
||||
# layout<String, Symbol, false)>:: The layout to use.
|
||||
# * <tt>String, Symbol, false</tt> - The layout to use.
|
||||
#
|
||||
# ==== Options (conditions)
|
||||
# :only<#to_s, Array[#to_s]>:: A list of actions to apply this layout to.
|
||||
# :except<#to_s, Array[#to_s]>:: Apply this layout to all actions but this one
|
||||
# * :only - A list of actions to apply this layout to.
|
||||
# * :except - Apply this layout to all actions but this one.
|
||||
def layout(layout, conditions = {})
|
||||
include LayoutConditions unless conditions.empty?
|
||||
|
||||
@@ -228,7 +230,7 @@ module AbstractController
|
||||
# value of this method.
|
||||
#
|
||||
# ==== Returns
|
||||
# String:: A template name
|
||||
# * <tt>String</tt> - A template name
|
||||
def _implied_layout_name
|
||||
controller_path
|
||||
end
|
||||
@@ -313,8 +315,8 @@ module AbstractController
|
||||
# the name type.
|
||||
#
|
||||
# ==== Parameters
|
||||
# name<String|TrueClass|FalseClass|Symbol>:: The name of the template
|
||||
# details<Hash{Symbol => Object}>:: A list of details to restrict
|
||||
# * <tt>name</tt> - The name of the template
|
||||
# * <tt>details</tt> - A list of details to restrict
|
||||
# the lookup to. By default, layout lookup is limited to the
|
||||
# formats specified for the current request.
|
||||
def _layout_for_option(name)
|
||||
@@ -333,14 +335,14 @@ module AbstractController
|
||||
# Optionally raises an exception if the layout could not be found.
|
||||
#
|
||||
# ==== Parameters
|
||||
# details<Hash>:: A list of details to restrict the search by. This
|
||||
# * <tt>details</tt> - A list of details to restrict the search by. This
|
||||
# might include details like the format or locale of the template.
|
||||
# require_layout<Boolean>:: If this is true, raise an ArgumentError
|
||||
# * <tt>require_logout</tt> - If this is true, raise an ArgumentError
|
||||
# with details about the fact that the exception could not be
|
||||
# found (defaults to false)
|
||||
#
|
||||
# ==== Returns
|
||||
# Template:: The template object for the default layout (or nil)
|
||||
# * <tt>template</tt> - The template object for the default layout (or nil)
|
||||
def _default_layout(require_layout = false)
|
||||
begin
|
||||
layout_name = _layout if action_has_layout?
|
||||
|
||||
@@ -47,13 +47,13 @@ module AbstractController
|
||||
@view_context_class ||= begin
|
||||
controller = self
|
||||
Class.new(ActionView::Base) do
|
||||
if controller.respond_to?(:_routes)
|
||||
include controller._routes.url_helpers
|
||||
end
|
||||
|
||||
if controller.respond_to?(:_helpers)
|
||||
include controller._helpers
|
||||
|
||||
if controller.respond_to?(:_routes)
|
||||
include controller._routes.url_helpers
|
||||
end
|
||||
|
||||
# TODO: Fix RJS to not require this
|
||||
self.helpers = controller._helpers
|
||||
end
|
||||
|
||||
@@ -34,9 +34,9 @@ module AbstractController
|
||||
# Append a path to the list of view paths for this controller.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String, ViewPath>:: If a String is provided, it gets converted into
|
||||
# the default view path. You may also provide a custom view path
|
||||
# (see ActionView::ViewPathSet for more information)
|
||||
# * <tt>path</tt> - If a String is provided, it gets converted into
|
||||
# the default view path. You may also provide a custom view path
|
||||
# (see ActionView::ViewPathSet for more information)
|
||||
def append_view_path(path)
|
||||
self.view_paths = view_paths.dup + Array(path)
|
||||
end
|
||||
@@ -44,9 +44,9 @@ module AbstractController
|
||||
# Prepend a path to the list of view paths for this controller.
|
||||
#
|
||||
# ==== Parameters
|
||||
# path<String, ViewPath>:: If a String is provided, it gets converted into
|
||||
# the default view path. You may also provide a custom view path
|
||||
# (see ActionView::ViewPathSet for more information)
|
||||
# * <tt>path</tt> - If a String is provided, it gets converted into
|
||||
# the default view path. You may also provide a custom view path
|
||||
# (see ActionView::ViewPathSet for more information)
|
||||
def prepend_view_path(path)
|
||||
self.view_paths = Array(path) + view_paths.dup
|
||||
end
|
||||
@@ -59,7 +59,7 @@ module AbstractController
|
||||
# Set the view paths.
|
||||
#
|
||||
# ==== Parameters
|
||||
# paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
|
||||
# * <tt>paths</tt> - If a ViewPathSet is provided, use that;
|
||||
# otherwise, process the parameter into a ViewPathSet.
|
||||
def view_paths=(paths)
|
||||
self._view_paths = ActionView::Base.process_view_paths(paths)
|
||||
|
||||
@@ -35,10 +35,11 @@ module ActionController
|
||||
end
|
||||
|
||||
autoload :Dispatcher, 'action_controller/deprecated/dispatcher'
|
||||
autoload :UrlWriter, 'action_controller/deprecated/url_writer'
|
||||
autoload :UrlRewriter, 'action_controller/deprecated/url_writer'
|
||||
autoload :Integration, 'action_controller/deprecated/integration_test'
|
||||
autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
|
||||
autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
|
||||
autoload :UrlWriter, 'action_controller/deprecated'
|
||||
autoload :Routing, 'action_controller/deprecated'
|
||||
autoload :TestCase, 'action_controller/test_case'
|
||||
|
||||
|
||||
@@ -1,6 +1,171 @@
|
||||
require "action_controller/log_subscriber"
|
||||
|
||||
module ActionController
|
||||
# Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed
|
||||
# on request and then either render a template or redirect to another action. An action is defined as a public method
|
||||
# on the controller, which will automatically be made accessible to the web-server through \Rails Routes.
|
||||
#
|
||||
# By default, only the ApplicationController in a \Rails application inherits from <tt>ActionController::Base</tt>. All other
|
||||
# controllers in turn inherit from ApplicationController. This gives you one class to configure things such as
|
||||
# request forgery protection and filtering of sensitive request parameters.
|
||||
#
|
||||
# A sample controller could look like this:
|
||||
#
|
||||
# class PostsController < ApplicationController
|
||||
# def index
|
||||
# @posts = Post.all
|
||||
# end
|
||||
#
|
||||
# def create
|
||||
# @post = Post.create params[:post]
|
||||
# redirect_to posts_path
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Actions, by default, render a template in the <tt>app/views</tt> directory corresponding to the name of the controller and action
|
||||
# after executing code in the action. For example, the +index+ action of the PostsController would render the
|
||||
# template <tt>app/views/posts/index.erb</tt> by default after populating the <tt>@posts</tt> instance variable.
|
||||
#
|
||||
# Unlike index, the create action will not render a template. After performing its main purpose (creating a
|
||||
# new post), it initiates a redirect instead. This redirect works by returning an external
|
||||
# "302 Moved" HTTP response that takes the user to the index action.
|
||||
#
|
||||
# These two methods represent the two basic action archetypes used in Action Controllers. Get-and-show and do-and-redirect.
|
||||
# Most actions are variations of these themes.
|
||||
#
|
||||
# == Requests
|
||||
#
|
||||
# For every request, the router determines the value of the +controller+ and +action+ keys. These determine which controller
|
||||
# and action are called. The remaining request parameters, the session (if one is available), and the full request with
|
||||
# all the HTTP headers are made available to the action through accessor methods. Then the action is performed.
|
||||
#
|
||||
# The full request object is available via the request accessor and is primarily used to query for HTTP headers:
|
||||
#
|
||||
# def server_ip
|
||||
# location = request.env["SERVER_ADDR"]
|
||||
# render :text => "This server hosted at #{location}"
|
||||
# end
|
||||
#
|
||||
# == Parameters
|
||||
#
|
||||
# All request parameters, whether they come from a GET or POST request, or from the URL, are available through the params method
|
||||
# which returns a hash. For example, an action that was performed through <tt>/posts?category=All&limit=5</tt> will include
|
||||
# <tt>{ "category" => "All", "limit" => 5 }</tt> in params.
|
||||
#
|
||||
# It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:
|
||||
#
|
||||
# <input type="text" name="post[name]" value="david">
|
||||
# <input type="text" name="post[address]" value="hyacintvej">
|
||||
#
|
||||
# A request stemming from a form holding these inputs will include <tt>{ "post" => { "name" => "david", "address" => "hyacintvej" } }</tt>.
|
||||
# If the address input had been named "post[address][street]", the params would have included
|
||||
# <tt>{ "post" => { "address" => { "street" => "hyacintvej" } } }</tt>. There's no limit to the depth of the nesting.
|
||||
#
|
||||
# == Sessions
|
||||
#
|
||||
# Sessions allows you to store objects in between requests. This is useful for objects that are not yet ready to be persisted,
|
||||
# such as a Signup object constructed in a multi-paged process, or objects that don't change much and are needed all the time, such
|
||||
# as a User object for a system that requires login. The session should not be used, however, as a cache for objects where it's likely
|
||||
# they could be changed unknowingly. It's usually too much work to keep it all synchronized -- something databases already excel at.
|
||||
#
|
||||
# You can place objects in the session by using the <tt>session</tt> method, which accesses a hash:
|
||||
#
|
||||
# session[:person] = Person.authenticate(user_name, password)
|
||||
#
|
||||
# And retrieved again through the same hash:
|
||||
#
|
||||
# Hello #{session[:person]}
|
||||
#
|
||||
# For removing objects from the session, you can either assign a single key to +nil+:
|
||||
#
|
||||
# # removes :person from session
|
||||
# session[:person] = nil
|
||||
#
|
||||
# or you can remove the entire session with +reset_session+.
|
||||
#
|
||||
# Sessions are stored by default in a browser cookie that's cryptographically signed, but unencrypted.
|
||||
# This prevents the user from tampering with the session but also allows him to see its contents.
|
||||
#
|
||||
# Do not put secret information in cookie-based sessions!
|
||||
#
|
||||
# Other options for session storage:
|
||||
#
|
||||
# * ActiveRecord::SessionStore - Sessions are stored in your database, which works better than PStore with multiple app servers and,
|
||||
# unlike CookieStore, hides your session contents from the user. To use ActiveRecord::SessionStore, set
|
||||
#
|
||||
# config.action_controller.session_store = :active_record_store
|
||||
#
|
||||
# in your <tt>config/environment.rb</tt> and run <tt>rake db:sessions:create</tt>.
|
||||
#
|
||||
# == Responses
|
||||
#
|
||||
# Each action results in a response, which holds the headers and document to be sent to the user's browser. The actual response
|
||||
# object is generated automatically through the use of renders and redirects and requires no user intervention.
|
||||
#
|
||||
# == Renders
|
||||
#
|
||||
# Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering
|
||||
# of a template. Included in the Action Pack is the Action View, which enables rendering of ERb templates. It's automatically configured.
|
||||
# The controller passes objects to the view by assigning instance variables:
|
||||
#
|
||||
# def show
|
||||
# @post = Post.find(params[:id])
|
||||
# end
|
||||
#
|
||||
# Which are then automatically available to the view:
|
||||
#
|
||||
# Title: <%= @post.title %>
|
||||
#
|
||||
# You don't have to rely on the automated rendering. Especially actions that could result in the rendering of different templates will use
|
||||
# the manual rendering methods:
|
||||
#
|
||||
# def search
|
||||
# @results = Search.find(params[:query])
|
||||
# case @results
|
||||
# when 0 then render :action => "no_results"
|
||||
# when 1 then render :action => "show"
|
||||
# when 2..10 then render :action => "show_many"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Read more about writing ERb and Builder templates in ActionView::Base.
|
||||
#
|
||||
# == Redirects
|
||||
#
|
||||
# Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to a database,
|
||||
# we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're going to reuse (and redirect to)
|
||||
# a <tt>show</tt> action that we'll assume has already been created. The code might look like this:
|
||||
#
|
||||
# def create
|
||||
# @entry = Entry.new(params[:entry])
|
||||
# if @entry.save
|
||||
# # The entry was saved correctly, redirect to show
|
||||
# redirect_to :action => 'show', :id => @entry.id
|
||||
# else
|
||||
# # things didn't go so well, do something else
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed.
|
||||
#
|
||||
# Learn more about <tt>redirect_to</tt> and what options you have in ActionController::Redirecting.
|
||||
#
|
||||
# == Calling multiple redirects or renders
|
||||
#
|
||||
# An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:
|
||||
#
|
||||
# def do_something
|
||||
# redirect_to :action => "elsewhere"
|
||||
# render :action => "overthere" # raises DoubleRenderError
|
||||
# end
|
||||
#
|
||||
# If you need to redirect on the condition of something, then be sure to add "and return" to halt execution.
|
||||
#
|
||||
# def do_something
|
||||
# redirect_to(:action => "elsewhere") and return if monkeys.nil?
|
||||
# render :action => "overthere" # won't be called if monkeys is nil
|
||||
# end
|
||||
#
|
||||
class Base < Metal
|
||||
abstract!
|
||||
|
||||
@@ -60,11 +225,11 @@ module ActionController
|
||||
|
||||
def self.inherited(klass)
|
||||
super
|
||||
klass.helper :all
|
||||
klass.helper :all if klass.superclass == ActionController::Base
|
||||
end
|
||||
|
||||
require "action_controller/deprecated/base"
|
||||
ActiveSupport.run_load_hooks(:action_controller, self)
|
||||
end
|
||||
end
|
||||
|
||||
require "action_controller/deprecated/base"
|
||||
|
||||
@@ -81,6 +81,11 @@ module ActionController
|
||||
def session=(value)
|
||||
ActiveSupport::Deprecation.warn "ActionController::Base.session= is deprecated. " <<
|
||||
"Please configure it on your application with config.session_store :cookie_store, :key => '....'", caller
|
||||
|
||||
if secret = value.delete(:secret)
|
||||
Rails.application.config.secret_token = secret
|
||||
end
|
||||
|
||||
if value.delete(:disabled)
|
||||
Rails.application.config.session_store :disabled
|
||||
else
|
||||
@@ -120,9 +125,14 @@ module ActionController
|
||||
|
||||
# This was moved to a plugin
|
||||
def verify(*args)
|
||||
ActiveSupport::Deprecation.warn "verify was removed from Rails and is now available as a plugin. " <<
|
||||
ActiveSupport::Deprecation.warn "verify was removed from Rails and is now available as a plugin. " \
|
||||
"Please install it with `rails plugin install git://github.com/rails/verification.git`.", caller
|
||||
end
|
||||
|
||||
def exempt_from_layout(*)
|
||||
ActiveSupport::Deprecation.warn "exempt_from_layout is no longer needed, because layouts in Rails 3 " \
|
||||
"are restricted to the content-type of the template that was rendered.", caller
|
||||
end
|
||||
end
|
||||
|
||||
extend DeprecatedBehavior
|
||||
|
||||
14
actionpack/lib/action_controller/deprecated/url_writer.rb
Normal file
14
actionpack/lib/action_controller/deprecated/url_writer.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module ActionController
|
||||
module UrlWriter
|
||||
def self.included(klass)
|
||||
ActiveSupport::Deprecation.warn "include ActionController::UrlWriter is deprecated. Instead, " \
|
||||
"include Rails.application.routes.url_helpers"
|
||||
klass.class_eval { include Rails.application.routes.url_helpers }
|
||||
end
|
||||
end
|
||||
|
||||
class UrlRewriter
|
||||
def initialize(*)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,7 +12,7 @@ module ActionController
|
||||
#
|
||||
class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
|
||||
class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
|
||||
def initialize(klass, *args)
|
||||
def initialize(klass, *args, &block)
|
||||
options = args.extract_options!
|
||||
@only = Array(options.delete(:only)).map(&:to_s)
|
||||
@except = Array(options.delete(:except)).map(&:to_s)
|
||||
@@ -112,6 +112,11 @@ module ActionController
|
||||
headers["Location"] = url
|
||||
end
|
||||
|
||||
# basic url_for that can be overridden for more robust functionality
|
||||
def url_for(string)
|
||||
string
|
||||
end
|
||||
|
||||
def status
|
||||
@_status
|
||||
end
|
||||
@@ -147,8 +152,8 @@ module ActionController
|
||||
super
|
||||
end
|
||||
|
||||
def self.use(*args)
|
||||
middleware_stack.use(*args)
|
||||
def self.use(*args, &block)
|
||||
middleware_stack.use(*args, &block)
|
||||
end
|
||||
|
||||
def self.middleware
|
||||
|
||||
@@ -2,8 +2,6 @@ module ActionController
|
||||
module Head
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include ActionController::UrlFor
|
||||
|
||||
# Return a response that has no content (merely headers). The options
|
||||
# argument is interpreted to be a hash of header names and values.
|
||||
# This allows you to easily return a response that consists only of
|
||||
@@ -27,8 +25,8 @@ module ActionController
|
||||
|
||||
self.status = status
|
||||
self.location = url_for(location) if location
|
||||
self.content_type = Mime[formats.first]
|
||||
self.content_type = Mime[formats.first] if formats
|
||||
self.response_body = " "
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -95,12 +95,11 @@ module ActionController
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password or the ha1 digest hash so the framework can appropriately
|
||||
# hash to check the user's credentials. Returning +nil+ will cause authentication to fail.
|
||||
# Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
|
||||
# the password file or database is compromised, the attacker would be able to use the ha1 hash to
|
||||
# authenticate as the user at this +realm+, but would not have the user's password to try using at
|
||||
# other sites.
|
||||
# === Notes
|
||||
#
|
||||
# The +authenticate_or_request_with_http_digest+ block must return the user's password
|
||||
# or the ha1 digest hash so the framework can appropriately hash to check the user's
|
||||
# credentials. Returning +nil+ will cause authentication to fail.
|
||||
#
|
||||
# On shared hosts, Apache sometimes doesn't pass authentication headers to
|
||||
# FCGI instances. If your environment matches this description and you cannot
|
||||
@@ -218,11 +217,10 @@ module ActionController
|
||||
end
|
||||
|
||||
def decode_credentials(header)
|
||||
header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}) do |hash, pair|
|
||||
Hash[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
|
||||
key, value = pair.split('=', 2)
|
||||
hash[key.strip.to_sym] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')
|
||||
hash
|
||||
end
|
||||
[key.strip.to_sym, value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')]
|
||||
end]
|
||||
end
|
||||
|
||||
def authentication_header(controller, realm)
|
||||
@@ -392,11 +390,11 @@ module ActionController
|
||||
end
|
||||
end
|
||||
|
||||
# If token Authorization header is present, call the login procedure with
|
||||
# If token Authorization header is present, call the login procedure with
|
||||
# the present token and options.
|
||||
#
|
||||
# controller - ActionController::Base instance for the current request.
|
||||
# login_procedure - Proc to call if a token is present. The Proc should
|
||||
# login_procedure - Proc to call if a token is present. The Proc should
|
||||
# take 2 arguments:
|
||||
# authenticate(controller) { |token, options| ... }
|
||||
#
|
||||
|
||||
@@ -227,7 +227,7 @@ module ActionController #:nodoc:
|
||||
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
|
||||
|
||||
if response = retrieve_response_from_mimes(&block)
|
||||
options = resources.extract_options!
|
||||
options = resources.size == 1 ? {} : resources.extract_options!
|
||||
options.merge!(:default_response => response)
|
||||
(options.delete(:responder) || self.class.responder).call(self, resources, options)
|
||||
end
|
||||
|
||||
@@ -38,6 +38,9 @@ module ActionController
|
||||
# redirect_to :action=>'atom', :status => :moved_permanently
|
||||
# redirect_to post_url(@post), :status => 301
|
||||
# redirect_to :action=>'atom', :status => 302
|
||||
#
|
||||
# The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an
|
||||
# integer, or a symbol representing the downcased, underscored and symbolized description.
|
||||
#
|
||||
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
|
||||
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
|
||||
@@ -48,8 +51,7 @@ module ActionController
|
||||
# redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
|
||||
# redirect_to { :action=>'atom' }, :alert => "Something serious happened"
|
||||
#
|
||||
# When using <tt>redirect_to :back</tt>, if there is no referrer,
|
||||
# RedirectBackError will be raised. You may specify some fallback
|
||||
# When using <tt>redirect_to :back</tt>, if there is no referrer, RedirectBackError will be raised. You may specify some fallback
|
||||
# behavior for this case by rescuing RedirectBackError.
|
||||
def redirect_to(options = {}, response_status = {}) #:doc:
|
||||
raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
|
||||
|
||||
@@ -71,7 +71,7 @@ module ActionController
|
||||
end
|
||||
|
||||
add :json do |json, options|
|
||||
json = ActiveSupport::JSON.encode(json, options) unless json.respond_to?(:to_str)
|
||||
json = json.to_json(options) unless json.respond_to?(:to_str)
|
||||
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
|
||||
self.content_type ||= Mime::JSON
|
||||
self.response_body = json
|
||||
|
||||
@@ -89,6 +89,8 @@ module ActionController #:nodoc:
|
||||
|
||||
def initialize(controller, resources, options={})
|
||||
@controller = controller
|
||||
@request = @controller.request
|
||||
@format = @controller.formats.first
|
||||
@resource = resources.last
|
||||
@resources = resources
|
||||
@options = options
|
||||
@@ -99,14 +101,6 @@ module ActionController #:nodoc:
|
||||
delegate :head, :render, :redirect_to, :to => :controller
|
||||
delegate :get?, :post?, :put?, :delete?, :to => :request
|
||||
|
||||
def request
|
||||
@request ||= @controller.request
|
||||
end
|
||||
|
||||
def format
|
||||
@format ||= @controller.formats.first
|
||||
end
|
||||
|
||||
# Undefine :to_json and :to_yaml since it's defined on Object
|
||||
undef_method(:to_json) if method_defined?(:to_json)
|
||||
undef_method(:to_yaml) if method_defined?(:to_yaml)
|
||||
@@ -167,6 +161,8 @@ module ActionController #:nodoc:
|
||||
display resource.errors, :status => :unprocessable_entity
|
||||
elsif post?
|
||||
display resource, :status => :created, :location => api_location
|
||||
elsif has_empty_resource_definition?
|
||||
display empty_resource, :status => :ok
|
||||
else
|
||||
head :ok
|
||||
end
|
||||
@@ -227,5 +223,23 @@ module ActionController #:nodoc:
|
||||
def default_action
|
||||
@action ||= ACTIONS_FOR_VERBS[request.request_method_symbol]
|
||||
end
|
||||
|
||||
# Check whether resource needs a specific definition of empty resource to be valid
|
||||
#
|
||||
def has_empty_resource_definition?
|
||||
respond_to?("empty_#{format}_resource")
|
||||
end
|
||||
|
||||
# Delegate to proper empty resource method
|
||||
#
|
||||
def empty_resource
|
||||
send("empty_#{format}_resource")
|
||||
end
|
||||
|
||||
# Return a valid empty JSON resource
|
||||
#
|
||||
def empty_json_resource
|
||||
"{}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,7 +31,7 @@ module ActionController
|
||||
super()
|
||||
@_app = app
|
||||
end
|
||||
|
||||
|
||||
def index
|
||||
call(env)
|
||||
end
|
||||
|
||||
@@ -40,6 +40,13 @@ module ActionController
|
||||
ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
|
||||
end
|
||||
|
||||
def process(*args)
|
||||
@partials = Hash.new(0)
|
||||
@templates = Hash.new(0)
|
||||
@layouts = Hash.new(0)
|
||||
super
|
||||
end
|
||||
|
||||
# Asserts that the request was rendered with the appropriate template file or partials.
|
||||
#
|
||||
# ==== Examples
|
||||
@@ -167,6 +174,7 @@ module ActionController
|
||||
@formats = nil
|
||||
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
|
||||
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
|
||||
@symbolized_path_params = nil
|
||||
@method = @request_method = nil
|
||||
@fullpath = @ip = @remote_ip = nil
|
||||
@env['action_dispatch.request.query_parameters'] = {}
|
||||
@@ -311,7 +319,7 @@ module ActionController
|
||||
def tests(controller_class)
|
||||
self.controller_class = controller_class
|
||||
end
|
||||
|
||||
|
||||
def controller_class=(new_class)
|
||||
prepare_controller_class(new_class) if new_class
|
||||
write_inheritable_attribute(:controller_class, new_class)
|
||||
|
||||
@@ -48,7 +48,7 @@ EOF
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Search the tree for (and return) the first node that matches the given
|
||||
# conditions. The conditions are interpreted differently for different node
|
||||
# types, see HTML::Text#find and HTML::Tag#find.
|
||||
@@ -62,7 +62,7 @@ EOF
|
||||
def find_all(conditions)
|
||||
@root.find_all(conditions)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'strscan'
|
||||
|
||||
module HTML #:nodoc:
|
||||
|
||||
|
||||
class Conditions < Hash #:nodoc:
|
||||
def initialize(hash)
|
||||
super()
|
||||
@@ -38,18 +38,14 @@ module HTML #:nodoc:
|
||||
private
|
||||
|
||||
def keys_to_strings(hash)
|
||||
hash.keys.inject({}) do |h,k|
|
||||
h[k.to_s] = hash[k]
|
||||
h
|
||||
end
|
||||
Hash[hash.keys.map {|k| [k.to_s, hash[k]]}]
|
||||
end
|
||||
|
||||
def keys_to_symbols(hash)
|
||||
hash.keys.inject({}) do |h,k|
|
||||
Hash[hash.keys.map do |k|
|
||||
raise "illegal key #{k.inspect}" unless k.respond_to?(:to_sym)
|
||||
h[k.to_sym] = hash[k]
|
||||
h
|
||||
end
|
||||
[k.to_sym, hash[k]]
|
||||
end]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -57,17 +53,17 @@ module HTML #:nodoc:
|
||||
class Node #:nodoc:
|
||||
# The array of children of this node. Not all nodes have children.
|
||||
attr_reader :children
|
||||
|
||||
|
||||
# The parent node of this node. All nodes have a parent, except for the
|
||||
# root node.
|
||||
attr_reader :parent
|
||||
|
||||
|
||||
# The line number of the input where this node was begun
|
||||
attr_reader :line
|
||||
|
||||
|
||||
# The byte position in the input where this node was begun
|
||||
attr_reader :position
|
||||
|
||||
|
||||
# Create a new node as a child of the given parent.
|
||||
def initialize(parent, line=0, pos=0)
|
||||
@parent = parent
|
||||
@@ -77,9 +73,7 @@ module HTML #:nodoc:
|
||||
|
||||
# Return a textual representation of the node.
|
||||
def to_s
|
||||
s = ""
|
||||
@children.each { |child| s << child.to_s }
|
||||
s
|
||||
@children.join()
|
||||
end
|
||||
|
||||
# Return false (subclasses must override this to provide specific matching
|
||||
@@ -92,7 +86,7 @@ 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|
|
||||
@children.each do |child|
|
||||
node = child.find(conditions)
|
||||
return node if node
|
||||
end
|
||||
@@ -133,7 +127,7 @@ module HTML #:nodoc:
|
||||
|
||||
equivalent
|
||||
end
|
||||
|
||||
|
||||
class <<self
|
||||
def parse(parent, line, pos, content, strict=true)
|
||||
if content !~ /^<\S/
|
||||
@@ -160,11 +154,11 @@ module HTML #:nodoc:
|
||||
|
||||
return CDATA.new(parent, line, pos, scanner.pre_match.gsub(/<!\[CDATA\[/, ''))
|
||||
end
|
||||
|
||||
|
||||
closing = ( scanner.scan(/\//) ? :close : nil )
|
||||
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[\w:-]+/)
|
||||
name.downcase!
|
||||
|
||||
|
||||
unless closing
|
||||
scanner.skip(/\s*/)
|
||||
attributes = {}
|
||||
@@ -191,13 +185,13 @@ module HTML #:nodoc:
|
||||
attributes[attr.downcase] = value
|
||||
scanner.skip(/\s*/)
|
||||
end
|
||||
|
||||
|
||||
closing = ( scanner.scan(/\//) ? :self : nil )
|
||||
end
|
||||
|
||||
|
||||
unless scanner.scan(/\s*>/)
|
||||
if strict
|
||||
raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
|
||||
raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
|
||||
else
|
||||
# throw away all text until we find what we're looking for
|
||||
scanner.skip_until(/>/) or scanner.terminate
|
||||
@@ -212,9 +206,9 @@ module HTML #:nodoc:
|
||||
|
||||
# A node that represents text, rather than markup.
|
||||
class Text < Node #:nodoc:
|
||||
|
||||
|
||||
attr_reader :content
|
||||
|
||||
|
||||
# Creates a new text node as a child of the given parent, with the given
|
||||
# content.
|
||||
def initialize(parent, line, pos, content)
|
||||
@@ -240,7 +234,7 @@ module HTML #:nodoc:
|
||||
def find(conditions)
|
||||
match(conditions) && self
|
||||
end
|
||||
|
||||
|
||||
# Returns non-+nil+ if this node meets the given conditions, or +nil+
|
||||
# otherwise. See the discussion of #find for the valid conditions.
|
||||
def match(conditions)
|
||||
@@ -268,7 +262,7 @@ module HTML #:nodoc:
|
||||
content == node.content
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# A CDATA node is simply a text node with a specialized way of displaying
|
||||
# itself.
|
||||
class CDATA < Text #:nodoc:
|
||||
@@ -281,16 +275,16 @@ module HTML #:nodoc:
|
||||
# closing tag, or a self-closing tag. It has a name, and may have a hash of
|
||||
# attributes.
|
||||
class Tag < Node #:nodoc:
|
||||
|
||||
|
||||
# Either +nil+, <tt>:close</tt>, or <tt>:self</tt>
|
||||
attr_reader :closing
|
||||
|
||||
|
||||
# Either +nil+, or a hash of attributes for this node.
|
||||
attr_reader :attributes
|
||||
|
||||
# The name of this tag.
|
||||
attr_reader :name
|
||||
|
||||
|
||||
# Create a new node as a child of the given parent, using the given content
|
||||
# to describe the node. It will be parsed and the node name, attributes and
|
||||
# closing status extracted.
|
||||
@@ -344,7 +338,7 @@ module HTML #:nodoc:
|
||||
def tag?
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
# Returns +true+ if the node meets any of the given conditions. The
|
||||
# +conditions+ parameter must be a hash of any of the following keys
|
||||
# (all are optional):
|
||||
@@ -404,7 +398,7 @@ module HTML #:nodoc:
|
||||
# node.match :descendant => { :tag => "strong" }
|
||||
#
|
||||
# # test if the node has between 2 and 4 span tags as immediate children
|
||||
# node.match :children => { :count => 2..4, :only => { :tag => "span" } }
|
||||
# node.match :children => { :count => 2..4, :only => { :tag => "span" } }
|
||||
#
|
||||
# # get funky: test to see if the node is a "div", has a "ul" ancestor
|
||||
# # and an "li" parent (with "class" = "enum"), and whether or not it has
|
||||
@@ -439,7 +433,7 @@ module HTML #:nodoc:
|
||||
|
||||
# test children
|
||||
return false unless children.find { |child| child.match(conditions[:child]) } if conditions[:child]
|
||||
|
||||
|
||||
# test ancestors
|
||||
if conditions[:ancestor]
|
||||
return false unless catch :found do
|
||||
@@ -457,13 +451,13 @@ module HTML #:nodoc:
|
||||
child.match(:descendant => conditions[:descendant])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# count children
|
||||
if opts = conditions[:children]
|
||||
matches = children.select do |c|
|
||||
(c.kind_of?(HTML::Tag) and (c.closing == :self or ! c.childless?))
|
||||
end
|
||||
|
||||
|
||||
matches = matches.select { |c| c.match(opts[:only]) } if opts[:only]
|
||||
opts.each do |key, value|
|
||||
next if key == :only
|
||||
@@ -489,24 +483,24 @@ module HTML #:nodoc:
|
||||
self_index = siblings.index(self)
|
||||
|
||||
if conditions[:sibling]
|
||||
return false unless siblings.detect do |s|
|
||||
return false unless siblings.detect do |s|
|
||||
s != self && s.match(conditions[:sibling])
|
||||
end
|
||||
end
|
||||
|
||||
if conditions[:before]
|
||||
return false unless siblings[self_index+1..-1].detect do |s|
|
||||
return false unless siblings[self_index+1..-1].detect do |s|
|
||||
s != self && s.match(conditions[:before])
|
||||
end
|
||||
end
|
||||
|
||||
if conditions[:after]
|
||||
return false unless siblings[0,self_index].detect do |s|
|
||||
return false unless siblings[0,self_index].detect do |s|
|
||||
s != self && s.match(conditions[:after])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
@@ -515,7 +509,7 @@ module HTML #:nodoc:
|
||||
return false unless closing == node.closing && self.name == node.name
|
||||
attributes == node.attributes
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
# Match the given value to the given condition.
|
||||
def match_condition(value, condition)
|
||||
|
||||
@@ -7,11 +7,11 @@ module HTML
|
||||
return text unless sanitizeable?(text)
|
||||
tokenize(text, options).join
|
||||
end
|
||||
|
||||
|
||||
def sanitizeable?(text)
|
||||
!(text.nil? || text.empty? || !text.index("<"))
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def tokenize(text, options)
|
||||
tokenizer = HTML::Tokenizer.new(text)
|
||||
@@ -22,12 +22,12 @@ module HTML
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
|
||||
def process_node(node, result, options)
|
||||
result << node.to_s
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class FullSanitizer < Sanitizer
|
||||
def sanitize(text, options = {})
|
||||
result = super
|
||||
@@ -37,12 +37,12 @@ module HTML
|
||||
# Recurse - handle all dirty nested tags
|
||||
result == text ? result : sanitize(result, options)
|
||||
end
|
||||
|
||||
|
||||
def process_node(node, result, options)
|
||||
result << node.to_s if node.class == HTML::Text
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class LinkSanitizer < FullSanitizer
|
||||
cattr_accessor :included_tags, :instance_writer => false
|
||||
self.included_tags = Set.new(%w(a href))
|
||||
@@ -50,13 +50,13 @@ module HTML
|
||||
def sanitizeable?(text)
|
||||
!(text.nil? || text.empty? || !((text.index("<a") || text.index("<href")) && text.index(">")))
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def process_node(node, result, options)
|
||||
result << node.to_s unless node.is_a?(HTML::Tag) && included_tags.include?(node.name)
|
||||
result << node.to_s unless node.is_a?(HTML::Tag) && included_tags.include?(node.name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class WhiteListSanitizer < Sanitizer
|
||||
[:protocol_separator, :uri_attributes, :allowed_attributes, :allowed_tags, :allowed_protocols, :bad_tags,
|
||||
:allowed_css_properties, :allowed_css_keywords, :shorthand_css_properties].each do |attr|
|
||||
@@ -66,35 +66,35 @@ module HTML
|
||||
# A regular expression of the valid characters used to separate protocols like
|
||||
# the ':' in 'http://foo.com'
|
||||
self.protocol_separator = /:|(�*58)|(p)|(%|%)3A/
|
||||
|
||||
|
||||
# Specifies a Set of HTML attributes that can have URIs.
|
||||
self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc))
|
||||
|
||||
# Specifies a Set of 'bad' tags that the #sanitize helper will remove completely, as opposed
|
||||
# to just escaping harmless tags like <font>
|
||||
self.bad_tags = Set.new(%w(script))
|
||||
|
||||
|
||||
# Specifies the default Set of tags that the #sanitize helper will allow unscathed.
|
||||
self.allowed_tags = Set.new(%w(strong em b i p code pre tt samp kbd var sub
|
||||
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dl dt dd abbr
|
||||
self.allowed_tags = Set.new(%w(strong em b i p code pre tt samp kbd var sub
|
||||
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dl dt dd abbr
|
||||
acronym a img blockquote del ins))
|
||||
|
||||
# Specifies the default Set of html attributes that the #sanitize helper will leave
|
||||
# Specifies the default Set of html attributes that the #sanitize helper will leave
|
||||
# in the allowed tag.
|
||||
self.allowed_attributes = Set.new(%w(href src width height alt cite datetime title class name xml:lang abbr))
|
||||
|
||||
|
||||
# Specifies the default Set of acceptable css properties that #sanitize and #sanitize_css will accept.
|
||||
self.allowed_protocols = Set.new(%w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto
|
||||
self.allowed_protocols = Set.new(%w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto
|
||||
feed svn urn aim rsync tag ssh sftp rtsp afs))
|
||||
|
||||
|
||||
# Specifies the default Set of acceptable css keywords that #sanitize and #sanitize_css will accept.
|
||||
self.allowed_css_properties = Set.new(%w(azimuth background-color border-bottom-color border-collapse
|
||||
border-color border-left-color border-right-color border-top-color clear color cursor direction display
|
||||
self.allowed_css_properties = Set.new(%w(azimuth background-color border-bottom-color border-collapse
|
||||
border-color border-left-color border-right-color border-top-color clear color cursor direction display
|
||||
elevation float font font-family font-size font-style font-variant font-weight height letter-spacing line-height
|
||||
overflow pause pause-after pause-before pitch pitch-range richness speak speak-header speak-numeral speak-punctuation
|
||||
speech-rate stress text-align text-decoration text-indent unicode-bidi vertical-align voice-family volume white-space
|
||||
width))
|
||||
|
||||
|
||||
# Specifies the default Set of acceptable css keywords that #sanitize and #sanitize_css will accept.
|
||||
self.allowed_css_keywords = Set.new(%w(auto aqua black block blue bold both bottom brown center
|
||||
collapse dashed dotted fuchsia gray green !important italic left lime maroon medium none navy normal
|
||||
@@ -118,9 +118,9 @@ module HTML
|
||||
style.scan(/([-\w]+)\s*:\s*([^:;]*)/) do |prop,val|
|
||||
if allowed_css_properties.include?(prop.downcase)
|
||||
clean << prop + ': ' + val + ';'
|
||||
elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)
|
||||
elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)
|
||||
unless val.split().any? do |keyword|
|
||||
!allowed_css_keywords.include?(keyword) &&
|
||||
!allowed_css_keywords.include?(keyword) &&
|
||||
keyword !~ /^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$/
|
||||
end
|
||||
clean << prop + ': ' + val + ';'
|
||||
@@ -146,7 +146,7 @@ module HTML
|
||||
else
|
||||
options[:parent].unshift node.name
|
||||
end
|
||||
|
||||
|
||||
process_attributes_for node, options
|
||||
|
||||
options[:tags].include?(node.name) ? node : nil
|
||||
@@ -154,7 +154,7 @@ module HTML
|
||||
bad_tags.include?(options[:parent].first) ? nil : node.to_s.gsub(/</, "<")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def process_attributes_for(node, options)
|
||||
return unless node.attributes
|
||||
node.attributes.keys.each do |attr_name|
|
||||
@@ -169,7 +169,7 @@ module HTML
|
||||
end
|
||||
|
||||
def contains_bad_protocols?(attr_name, value)
|
||||
uri_attributes.include?(attr_name) &&
|
||||
uri_attributes.include?(attr_name) &&
|
||||
(value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -182,7 +182,7 @@ module HTML
|
||||
# not another using <tt>:not</tt>. For example:
|
||||
# p:not(.post)
|
||||
# Matches all paragraphs that do not have the class <tt>.post</tt>.
|
||||
#
|
||||
#
|
||||
# === Substitution Values
|
||||
#
|
||||
# You can use substitution with identifiers, class names and element values.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'strscan'
|
||||
|
||||
module HTML #:nodoc:
|
||||
|
||||
|
||||
# A simple HTML tokenizer. It simply breaks a stream of text into tokens, where each
|
||||
# token is a string. Each string represents either "text", or an HTML element.
|
||||
#
|
||||
@@ -14,13 +14,13 @@ module HTML #:nodoc:
|
||||
# p token
|
||||
# end
|
||||
class Tokenizer #:nodoc:
|
||||
|
||||
|
||||
# The current (byte) position in the text
|
||||
attr_reader :position
|
||||
|
||||
|
||||
# The current line number
|
||||
attr_reader :line
|
||||
|
||||
|
||||
# Create a new Tokenizer for the given text.
|
||||
def initialize(text)
|
||||
text.encode! if text.encoding_aware?
|
||||
@@ -42,7 +42,7 @@ module HTML #:nodoc:
|
||||
update_current_line(scan_text)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
# Treat the text at the current position as a tag, and scan it. Supports
|
||||
@@ -69,13 +69,13 @@ module HTML #:nodoc:
|
||||
def scan_text
|
||||
"#{@scanner.getch}#{@scanner.scan(/[^<]*/)}"
|
||||
end
|
||||
|
||||
|
||||
# Counts the number of newlines in the text and updates the current line
|
||||
# accordingly.
|
||||
def update_current_line(text)
|
||||
text.scan(/\r?\n/) { @current_line += 1 }
|
||||
end
|
||||
|
||||
|
||||
# Skips over quoted strings, so that less-than and greater-than characters
|
||||
# within the strings are ignored.
|
||||
def consume_quoted_regions
|
||||
@@ -103,5 +103,5 @@ module HTML #:nodoc:
|
||||
text
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -113,10 +113,10 @@ module ActionDispatch
|
||||
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
|
||||
|
||||
def set_conditional_cache_control!
|
||||
control = @cache_control
|
||||
|
||||
return if self["Cache-Control"].present?
|
||||
|
||||
control = @cache_control
|
||||
|
||||
if control.empty?
|
||||
headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
|
||||
elsif @cache_control[:no_cache]
|
||||
|
||||
@@ -32,7 +32,7 @@ module ActionDispatch
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the Mime type for the \format used in the request.
|
||||
# Returns the MIME type for the \format used in the request.
|
||||
#
|
||||
# GET /posts/5.xml | request.format => Mime::XML
|
||||
# GET /posts/5.xhtml | request.format => Mime::HTML
|
||||
|
||||
@@ -109,10 +109,10 @@ module Mime
|
||||
else
|
||||
# keep track of creation order to keep the subsequent sort stable
|
||||
list = []
|
||||
accept_header.split(/,/).each_with_index do |header, index|
|
||||
params, q = header.split(/;\s*q=/)
|
||||
accept_header.split(/,/).each_with_index do |header, index|
|
||||
params, q = header.split(/;\s*q=/)
|
||||
if params
|
||||
params.strip!
|
||||
params.strip!
|
||||
list << AcceptItem.new(index, params, q) unless params.empty?
|
||||
end
|
||||
end
|
||||
@@ -161,20 +161,20 @@ module Mime
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def initialize(string, symbol = nil, synonyms = [])
|
||||
@symbol, @synonyms = symbol, synonyms
|
||||
@string = string
|
||||
end
|
||||
|
||||
|
||||
def to_s
|
||||
@string
|
||||
end
|
||||
|
||||
|
||||
def to_str
|
||||
to_s
|
||||
end
|
||||
|
||||
|
||||
def to_sym
|
||||
@symbol || @string.to_sym
|
||||
end
|
||||
@@ -186,11 +186,11 @@ module Mime
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def ==(mime_type)
|
||||
return false if mime_type.blank?
|
||||
(@synonyms + [ self ]).any? do |synonym|
|
||||
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
|
||||
(@synonyms + [ self ]).any? do |synonym|
|
||||
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ module ActionDispatch
|
||||
alias :params :parameters
|
||||
|
||||
def path_parameters=(parameters) #:nodoc:
|
||||
@env.delete("action_dispatch.request.symbolized_path_parameters")
|
||||
@symbolized_path_params = nil
|
||||
@env.delete("action_dispatch.request.parameters")
|
||||
@env["action_dispatch.request.path_parameters"] = parameters
|
||||
end
|
||||
|
||||
# The same as <tt>path_parameters</tt> with explicitly symbolized keys.
|
||||
def symbolized_path_parameters
|
||||
@env["action_dispatch.request.symbolized_path_parameters"] ||= path_parameters.symbolize_keys
|
||||
@symbolized_path_params ||= path_parameters.symbolize_keys
|
||||
end
|
||||
|
||||
# Returns a hash with the \parameters used to form the \path of the request.
|
||||
|
||||
@@ -4,6 +4,7 @@ require 'strscan'
|
||||
|
||||
require 'active_support/core_ext/hash/indifferent_access'
|
||||
require 'active_support/core_ext/string/access'
|
||||
require 'active_support/inflector'
|
||||
require 'action_dispatch/http/headers'
|
||||
|
||||
module ActionDispatch
|
||||
@@ -15,6 +16,8 @@ module ActionDispatch
|
||||
include ActionDispatch::Http::Upload
|
||||
include ActionDispatch::Http::URL
|
||||
|
||||
LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
|
||||
|
||||
%w[ AUTH_TYPE GATEWAY_INTERFACE
|
||||
PATH_TRANSLATED REMOTE_HOST
|
||||
REMOTE_IDENT REMOTE_USER REMOTE_ADDR
|
||||
@@ -42,8 +45,24 @@ module ActionDispatch
|
||||
@env.key?(key)
|
||||
end
|
||||
|
||||
HTTP_METHODS = %w(get head put post delete options)
|
||||
HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
|
||||
# List of HTTP request methods from the following RFCs:
|
||||
# Hypertext Transfer Protocol -- HTTP/1.1 (http://www.ietf.org/rfc/rfc2616.txt)
|
||||
# HTTP Extensions for Distributed Authoring -- WEBDAV (http://www.ietf.org/rfc/rfc2518.txt)
|
||||
# Versioning Extensions to WebDAV (http://www.ietf.org/rfc/rfc3253.txt)
|
||||
# Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt)
|
||||
# Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt)
|
||||
# Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt)
|
||||
# PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt)
|
||||
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
|
||||
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
|
||||
RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
|
||||
RFC3648 = %w(ORDERPATCH)
|
||||
RFC3744 = %w(ACL)
|
||||
RFC5323 = %w(SEARCH)
|
||||
RFC5789 = %w(PATCH)
|
||||
|
||||
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
|
||||
HTTP_METHOD_LOOKUP = Hash.new { |h, m| h[m] = m.underscore.to_sym if HTTP_METHODS.include?(m) }
|
||||
|
||||
# Returns the HTTP \method that the application should see.
|
||||
# In the case where the \method was overridden by a middleware
|
||||
@@ -231,5 +250,10 @@ module ActionDispatch
|
||||
@env['X_HTTP_AUTHORIZATION'] ||
|
||||
@env['REDIRECT_X_HTTP_AUTHORIZATION']
|
||||
end
|
||||
|
||||
# True if the request came from localhost, 127.0.0.1.
|
||||
def local?
|
||||
LOCALHOST.any? { |local_ip| local_ip === remote_addr && local_ip === remote_ip }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,27 +4,26 @@ require 'active_support/core_ext/object/blank'
|
||||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
|
||||
module ActionDispatch # :nodoc:
|
||||
# Represents an HTTP response generated by a controller action. One can use
|
||||
# an ActionDispatch::Response object to retrieve the current state
|
||||
# of the response, or customize the response. An Response object can
|
||||
# either represent a "real" HTTP response (i.e. one that is meant to be sent
|
||||
# back to the web browser) or a test response (i.e. one that is generated
|
||||
# from integration tests). See CgiResponse and TestResponse, respectively.
|
||||
# Represents an HTTP response generated by a controller action. Use it to
|
||||
# retrieve the current state of the response, or customize the response. It can
|
||||
# either represent a real HTTP response (i.e. one that is meant to be sent
|
||||
# back to the web browser) or a TestResponse (i.e. one that is generated
|
||||
# from integration tests).
|
||||
#
|
||||
# Response is mostly a Ruby on Rails framework implement detail, and
|
||||
# \Response is mostly a Ruby on \Rails framework implementation detail, and
|
||||
# should never be used directly in controllers. Controllers should use the
|
||||
# methods defined in ActionController::Base instead. For example, if you want
|
||||
# to set the HTTP response's content MIME type, then use
|
||||
# ActionControllerBase#headers instead of Response#headers.
|
||||
#
|
||||
# Nevertheless, integration tests may want to inspect controller responses in
|
||||
# more detail, and that's when Response can be useful for application
|
||||
# more detail, and that's when \Response can be useful for application
|
||||
# developers. Integration test methods such as
|
||||
# ActionDispatch::Integration::Session#get and
|
||||
# ActionDispatch::Integration::Session#post return objects of type
|
||||
# TestResponse (which are of course also of type Response).
|
||||
# TestResponse (which are of course also of type \Response).
|
||||
#
|
||||
# For example, the following demo integration "test" prints the body of the
|
||||
# For example, the following demo integration test prints the body of the
|
||||
# controller response to the console:
|
||||
#
|
||||
# class DemoControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
@@ -2,31 +2,27 @@ require 'active_support/core_ext/object/blank'
|
||||
|
||||
module ActionDispatch
|
||||
module Http
|
||||
module UploadedFile
|
||||
def self.extended(object)
|
||||
object.class_eval do
|
||||
attr_accessor :original_path, :content_type
|
||||
alias_method :local_path, :path if method_defined?(:path)
|
||||
end
|
||||
class UploadedFile
|
||||
attr_accessor :original_filename, :content_type, :tempfile, :headers
|
||||
|
||||
def initialize(hash)
|
||||
@original_filename = hash[:filename]
|
||||
@content_type = hash[:type]
|
||||
@headers = hash[:head]
|
||||
@tempfile = hash[:tempfile]
|
||||
raise(ArgumentError, ':tempfile is required') unless @tempfile
|
||||
end
|
||||
|
||||
# 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
|
||||
unless defined? @original_filename
|
||||
@original_filename =
|
||||
unless original_path.blank?
|
||||
if original_path =~ /^(?:.*[:\\\/])?(.*)/m
|
||||
$1
|
||||
else
|
||||
File.basename original_path
|
||||
end
|
||||
end
|
||||
end
|
||||
@original_filename
|
||||
def read(*args)
|
||||
@tempfile.read(*args)
|
||||
end
|
||||
|
||||
def rewind
|
||||
@tempfile.rewind
|
||||
end
|
||||
|
||||
def size
|
||||
@tempfile.size
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,11 +31,7 @@ module ActionDispatch
|
||||
# file upload hash with UploadedFile objects
|
||||
def normalize_parameters(value)
|
||||
if Hash === value && value.has_key?(:tempfile)
|
||||
upload = value[:tempfile]
|
||||
upload.extend(UploadedFile)
|
||||
upload.original_path = value[:filename]
|
||||
upload.content_type = value[:type]
|
||||
upload
|
||||
UploadedFile.new(value)
|
||||
else
|
||||
super
|
||||
end
|
||||
@@ -47,4 +39,4 @@ module ActionDispatch
|
||||
private :normalize_parameters
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
module ActionDispatch
|
||||
module Http
|
||||
module URL
|
||||
# Returns the complete URL used for this request.
|
||||
# Returns the complete \URL used for this request.
|
||||
def url
|
||||
protocol + host_with_port + fullpath
|
||||
end
|
||||
|
||||
# Returns 'https' if this is an SSL request and 'http' otherwise.
|
||||
def scheme
|
||||
ssl? ? 'https' : 'http'
|
||||
end
|
||||
|
||||
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
||||
def protocol
|
||||
ssl? ? 'https://' : 'http://'
|
||||
@@ -53,6 +58,11 @@ module ActionDispatch
|
||||
end
|
||||
end
|
||||
|
||||
# Returns whether this request is using the standard port
|
||||
def standard_port?
|
||||
port == standard_port
|
||||
end
|
||||
|
||||
# Returns a \port suffix like ":8080" if the \port number of this request
|
||||
# is not the default HTTP \port 80 or HTTPS \port 443.
|
||||
def port_string
|
||||
@@ -86,7 +96,7 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
# Returns the request URI, accounting for server idiosyncrasies.
|
||||
# WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
|
||||
# WEBrick includes the full \URL. IIS leaves REQUEST_URI blank.
|
||||
def request_uri
|
||||
ActiveSupport::Deprecation.warn "Using #request_uri is deprecated. Use fullpath instead.", caller
|
||||
fullpath
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
module ActionDispatch
|
||||
class BestStandardsSupport
|
||||
def initialize(app)
|
||||
def initialize(app, type = true)
|
||||
@app = app
|
||||
|
||||
@header = case type
|
||||
when true
|
||||
"IE=Edge,chrome=1"
|
||||
when :builtin
|
||||
"IE=Edge"
|
||||
when false
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, body = @app.call(env)
|
||||
headers["X-UA-Compatible"] = "IE=Edge,chrome=1"
|
||||
headers["X-UA-Compatible"] = @header
|
||||
[status, headers, body]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,7 +7,7 @@ module ActionDispatch
|
||||
end
|
||||
end
|
||||
|
||||
# Cookies are read and written through ActionController#cookies.
|
||||
# \Cookies are read and written through ActionController#cookies.
|
||||
#
|
||||
# The cookies being read are the ones received along with the request, the cookies
|
||||
# being written will be sent out with the response. Reading a cookie does not get
|
||||
@@ -21,6 +21,15 @@ module ActionDispatch
|
||||
# # Sets a cookie that expires in 1 hour.
|
||||
# cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now }
|
||||
#
|
||||
# # Sets a signed cookie, which prevents a user from tampering with its value.
|
||||
# # You must specify a value in ActionController::Base.cookie_verifier_secret.
|
||||
# cookies.signed[:remember_me] = [current_user.id, current_user.salt]
|
||||
#
|
||||
# # Sets a "permanent" cookie (which expires in 20 years from now).
|
||||
# cookies.permanent[:login] = "XJ-122"
|
||||
# # You can also chain these methods:
|
||||
# cookies.permanent.signed[:login] = "XJ-122"
|
||||
#
|
||||
# Examples for reading:
|
||||
#
|
||||
# cookies[:user_name] # => "david"
|
||||
@@ -55,7 +64,7 @@ module ActionDispatch
|
||||
# :domain => :all # Allow the cookie for the top most level
|
||||
# domain and subdomains.
|
||||
#
|
||||
# * <tt>:expires</tt> - The time at which this cookie expires, as a Time object.
|
||||
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
|
||||
# * <tt>:secure</tt> - Whether this cookie is a only transmitted to HTTPS servers.
|
||||
# Default is +false+.
|
||||
# * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
|
||||
@@ -69,27 +78,39 @@ module ActionDispatch
|
||||
|
||||
class CookieJar < Hash #:nodoc:
|
||||
|
||||
# This regular expression is used to split the levels of a domain
|
||||
# So www.example.co.uk gives:
|
||||
# $1 => www.
|
||||
# $2 => example
|
||||
# $3 => co.uk
|
||||
DOMAIN_REGEXP = /^(.*\.)*(.*)\.(...|...\...|....|..\...|..)$/
|
||||
# This regular expression is used to split the levels of a domain.
|
||||
# The top level domain can be any string without a period or
|
||||
# **.**, ***.** style TLDs like co.uk or com.au
|
||||
#
|
||||
# www.example.co.uk gives:
|
||||
# $1 => example
|
||||
# $2 => co.uk
|
||||
#
|
||||
# example.com gives:
|
||||
# $1 => example
|
||||
# $2 => com
|
||||
#
|
||||
# lots.of.subdomains.example.local gives:
|
||||
# $1 => example
|
||||
# $2 => local
|
||||
DOMAIN_REGEXP = /([^.]*)\.([^.]*|..\...|...\...)$/
|
||||
|
||||
def self.build(request)
|
||||
secret = request.env[TOKEN_KEY]
|
||||
host = request.env["HTTP_HOST"]
|
||||
host = request.host
|
||||
secure = request.ssl?
|
||||
|
||||
new(secret, host).tap do |hash|
|
||||
new(secret, host, secure).tap do |hash|
|
||||
hash.update(request.cookies)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(secret = nil, host = nil)
|
||||
def initialize(secret = nil, host = nil, secure = false)
|
||||
@secret = secret
|
||||
@set_cookies = {}
|
||||
@delete_cookies = {}
|
||||
@host = host
|
||||
@secure = secure
|
||||
|
||||
super()
|
||||
end
|
||||
@@ -104,7 +125,7 @@ module ActionDispatch
|
||||
|
||||
if options[:domain] == :all
|
||||
@host =~ DOMAIN_REGEXP
|
||||
options[:domain] = ".#{$2}.#{$3}"
|
||||
options[:domain] = ".#{$1}.#{$2}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -174,9 +195,15 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def write(headers)
|
||||
@set_cookies.each { |k, v| ::Rack::Utils.set_cookie_header!(headers, k, v) }
|
||||
@set_cookies.each { |k, v| ::Rack::Utils.set_cookie_header!(headers, k, v) if write_cookie?(v) }
|
||||
@delete_cookies.each { |k, v| ::Rack::Utils.delete_cookie_header!(headers, k, v) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def write_cookie?(cookie)
|
||||
@secure || !cookie[:secure] || defined?(Rails.env) && Rails.env.development?
|
||||
end
|
||||
end
|
||||
|
||||
class PermanentCookieJar < CookieJar #:nodoc:
|
||||
|
||||
@@ -10,13 +10,13 @@ module ActionDispatch
|
||||
|
||||
# The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed
|
||||
# to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
|
||||
# action that sets <tt>flash[:notice] = "Successfully created"</tt> before redirecting to a display action that can
|
||||
# action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
|
||||
# then expose the flash to its template. Actually, that exposure is automatically done. Example:
|
||||
#
|
||||
# class PostsController < ActionController::Base
|
||||
# def create
|
||||
# # save post
|
||||
# flash[:notice] = "Successfully created post"
|
||||
# flash[:notice] = "Post successfully created"
|
||||
# redirect_to posts_path(@post)
|
||||
# end
|
||||
#
|
||||
@@ -30,6 +30,11 @@ module ActionDispatch
|
||||
# <div class="notice"><%= flash[:notice] %></div>
|
||||
# <% end %>
|
||||
#
|
||||
# Since the +notice+ and +alert+ keys are a common idiom, convenience accessors are available:
|
||||
#
|
||||
# flash.alert = "You must be logged in"
|
||||
# flash.notice = "Post successfully created"
|
||||
#
|
||||
# This example just places a string in the flash, but you can put any object in there. And of course, you can put as
|
||||
# many as you like at a time too. Just remember: They'll be gone by the time the next action has been performed.
|
||||
#
|
||||
|
||||
@@ -6,8 +6,6 @@ module ActionDispatch
|
||||
# This middleware rescues any exception returned by the application and renders
|
||||
# nice exception pages if it's being rescued locally.
|
||||
class ShowExceptions
|
||||
LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
|
||||
|
||||
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
|
||||
|
||||
cattr_accessor :rescue_responses
|
||||
@@ -66,7 +64,7 @@ module ActionDispatch
|
||||
log_error(exception)
|
||||
|
||||
request = Request.new(env)
|
||||
if @consider_all_requests_local || local_request?(request)
|
||||
if @consider_all_requests_local || request.local?
|
||||
rescue_action_locally(request, exception)
|
||||
else
|
||||
rescue_action_in_public(exception)
|
||||
@@ -112,11 +110,6 @@ module ActionDispatch
|
||||
end
|
||||
end
|
||||
|
||||
# True if the request came from localhost, 127.0.0.1.
|
||||
def local_request?(request)
|
||||
LOCALHOST.any? { |local_ip| local_ip === request.remote_addr && local_ip === request.remote_ip }
|
||||
end
|
||||
|
||||
def status_code(exception)
|
||||
Rack::Utils.status_code(@@rescue_responses[exception.class.name])
|
||||
end
|
||||
@@ -134,7 +127,7 @@ module ActionDispatch
|
||||
|
||||
ActiveSupport::Deprecation.silence do
|
||||
message = "\n#{exception.class} (#{exception.message}):\n"
|
||||
message << exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
|
||||
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
||||
message << " " << application_trace(exception).join("\n ")
|
||||
logger.fatal("#{message}\n\n")
|
||||
end
|
||||
|
||||
@@ -69,7 +69,7 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def active
|
||||
ActiveSupport::Deprecation.warn "All middlewares in the chain are active since the laziness " <<
|
||||
ActiveSupport::Deprecation.warn "All middlewares in the chain are active since the laziness " <<
|
||||
"was removed from the middleware stack", caller
|
||||
end
|
||||
|
||||
|
||||
@@ -8,10 +8,5 @@ module ActionDispatch
|
||||
config.action_dispatch.ip_spoofing_check = true
|
||||
config.action_dispatch.show_exceptions = true
|
||||
config.action_dispatch.best_standards_support = true
|
||||
|
||||
# Prepare dispatcher callbacks and run 'prepare' callbacks
|
||||
initializer "action_dispatch.prepare_dispatcher" do |app|
|
||||
ActionDispatch::Callbacks.to_prepare { app.routes_reloader.execute_if_updated }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,31 +2,11 @@ require 'active_support/core_ext/object/to_param'
|
||||
require 'active_support/core_ext/regexp'
|
||||
|
||||
module ActionDispatch
|
||||
# = Routing
|
||||
#
|
||||
# The routing module provides URL rewriting in native Ruby. It's a way to
|
||||
# redirect incoming requests to controllers and actions. This replaces
|
||||
# mod_rewrite rules. Best of all, Rails' Routing works with any web server.
|
||||
# mod_rewrite rules. Best of all, Rails' \Routing works with any web server.
|
||||
# Routes are defined in <tt>config/routes.rb</tt>.
|
||||
#
|
||||
# Consider the following route, which you will find commented out at the
|
||||
# bottom of your generated <tt>config/routes.rb</tt>:
|
||||
#
|
||||
# match ':controller(/:action(/:id(.:format)))'
|
||||
#
|
||||
# This route states that it expects requests to consist of a
|
||||
# <tt>:controller</tt> followed optionally by an <tt>:action</tt> that in
|
||||
# turn is followed optionally by an <tt>:id</tt>, which in turn is followed
|
||||
# optionally by a <tt>:format</tt>
|
||||
#
|
||||
# Suppose you get an incoming request for <tt>/blog/edit/22</tt>, you'll end
|
||||
# up with:
|
||||
#
|
||||
# params = { :controller => 'blog',
|
||||
# :action => 'edit',
|
||||
# :id => '22'
|
||||
# }
|
||||
#
|
||||
# Think of creating routes as drawing a map for your requests. The map tells
|
||||
# them where to go based on some predefined pattern:
|
||||
#
|
||||
@@ -43,6 +23,39 @@ module ActionDispatch
|
||||
#
|
||||
# Other names simply map to a parameter as in the case of <tt>:id</tt>.
|
||||
#
|
||||
# == Resources
|
||||
#
|
||||
# Resource routing allows you to quickly declare all of the common routes
|
||||
# for a given resourceful controller. Instead of declaring separate routes
|
||||
# for your +index+, +show+, +new+, +edit+, +create+, +update+ and +destroy+
|
||||
# actions, a resourceful route declares them in a single line of code:
|
||||
#
|
||||
# resources :photos
|
||||
#
|
||||
# Sometimes, you have a resource that clients always look up without
|
||||
# referencing an ID. A common example, /profile always shows the profile of
|
||||
# the currently logged in user. In this case, you can use a singular resource
|
||||
# to map /profile (rather than /profile/:id) to the show action.
|
||||
#
|
||||
# resource :profile
|
||||
#
|
||||
# It's common to have resources that are logically children of other
|
||||
# resources:
|
||||
#
|
||||
# resources :magazines do
|
||||
# resources :ads
|
||||
# end
|
||||
#
|
||||
# You may wish to organize groups of controllers under a namespace. Most
|
||||
# commonly, you might group a number of administrative controllers under
|
||||
# an +admin+ namespace. You would place these controllers under the
|
||||
# app/controllers/admin directory, and you can group them together in your
|
||||
# router:
|
||||
#
|
||||
# namespace "admin" do
|
||||
# resources :posts, :comments
|
||||
# end
|
||||
#
|
||||
# == Named routes
|
||||
#
|
||||
# Routes can be named by passing an <tt>:as</tt> option,
|
||||
@@ -131,11 +144,35 @@ module ActionDispatch
|
||||
# Encoding regular expression modifiers are silently ignored. The
|
||||
# match will always use the default encoding or ASCII.
|
||||
#
|
||||
# == Default route
|
||||
#
|
||||
# Consider the following route, which you will find commented out at the
|
||||
# bottom of your generated <tt>config/routes.rb</tt>:
|
||||
#
|
||||
# match ':controller(/:action(/:id(.:format)))'
|
||||
#
|
||||
# This route states that it expects requests to consist of a
|
||||
# <tt>:controller</tt> followed optionally by an <tt>:action</tt> that in
|
||||
# turn is followed optionally by an <tt>:id</tt>, which in turn is followed
|
||||
# optionally by a <tt>:format</tt>.
|
||||
#
|
||||
# Suppose you get an incoming request for <tt>/blog/edit/22</tt>, you'll end
|
||||
# up with:
|
||||
#
|
||||
# params = { :controller => 'blog',
|
||||
# :action => 'edit',
|
||||
# :id => '22'
|
||||
# }
|
||||
#
|
||||
# By not relying on default routes, you improve the security of your
|
||||
# application since not all controller actions, which includes actions you
|
||||
# might add at a later time, are exposed by default.
|
||||
#
|
||||
# == HTTP Methods
|
||||
#
|
||||
# Using the <tt>:via</tt> option when specifying a route allows you to restrict it to a specific HTTP method.
|
||||
# Possible values are <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>.
|
||||
# If your route needs to respond to more than one method you can use an array, e.g. <tt>[ :get, :post ]</tt>.
|
||||
# Possible values are <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>.
|
||||
# If your route needs to respond to more than one method you can use an array, e.g. <tt>[ :get, :post ]</tt>.
|
||||
# The default value is <tt>:any</tt> which means that the route will respond to any of the HTTP methods.
|
||||
#
|
||||
# Examples:
|
||||
@@ -144,7 +181,7 @@ module ActionDispatch
|
||||
# match 'post/:id' => "posts#create_comment', :via => :post
|
||||
#
|
||||
# Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
|
||||
# URL will route to the <tt>show</tt> action.
|
||||
# URL will route to the <tt>show</tt> action.
|
||||
#
|
||||
# === HTTP helper methods
|
||||
#
|
||||
@@ -160,6 +197,20 @@ module ActionDispatch
|
||||
# however if your route needs to respond to more than one HTTP method (or all methods) then using the
|
||||
# <tt>:via</tt> option on <tt>match</tt> is preferable.
|
||||
#
|
||||
# == External redirects
|
||||
#
|
||||
# You can redirect any path to another path using the redirect helper in your router:
|
||||
#
|
||||
# match "/stories" => redirect("/posts")
|
||||
#
|
||||
# == Routing to Rack Applications
|
||||
#
|
||||
# Instead of a String, like <tt>posts#index</tt>, which corresponds to the
|
||||
# index action in the PostsController, you can specify any Rack application
|
||||
# as the endpoint for a matcher:
|
||||
#
|
||||
# match "/application.js" => Sprockets
|
||||
#
|
||||
# == Reloading routes
|
||||
#
|
||||
# You can reload routes if you feel you must:
|
||||
@@ -208,7 +259,9 @@ module ActionDispatch
|
||||
#
|
||||
# == View a list of all your routes
|
||||
#
|
||||
# Run <tt>rake routes</tt>.
|
||||
# rake routes
|
||||
#
|
||||
# Target specific controllers by prefixing the command with <tt>CONTROLLER=x</tt>.
|
||||
#
|
||||
module Routing
|
||||
autoload :DeprecatedMapper, 'action_dispatch/routing/deprecated_mapper'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'active_support/core_ext/object/blank'
|
||||
require 'active_support/core_ext/object/with_options'
|
||||
require 'active_support/core_ext/object/try'
|
||||
|
||||
module ActionDispatch
|
||||
module Routing
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ module ActionDispatch
|
||||
#
|
||||
# == Usage within the framework
|
||||
#
|
||||
# Polymorphic URL helpers are used in a number of places throughout the Rails framework:
|
||||
# Polymorphic URL helpers are used in a number of places throughout the \Rails framework:
|
||||
#
|
||||
# * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
|
||||
# <tt>url_for(@article)</tt>;
|
||||
@@ -148,29 +148,29 @@ module ActionDispatch
|
||||
def build_named_route_call(records, inflection, options = {})
|
||||
unless records.is_a?(Array)
|
||||
record = extract_record(records)
|
||||
route = ''
|
||||
route = []
|
||||
else
|
||||
record = records.pop
|
||||
route = records.inject("") do |string, parent|
|
||||
route = records.map do |parent|
|
||||
if parent.is_a?(Symbol) || parent.is_a?(String)
|
||||
string << "#{parent}_"
|
||||
parent
|
||||
else
|
||||
string << ActiveModel::Naming.plural(parent).singularize
|
||||
string << "_"
|
||||
ActiveModel::Naming.plural(parent).singularize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if record.is_a?(Symbol) || record.is_a?(String)
|
||||
route << "#{record}_"
|
||||
route << record
|
||||
else
|
||||
route << ActiveModel::Naming.plural(record)
|
||||
route = route.singularize if inflection == :singular
|
||||
route << "_"
|
||||
route << "index_" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
|
||||
route = [route.join("_").singularize] if inflection == :singular
|
||||
route << "index" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
|
||||
end
|
||||
|
||||
action_prefix(options) + route + routing_type(options).to_s
|
||||
route << routing_type(options)
|
||||
|
||||
action_prefix(options) + route.join("_")
|
||||
end
|
||||
|
||||
def extract_record(record_or_hash_or_array)
|
||||
|
||||
@@ -34,7 +34,8 @@ module ActionDispatch
|
||||
if method = conditions[:request_method]
|
||||
case method
|
||||
when Regexp
|
||||
method.source.upcase
|
||||
source = method.source.upcase
|
||||
source =~ /\A\^[-A-Z|]+\$\Z/ ? source[1..-2] : source
|
||||
else
|
||||
method.to_s.upcase
|
||||
end
|
||||
|
||||
@@ -392,10 +392,9 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def generate
|
||||
error = ActionController::RoutingError.new("No route matches #{options.inspect}")
|
||||
path, params = @set.set.generate(:path_info, named_route, options, recall, opts)
|
||||
|
||||
raise error unless path
|
||||
raise_routing_error unless path
|
||||
|
||||
params.reject! {|k,v| !v }
|
||||
|
||||
@@ -404,7 +403,7 @@ module ActionDispatch
|
||||
path << "?#{params.to_query}" if params.any?
|
||||
"#{script_name}#{path}"
|
||||
rescue Rack::Mount::RoutingError
|
||||
raise error
|
||||
raise_routing_error
|
||||
end
|
||||
|
||||
def opts
|
||||
@@ -421,6 +420,10 @@ module ActionDispatch
|
||||
{:parameterize => parameterize}
|
||||
end
|
||||
|
||||
def raise_routing_error
|
||||
raise ActionController::RoutingError.new("No route matches #{options.inspect}")
|
||||
end
|
||||
|
||||
def different_controller?
|
||||
return false unless current_controller
|
||||
controller.to_param != current_controller.to_param
|
||||
@@ -491,7 +494,7 @@ module ActionDispatch
|
||||
|
||||
def recognize_path(path, environment = {})
|
||||
method = (environment[:method] || "GET").to_s.upcase
|
||||
path = Rack::Mount::Utils.normalize_path(path)
|
||||
path = Rack::Mount::Utils.normalize_path(path) unless path =~ %r{://}
|
||||
|
||||
begin
|
||||
env = Rack::MockRequest.env_for(path, {:method => method})
|
||||
@@ -499,7 +502,7 @@ module ActionDispatch
|
||||
raise ActionController::RoutingError, e.message
|
||||
end
|
||||
|
||||
req = Rack::Request.new(env)
|
||||
req = @request_class.new(env)
|
||||
@set.recognize(req) do |route, matches, params|
|
||||
params.each do |key, value|
|
||||
if value.is_a?(String)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module ActionDispatch
|
||||
module Routing
|
||||
# In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
|
||||
# In <tt>config/routes.rb</tt> you define URL-to-controller mappings, but the reverse
|
||||
# is also possible: an URL can be generated from one of your routing definitions.
|
||||
# URL generation functionality is centralized in this module.
|
||||
#
|
||||
@@ -12,15 +12,14 @@ module ActionDispatch
|
||||
#
|
||||
# == URL generation from parameters
|
||||
#
|
||||
# As you may know, some functions - such as ActionController::Base#url_for
|
||||
# As you may know, some functions, such as ActionController::Base#url_for
|
||||
# and ActionView::Helpers::UrlHelper#link_to, can generate URLs given a set
|
||||
# of parameters. For example, you've probably had the chance to write code
|
||||
# like this in one of your views:
|
||||
#
|
||||
# <%= link_to('Click here', :controller => 'users',
|
||||
# :action => 'new', :message => 'Welcome!') %>
|
||||
#
|
||||
# # Generates a link to /users/new?message=Welcome%21
|
||||
# # => "/users/new?message=Welcome%21"
|
||||
#
|
||||
# link_to, and all other functions that require URL generation functionality,
|
||||
# actually use ActionController::UrlFor under the hood. And in particular,
|
||||
@@ -61,7 +60,7 @@ module ActionDispatch
|
||||
#
|
||||
# UrlFor also allows one to access methods that have been auto-generated from
|
||||
# named routes. For example, suppose that you have a 'users' resource in your
|
||||
# <b>routes.rb</b>:
|
||||
# <tt>config/routes.rb</tt>:
|
||||
#
|
||||
# resources :users
|
||||
#
|
||||
|
||||
@@ -3,7 +3,7 @@ require 'action_controller/vendor/html-scanner'
|
||||
module ActionDispatch
|
||||
module Assertions
|
||||
module DomAssertions
|
||||
# Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
|
||||
# \Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module ActionDispatch
|
||||
module Assertions
|
||||
# A small suite of assertions that test responses from Rails applications.
|
||||
# A small suite of assertions that test responses from \Rails applications.
|
||||
module ResponseAssertions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
@@ -18,8 +18,8 @@ module ActionDispatch
|
||||
# * <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 number like assert_response(501)
|
||||
# or its symbolic equivalent assert_response(:not_implemented).
|
||||
# You can also pass an explicit status number like <tt>assert_response(501)</tt>
|
||||
# or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>.
|
||||
# See ActionDispatch::StatusCodes for a full list.
|
||||
#
|
||||
# ==== Examples
|
||||
@@ -45,8 +45,8 @@ module ActionDispatch
|
||||
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 redirect_to(:controller => "weblog", :action => "show") and so on.
|
||||
# This match can be partial, such that <tt>assert_redirected_to(:controller => "weblog")</tt> will also
|
||||
# match the redirection of <tt>redirect_to(:controller => "weblog", :action => "show")</tt> and so on.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
require 'uri'
|
||||
require 'active_support/core_ext/hash/diff'
|
||||
require 'active_support/core_ext/hash/indifferent_access'
|
||||
|
||||
module ActionDispatch
|
||||
module Assertions
|
||||
# Suite of assertions to test routes generated by Rails and the handling of requests made to them.
|
||||
# Suite of assertions to test routes generated by \Rails and the handling of requests made to them.
|
||||
module RoutingAssertions
|
||||
# Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash)
|
||||
# match +path+. Basically, it asserts that Rails recognizes the route given by +expected_options+.
|
||||
# match +path+. Basically, it asserts that \Rails recognizes the route given by +expected_options+.
|
||||
#
|
||||
# Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes
|
||||
# requiring a specific HTTP method. The hash should contain a :path with the incoming request path
|
||||
@@ -40,14 +41,7 @@ module ActionDispatch
|
||||
# # Check a Simply RESTful generated route
|
||||
# assert_recognizes list_items_url, 'items/list'
|
||||
def assert_recognizes(expected_options, path, extras={}, message=nil)
|
||||
if path.is_a? Hash
|
||||
request_method = path[:method]
|
||||
path = path[:path]
|
||||
else
|
||||
request_method = nil
|
||||
end
|
||||
|
||||
request = recognized_request_for(path, request_method)
|
||||
request = recognized_request_for(path)
|
||||
|
||||
expected_options = expected_options.clone
|
||||
extras.each_key { |key| expected_options.delete key } unless extras.nil?
|
||||
@@ -77,7 +71,16 @@ module ActionDispatch
|
||||
# # Asserts that the generated route gives us our custom route
|
||||
# assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" }
|
||||
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
|
||||
expected_path = "/#{expected_path}" unless expected_path[0] == ?/
|
||||
if expected_path =~ %r{://}
|
||||
begin
|
||||
uri = URI.parse(expected_path)
|
||||
expected_path = uri.path.to_s.empty? ? "/" : uri.path
|
||||
rescue URI::InvalidURIError => e
|
||||
raise ActionController::RoutingError, e.message
|
||||
end
|
||||
else
|
||||
expected_path = "/#{expected_path}" unless expected_path.first == '/'
|
||||
end
|
||||
# Load routes.rb if it hasn't been loaded.
|
||||
|
||||
generated_path, extra_keys = @routes.generate_extras(options, defaults)
|
||||
@@ -177,15 +180,35 @@ module ActionDispatch
|
||||
|
||||
private
|
||||
# Recognizes the route for a given path.
|
||||
def recognized_request_for(path, request_method = nil)
|
||||
path = "/#{path}" unless path.first == '/'
|
||||
def recognized_request_for(path)
|
||||
if path.is_a?(Hash)
|
||||
method = path[:method]
|
||||
path = path[:path]
|
||||
else
|
||||
method = :get
|
||||
end
|
||||
|
||||
# Assume given controller
|
||||
request = ActionController::TestRequest.new
|
||||
request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method
|
||||
request.path = path
|
||||
|
||||
params = @routes.recognize_path(path, { :method => request.method })
|
||||
if path =~ %r{://}
|
||||
begin
|
||||
uri = URI.parse(path)
|
||||
request.env["rack.url_scheme"] = uri.scheme || "http"
|
||||
request.host = uri.host if uri.host
|
||||
request.port = uri.port if uri.port
|
||||
request.path = uri.path.to_s.empty? ? "/" : uri.path
|
||||
rescue URI::InvalidURIError => e
|
||||
raise ActionController::RoutingError, e.message
|
||||
end
|
||||
else
|
||||
path = "/#{path}" unless path.first == "/"
|
||||
request.path = path
|
||||
end
|
||||
|
||||
request.request_method = method if method
|
||||
|
||||
params = @routes.recognize_path(path, { :method => method })
|
||||
request.path_parameters = params.with_indifferent_access
|
||||
|
||||
request
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'stringio'
|
||||
require 'uri'
|
||||
require 'active_support/core_ext/kernel/singleton_class'
|
||||
require 'active_support/core_ext/object/try'
|
||||
require 'rack/test'
|
||||
require 'test/unit/assertions'
|
||||
|
||||
@@ -114,8 +115,8 @@ module ActionDispatch
|
||||
end
|
||||
end
|
||||
|
||||
# An integration Session instance represents a set of requests and responses
|
||||
# performed sequentially by some virtual user. Because you can instantiate
|
||||
# An instance of this class represents a set of requests and responses
|
||||
# performed sequentially by a test process. Because you can instantiate
|
||||
# multiple sessions and run them side-by-side, you can also mimic (to some
|
||||
# limited extent) multiple simultaneous users interacting with your system.
|
||||
#
|
||||
@@ -256,12 +257,14 @@ module ActionDispatch
|
||||
end
|
||||
end
|
||||
|
||||
hostname, port = host.split(':')
|
||||
|
||||
env = {
|
||||
:method => method,
|
||||
:params => parameters,
|
||||
|
||||
"SERVER_NAME" => host.split(':')[0],
|
||||
"SERVER_PORT" => (https? ? "443" : "80"),
|
||||
"SERVER_NAME" => hostname,
|
||||
"SERVER_PORT" => port || (https? ? "443" : "80"),
|
||||
"HTTPS" => https? ? "on" : "off",
|
||||
"rack.url_scheme" => https? ? "https" : "http",
|
||||
|
||||
@@ -372,12 +375,12 @@ module ActionDispatch
|
||||
end
|
||||
end
|
||||
|
||||
# An IntegrationTest is one that spans multiple controllers and actions,
|
||||
# An test that spans multiple controllers and actions,
|
||||
# tying them all together to ensure they work together as expected. It tests
|
||||
# more completely than either unit or functional tests do, exercising the
|
||||
# entire stack, from the dispatcher to the database.
|
||||
#
|
||||
# At its simplest, you simply extend IntegrationTest and write your tests
|
||||
# At its simplest, you simply extend <tt>IntegrationTest</tt> and write your tests
|
||||
# using the get/post methods:
|
||||
#
|
||||
# require "test_helper"
|
||||
@@ -402,7 +405,7 @@ module ActionDispatch
|
||||
# However, you can also have multiple session instances open per test, and
|
||||
# even extend those instances with assertions and methods to create a very
|
||||
# powerful testing DSL that is specific for your application. You can even
|
||||
# reference any named routes you happen to have defined!
|
||||
# reference any named routes you happen to have defined.
|
||||
#
|
||||
# require "test_helper"
|
||||
#
|
||||
|
||||
@@ -2,9 +2,8 @@ module ActionPack
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "rc"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
TINY = 2
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -156,7 +156,7 @@ module ActionView #:nodoc:
|
||||
#
|
||||
# This refreshes the sidebar, removes a person element and highlights the user list.
|
||||
#
|
||||
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
|
||||
# See the ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods documentation for more details.
|
||||
class Base
|
||||
module Subclasses
|
||||
end
|
||||
@@ -227,6 +227,7 @@ module ActionView #:nodoc:
|
||||
@lookup_context = lookup_context.is_a?(ActionView::LookupContext) ?
|
||||
lookup_context : ActionView::LookupContext.new(lookup_context)
|
||||
@lookup_context.formats = formats if formats
|
||||
@controller = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :controller)
|
||||
end
|
||||
|
||||
def controller_path
|
||||
|
||||
@@ -393,6 +393,18 @@ module ActionView
|
||||
@@stylesheet_expansions.merge!(expansions)
|
||||
end
|
||||
|
||||
def self.reset_javascript_include_default
|
||||
ActiveSupport::Deprecation.warn "reset_javascript_include_default is deprecated. Please manipulate " \
|
||||
"config.action_view.javascript_expansions[:defaults] directly", caller
|
||||
self.javascript_expansions[:defaults] = ['prototype', 'effects', 'dragdrop', 'controls', 'rails']
|
||||
end
|
||||
|
||||
def self.register_javascript_include_default(*args)
|
||||
ActiveSupport::Deprecation.warn "register_javascript_include_default is deprecated. Please " \
|
||||
"manipulate config.action_view.javascript_expansions[:defaults] directly", caller
|
||||
self.javascript_expansions[:defaults].concat args
|
||||
end
|
||||
|
||||
# Computes the path to a stylesheet asset in the public stylesheets directory.
|
||||
# If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
|
||||
# Full paths from the document root will be passed through.
|
||||
@@ -824,7 +836,7 @@ module ActionView
|
||||
|
||||
def expand_javascript_sources(sources, recursive = false)
|
||||
if sources.include?(:all)
|
||||
all_javascript_files = collect_asset_files(config.javascripts_dir, ('**' if recursive), '*.js')
|
||||
all_javascript_files = (collect_asset_files(config.javascripts_dir, ('**' if recursive), '*.js') - ['application']) << 'application'
|
||||
((determine_source(:defaults, @@javascript_expansions).dup & all_javascript_files) + all_javascript_files).uniq
|
||||
else
|
||||
expanded_sources = sources.collect do |source|
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'active_support/core_ext/object/blank'
|
||||
require 'active_support/core_ext/string/output_safety'
|
||||
|
||||
module ActionView
|
||||
# = Action View Capture Helper
|
||||
@@ -38,7 +39,7 @@ module ActionView
|
||||
value = nil
|
||||
buffer = with_output_buffer { value = yield(*args) }
|
||||
if string = buffer.presence || value and string.is_a?(String)
|
||||
NonConcattingString.new(string)
|
||||
NonConcattingString.new(ERB::Util.html_escape(string))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -106,7 +107,7 @@ module ActionView
|
||||
# <%= javascript_include_tag :defaults %>
|
||||
# <% end %>
|
||||
#
|
||||
# That will place <script> tags for Prototype, Scriptaculous, and application.js (if it exists)
|
||||
# That will place <tt>script</tt> tags for Prototype, Scriptaculous, and application.js (if it exists)
|
||||
# on the page; this technique is useful if you'll only be using these scripts in a few views.
|
||||
#
|
||||
# Note that content_for concatenates the blocks it is given for a particular
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user