Skip to content
This repository
Browse code

major redesign

  • Loading branch information...
commit 8668b8e2e0c59293b875bcda33952948a7e6dbc7 1 parent d124319
Ryan Bates authored

Showing 171 changed files with 2,425 additions and 2,737 deletions. Show diff stats Hide diff stats

  1. +2 0  .gitignore
  2. +1 1  .rvmrc
  3. +18 7 Gemfile
  4. +139 79 Gemfile.lock
  5. +17 0 Guardfile
  6. +1 1  LICENSE
  7. +2 2 README.markdown
  8. +7 0 Rakefile
  9. +2 23 app/controllers/application_controller.rb
  10. +23 51 app/controllers/comments_controller.rb
  11. +15 34 app/controllers/episodes_controller.rb
  12. +15 0 app/controllers/feedback_messages_controller.rb
  13. +0 6 app/controllers/info_controller.rb
  14. +0 39 app/controllers/spam_checks_controller.rb
  15. +0 39 app/controllers/spam_questions_controller.rb
  16. +0 34 app/controllers/spam_reports_controller.rb
  17. +0 39 app/controllers/sponsors_controller.rb
  18. +0 6 app/controllers/tags_controller.rb
  19. +11 9 app/controllers/users_controller.rb
  20. +54 1 app/helpers/application_helper.rb
  21. +12 2 app/helpers/comments_helper.rb
  22. +0 5 app/helpers/episodes_helper.rb
  23. +2 0  app/helpers/feedback_messages_helper.rb
  24. +0 3  app/helpers/sessions_helper.rb
  25. +0 2  app/helpers/spam_checks_helper.rb
  26. +0 2  app/helpers/spam_questions_helper.rb
  27. +0 2  app/helpers/spam_reports_helper.rb
  28. +0 2  app/helpers/sponsors_helper.rb
  29. +0 3  app/helpers/tags_helper.rb
  30. +6 0 app/mailers/mailer.rb
  31. +25 0 app/models/ability.rb
  32. +2 35 app/models/comment.rb
  33. +0 3  app/models/download.rb
  34. +74 44 app/models/episode.rb
  35. +4 0 app/models/feedback_message.rb
  36. +0 5 app/models/spam_check.rb
  37. +0 7 app/models/spam_question.rb
  38. +0 44 app/models/spam_report.rb
  39. +0 11 app/models/sponsor.rb
  40. +4 0 app/models/tag.rb
  41. +4 0 app/models/user.rb
  42. +34 35 app/views/comments/_comment.html.erb
  43. +17 0 app/views/comments/_comment_headline.html.erb
  44. +69 15 app/views/comments/_form.html.erb
  45. +10 0 app/views/comments/create.js.erb
  46. +1 1  app/views/comments/destroy.js.erb
  47. +1 1  app/views/comments/edit.html.erb
  48. +2 0  app/views/comments/edit.js.erb
  49. +0 8 app/views/comments/index.html.erb
  50. +0 19 app/views/comments/index.rss.builder
  51. +2 12 app/views/comments/new.html.erb
  52. +2 0  app/views/comments/new.js.erb
  53. +5 0 app/views/comments/update.js.erb
  54. +4 0 app/views/episodes/_comments.html.erb
  55. +10 41 app/views/episodes/_episode.html.erb
  56. +22 37 app/views/episodes/_form.html.erb
  57. +0 5 app/views/episodes/_pagination.html.erb
  58. +14 0 app/views/episodes/_show_notes.html.erb
  59. +5 0 app/views/episodes/_similar.html.erb
  60. +0 20 app/views/episodes/archive.html.erb
  61. +92 28 app/views/episodes/index.html.erb
  62. +21 25 app/views/episodes/index.rss.builder
  63. +52 39 app/views/episodes/show.html.erb
  64. +1 0  app/views/episodes/show.js.erb
  65. +0 20 app/views/episodes/show.rss.builder
  66. +27 0 app/views/feedback_messages/new.html.erb
  67. +12 8 app/views/info/about.html.erb
  68. +0 228 app/views/info/contest.html.erb
  69. +0 24 app/views/info/feeds.html.erb
  70. +51 28 app/views/layouts/application.html.erb
  71. +4 0 app/views/mailer/feedback.text.erb
  72. +0 24 app/views/shared/_navigation.html.erb
  73. +0 44 app/views/shared/_side.html.erb
  74. +0 12 app/views/spam_checks/_form.html.erb
  75. +0 4 app/views/spam_checks/edit.html.erb
  76. +0 22 app/views/spam_checks/index.html.erb
  77. +0 5 app/views/spam_checks/new.html.erb
  78. +0 12 app/views/spam_questions/_form.html.erb
  79. +0 4 app/views/spam_questions/edit.html.erb
  80. +0 22 app/views/spam_questions/index.html.erb
  81. +0 5 app/views/spam_questions/new.html.erb
  82. +0 1  app/views/spam_reports/create.js.erb
  83. +0 27 app/views/spam_reports/index.html.erb
  84. +0 36 app/views/spam_reports/show.html.erb
  85. +0 26 app/views/sponsors/_form.html.erb
  86. +0 3  app/views/sponsors/edit.html.erb
  87. +0 16 app/views/sponsors/index.html.erb
  88. +0 3  app/views/sponsors/new.html.erb
  89. +0 7 app/views/tags/show.html.erb
  90. +1 1  app/views/users/edit.html.erb
  91. +0 2  autotest/discover.rb
  92. +1 0  config/application.rb
  93. +0 1  config/examples/app_config.yml
  94. +0 1  config/initializers/load_enkoder.rb
  95. +3 13 config/routes.rb
  96. +11 0 db/migrate/20110416201115_add_ancestry_to_comments.rb
  97. +9 0 db/migrate/20110416214833_add_legacy_to_episodes.rb
  98. +15 0 db/migrate/20110416232852_create_feedback_messages.rb
  99. +59 0 db/migrate/20110421060544_cleanup.rb
  100. +9 0 db/migrate/20110423184218_add_legacy_to_comments.rb
  101. +9 0 db/migrate/20110503025228_add_file_sizes_to_episodes.rb
  102. +9 0 db/migrate/20110504180955_add_hidden_to_comments.rb
  103. +10 42 db/schema.rb
  104. +57 0 lib/code_formatter.rb
  105. +0 144 lib/enkoder.rb
  106. +41 0 lib/tasks/application.rake
  107. +0 16 lib/textilizer.rb
  108. BIN  public/favicon.ico
  109. BIN  public/flash/clippy.swf
  110. BIN  public/images/guest.png
  111. BIN  public/images/icons/asciicasts.png
  112. BIN  public/images/icons/comments.png
  113. BIN  public/images/icons/facebook.png
  114. BIN  public/images/icons/itunes.png
  115. BIN  public/images/icons/new_comment.png
  116. BIN  public/images/icons/rss.png
  117. BIN  public/images/icons/show_notes.png
  118. BIN  public/images/icons/twitter.png
  119. BIN  public/images/progress_large.gif
  120. BIN  public/images/railscasts_logo.png
  121. BIN  public/images/ryan_bates.jpg
  122. BIN  public/images/sublimevideo.png
  123. BIN  public/images/views/full.png
  124. BIN  public/images/views/grid.png
  125. BIN  public/images/views/list.png
  126. +43 10 public/javascripts/application.js
  127. +751 195 public/stylesheets/application.css
  128. +3 7 public/stylesheets/coderay.css
  129. +0 94 spec/controllers/comments_controller_spec.rb
  130. +0 126 spec/controllers/episodes_controller_spec.rb
  131. +0 21 spec/controllers/info_controller_spec.rb
  132. +0 63 spec/controllers/spam_checks_controller_spec.rb
  133. +0 63 spec/controllers/spam_questions_controller_spec.rb
  134. +0 60 spec/controllers/spam_reports_controller_spec.rb
  135. +0 63 spec/controllers/sponsors_controller_spec.rb
  136. +0 13 spec/controllers/tags_controller_spec.rb
  137. +0 66 spec/controllers/users_controller_spec.rb
  138. +7 7 spec/factories.rb
  139. +0 19 spec/fixtures/comments.yml
  140. +0 11 spec/fixtures/downloads.yml
  141. +0 10 spec/fixtures/episodes.yml
  142. +0 7 spec/fixtures/spam_checks.yml
  143. +0 7 spec/fixtures/spam_questions.yml
  144. +0 13 spec/fixtures/spam_reports.yml
  145. +0 11 spec/fixtures/sponsors.yml
  146. +0 7 spec/fixtures/taggings.yml
  147. +0 5 spec/fixtures/tags.yml
  148. +0 17 spec/fixtures/users.yml
  149. +11 3 spec/helpers/comments_helper_spec.rb
  150. +42 0 spec/lib/code_formatter_spec.rb
  151. +0 31 spec/lib/textilizer_spec.rb
  152. +92 0 spec/models/ability_spec.rb
  153. +5 36 spec/models/comment_spec.rb
  154. +0 4 spec/models/download_spec.rb
  155. +41 17 spec/models/episode_spec.rb
  156. +10 0 spec/models/feedback_message_spec.rb
  157. +0 7 spec/models/spam_check_spec.rb
  158. +0 7 spec/models/spam_question_spec.rb
  159. +0 54 spec/models/spam_report_spec.rb
  160. +0 16 spec/models/sponsor_spec.rb
  161. +1 1  spec/models/tag_spec.rb
  162. +1 1  spec/models/tagging_spec.rb
  163. +1 1  spec/models/user_spec.rb
  164. +44 0 spec/requests/comments_request_spec.rb
  165. +112 0 spec/requests/episodes_request_spec.rb
  166. +15 0 spec/requests/feedback_messages_request_spec.rb
  167. +8 0 spec/requests/info_request_spec.rb
  168. +47 0 spec/requests/users_request_spec.rb
  169. +53 5 spec/spec_helper.rb
  170. +6 0 spec/support/auth_macros.rb
  171. +0 31 spec/support/controller_macros.rb
2  .gitignore
@@ -3,6 +3,8 @@ db/*.sqlite3
3 3 log/*.log
4 4 log/*.pid
5 5 tmp/**/*
  6 +tmp/*
  7 +coverage/*
6 8 config/database.yml
7 9 config/app_config.yml
8 10 config/*.sphinx.conf
2  .rvmrc
... ... @@ -1 +1 @@
1   -rvm use 1.9.2-p0
  1 +rvm use 1.9.2@railscasts
25 Gemfile
... ... @@ -1,26 +1,37 @@
1 1 source 'http://rubygems.org'
2 2
3   -gem "rails", "3.0.3"
  3 +gem "rails", "3.0.7"
4 4 gem "mysql2"
5   -gem "RedCloth"
  5 +gem "redcarpet"
6 6 gem "coderay"
7 7 gem "acts_as_list"
8 8 gem "thinking-sphinx", ">= 2.0.1", :require => "thinking_sphinx"
9 9 gem "whenever", :require => false
10 10 gem "will_paginate", ">= 3.0.pre2"
11 11 gem "jquery-rails"
12   -gem "omniauth"
  12 +gem "omniauth", ">= 0.2.2"
13 13 gem "exception_notification", :git => "git://github.com/rails/exception_notification.git", :require => "exception_notifier"
  14 +gem "ancestry"
  15 +gem "cancan", :git => "git://github.com/ryanb/cancan.git", :branch => "2.0"
14 16
15 17 group :development, :test do
16   - gem "mocha"
17 18 gem "rspec-rails"
  19 + gem "launchy"
  20 +end
  21 +
  22 +group :test do
18 23 gem "factory_girl_rails"
19   - gem "webrat"
20   - gem "autotest"
21   - gem "autotest-rails"
  24 + gem "capybara", :git => "git://github.com/jnicklas/capybara.git"
  25 + gem "capybara-webkit"
  26 + gem "database_cleaner"
  27 + gem "guard"
  28 + gem "guard-rspec"
  29 + gem "rb-fsevent", :require => false if RUBY_PLATFORM.downcase.include?("darwin")
  30 + gem "fakeweb"
  31 + gem "simplecov", :require => false
22 32 end
23 33
24 34 group :development do
  35 + gem "thin"
25 36 gem "nifty-generators"
26 37 end
218 Gemfile.lock
... ... @@ -1,136 +1,177 @@
1 1 GIT
  2 + remote: git://github.com/jnicklas/capybara.git
  3 + revision: 4483061ccc32c34345e84685e8ed43870e7a8693
  4 + specs:
  5 + capybara (0.4.1.1)
  6 + mime-types (>= 1.16)
  7 + nokogiri (>= 1.3.3)
  8 + rack (>= 1.0.0)
  9 + rack-test (>= 0.5.4)
  10 + selenium-webdriver (>= 0.0.27)
  11 + xpath (~> 0.1.3)
  12 +
  13 +GIT
2 14 remote: git://github.com/rails/exception_notification.git
3 15 revision: 192a49a02d63d28b23ed41cebadfedd490929cf1
4 16 specs:
5 17 exception_notification (1.0.0)
6 18
  19 +GIT
  20 + remote: git://github.com/ryanb/cancan.git
  21 + revision: 63865cc7d8df9ea080e7fb1adf6ca8eeb1719ee9
  22 + branch: 2.0
  23 + specs:
  24 + cancan (1.6.3)
  25 +
7 26 GEM
8 27 remote: http://rubygems.org/
9 28 specs:
10   - RedCloth (4.2.3)
11   - ZenTest (4.4.0)
12 29 aaronh-chronic (0.3.9)
13 30 abstract (1.0.0)
14   - actionmailer (3.0.3)
15   - actionpack (= 3.0.3)
16   - mail (~> 2.2.9)
17   - actionpack (3.0.3)
18   - activemodel (= 3.0.3)
19   - activesupport (= 3.0.3)
  31 + actionmailer (3.0.7)
  32 + actionpack (= 3.0.7)
  33 + mail (~> 2.2.15)
  34 + actionpack (3.0.7)
  35 + activemodel (= 3.0.7)
  36 + activesupport (= 3.0.7)
20 37 builder (~> 2.1.2)
21 38 erubis (~> 2.6.6)
22   - i18n (~> 0.4)
  39 + i18n (~> 0.5.0)
23 40 rack (~> 1.2.1)
24   - rack-mount (~> 0.6.13)
25   - rack-test (~> 0.5.6)
  41 + rack-mount (~> 0.6.14)
  42 + rack-test (~> 0.5.7)
26 43 tzinfo (~> 0.3.23)
27   - activemodel (3.0.3)
28   - activesupport (= 3.0.3)
  44 + activemodel (3.0.7)
  45 + activesupport (= 3.0.7)
29 46 builder (~> 2.1.2)
30   - i18n (~> 0.4)
31   - activerecord (3.0.3)
32   - activemodel (= 3.0.3)
33   - activesupport (= 3.0.3)
  47 + i18n (~> 0.5.0)
  48 + activerecord (3.0.7)
  49 + activemodel (= 3.0.7)
  50 + activesupport (= 3.0.7)
34 51 arel (~> 2.0.2)
35 52 tzinfo (~> 0.3.23)
36   - activeresource (3.0.3)
37   - activemodel (= 3.0.3)
38   - activesupport (= 3.0.3)
39   - activesupport (3.0.3)
  53 + activeresource (3.0.7)
  54 + activemodel (= 3.0.7)
  55 + activesupport (= 3.0.7)
  56 + activesupport (3.0.7)
40 57 acts_as_list (0.1.2)
41   - addressable (2.2.2)
42   - arel (2.0.3)
43   - autotest (4.4.1)
44   - autotest-rails (4.1.0)
45   - ZenTest
  58 + addressable (2.2.5)
  59 + ancestry (1.2.3)
  60 + activerecord (>= 2.2.2)
  61 + arel (2.0.9)
46 62 builder (2.1.2)
  63 + capybara-webkit (0.2.0)
  64 + capybara (~> 0.4.1)
  65 + childprocess (0.1.8)
  66 + ffi (~> 1.0.6)
47 67 coderay (0.9.5)
  68 + configuration (1.2.0)
  69 + daemons (1.1.2)
  70 + database_cleaner (0.6.7)
48 71 diff-lcs (1.1.2)
49 72 erubis (2.6.6)
50 73 abstract (>= 1.0.0)
  74 + eventmachine (0.12.10)
51 75 factory_girl (1.3.2)
52 76 factory_girl_rails (1.0)
53 77 factory_girl (~> 1.3)
54 78 rails (>= 3.0.0.beta4)
55   - faraday (0.5.3)
56   - addressable (~> 2.2.2)
57   - multipart-post (~> 1.0.1)
  79 + fakeweb (1.3.0)
  80 + faraday (0.6.1)
  81 + addressable (~> 2.2.4)
  82 + multipart-post (~> 1.1.0)
58 83 rack (>= 1.1.0, < 2)
59   - i18n (0.4.2)
  84 + ffi (1.0.7)
  85 + rake (>= 0.8.7)
  86 + guard (0.3.4)
  87 + thor (~> 0.14.6)
  88 + guard-rspec (0.3.1)
  89 + guard (>= 0.2.2)
  90 + i18n (0.5.0)
60 91 jquery-rails (0.2.5)
61 92 rails (~> 3.0)
62 93 thor (~> 0.14.4)
63   - mail (2.2.10)
  94 + json_pure (1.5.1)
  95 + launchy (0.4.0)
  96 + configuration (>= 0.0.5)
  97 + rake (>= 0.8.1)
  98 + mail (2.2.19)
64 99 activesupport (>= 2.3.6)
65   - i18n (~> 0.4.1)
  100 + i18n (>= 0.4.0)
66 101 mime-types (~> 1.16)
67 102 treetop (~> 1.4.8)
68 103 mime-types (1.16)
69   - mocha (0.9.9)
70   - rake
71 104 multi_json (0.0.5)
72   - multipart-post (1.0.1)
  105 + multipart-post (1.1.0)
73 106 mysql2 (0.2.6)
74 107 net-ldap (0.1.1)
75 108 nifty-generators (0.4.2)
76 109 nokogiri (1.4.4)
77   - oa-basic (0.1.6)
  110 + oa-basic (0.2.2)
78 111 multi_json (~> 0.0.2)
79 112 nokogiri (~> 1.4.2)
80   - oa-core (= 0.1.6)
  113 + oa-core (= 0.2.2)
81 114 rest-client (~> 1.6.0)
82   - oa-core (0.1.6)
  115 + oa-core (0.2.2)
83 116 rack (~> 1.1)
84   - oa-enterprise (0.1.6)
  117 + oa-enterprise (0.2.2)
85 118 net-ldap (~> 0.1.1)
86 119 nokogiri (~> 1.4.2)
87   - oa-core (= 0.1.6)
  120 + oa-core (= 0.2.2)
88 121 pyu-ruby-sasl (~> 0.0.3.1)
89 122 rubyntlm (~> 0.1.1)
90   - oa-oauth (0.1.6)
  123 + oa-more (0.2.2)
  124 + multi_json (~> 0.0.2)
  125 + oa-core (= 0.2.2)
  126 + rest-client (~> 1.6.0)
  127 + oa-oauth (0.2.2)
  128 + faraday (~> 0.6.1)
91 129 multi_json (~> 0.0.2)
92 130 nokogiri (~> 1.4.2)
93   - oa-core (= 0.1.6)
  131 + oa-core (= 0.2.2)
94 132 oauth (~> 0.4.0)
95   - oauth2 (~> 0.1.0)
96   - oa-openid (0.1.6)
97   - oa-core (= 0.1.6)
  133 + oauth2 (~> 0.3.0)
  134 + oa-openid (0.2.2)
  135 + oa-core (= 0.2.2)
98 136 rack-openid (~> 1.2.0)
99 137 ruby-openid-apps-discovery
100 138 oauth (0.4.4)
101   - oauth2 (0.1.0)
102   - faraday (~> 0.5.0)
  139 + oauth2 (0.3.0)
  140 + faraday (~> 0.6.0)
103 141 multi_json (~> 0.0.4)
104   - omniauth (0.1.6)
105   - oa-basic (= 0.1.6)
106   - oa-core (= 0.1.6)
107   - oa-enterprise (= 0.1.6)
108   - oa-oauth (= 0.1.6)
109   - oa-openid (= 0.1.6)
  142 + omniauth (0.2.2)
  143 + oa-basic (= 0.2.2)
  144 + oa-core (= 0.2.2)
  145 + oa-enterprise (= 0.2.2)
  146 + oa-more (= 0.2.2)
  147 + oa-oauth (= 0.2.2)
  148 + oa-openid (= 0.2.2)
110 149 polyglot (0.3.1)
111 150 pyu-ruby-sasl (0.0.3.2)
112   - rack (1.2.1)
113   - rack-mount (0.6.13)
  151 + rack (1.2.2)
  152 + rack-mount (0.6.14)
114 153 rack (>= 1.0.0)
115 154 rack-openid (1.2.0)
116 155 rack (>= 1.1.0)
117 156 ruby-openid (>= 2.1.8)
118   - rack-test (0.5.6)
  157 + rack-test (0.5.7)
119 158 rack (>= 1.0)
120   - rails (3.0.3)
121   - actionmailer (= 3.0.3)
122   - actionpack (= 3.0.3)
123   - activerecord (= 3.0.3)
124   - activeresource (= 3.0.3)
125   - activesupport (= 3.0.3)
  159 + rails (3.0.7)
  160 + actionmailer (= 3.0.7)
  161 + actionpack (= 3.0.7)
  162 + activerecord (= 3.0.7)
  163 + activeresource (= 3.0.7)
  164 + activesupport (= 3.0.7)
126 165 bundler (~> 1.0)
127   - railties (= 3.0.3)
128   - railties (3.0.3)
129   - actionpack (= 3.0.3)
130   - activesupport (= 3.0.3)
  166 + railties (= 3.0.7)
  167 + railties (3.0.7)
  168 + actionpack (= 3.0.7)
  169 + activesupport (= 3.0.7)
131 170 rake (>= 0.8.7)
132 171 thor (~> 0.14.4)
133 172 rake (0.8.7)
  173 + rb-fsevent (0.4.0)
  174 + redcarpet (1.10.0)
134 175 rest-client (1.6.1)
135 176 mime-types (>= 1.16)
136 177 riddle (1.2.1)
@@ -148,41 +189,60 @@ GEM
148 189 ruby-openid-apps-discovery (1.2.0)
149 190 ruby-openid (>= 2.1.7)
150 191 rubyntlm (0.1.1)
  192 + rubyzip (0.9.4)
  193 + selenium-webdriver (0.1.4)
  194 + childprocess (>= 0.1.7)
  195 + ffi (>= 1.0.7)
  196 + json_pure
  197 + rubyzip
  198 + simplecov (0.4.2)
  199 + simplecov-html (~> 0.4.4)
  200 + simplecov-html (0.4.4)
  201 + thin (1.2.11)
  202 + daemons (>= 1.0.9)
  203 + eventmachine (>= 0.12.6)
  204 + rack (>= 1.0.0)
151 205 thinking-sphinx (2.0.1)
152 206 activerecord (>= 3.0.3)
153 207 riddle (>= 1.2.1)
154   - thor (0.14.4)
  208 + thor (0.14.6)
155 209 treetop (1.4.9)
156 210 polyglot (>= 0.3.1)
157   - tzinfo (0.3.23)
158   - webrat (0.7.2)
159   - nokogiri (>= 1.2.0)
160   - rack (>= 1.0)
161   - rack-test (>= 0.5.3)
  211 + tzinfo (0.3.27)
162 212 whenever (0.6.2)
163 213 aaronh-chronic (>= 0.3.9)
164 214 activesupport (>= 2.3.4)
165 215 will_paginate (3.0.pre2)
  216 + xpath (0.1.3)
  217 + nokogiri (~> 1.3)
166 218
167 219 PLATFORMS
168 220 ruby
169 221
170 222 DEPENDENCIES
171   - RedCloth
172 223 acts_as_list
173   - autotest
174   - autotest-rails
  224 + ancestry
  225 + cancan!
  226 + capybara!
  227 + capybara-webkit
175 228 coderay
  229 + database_cleaner
176 230 exception_notification!
177 231 factory_girl_rails
  232 + fakeweb
  233 + guard
  234 + guard-rspec
178 235 jquery-rails
179   - mocha
  236 + launchy
180 237 mysql2
181 238 nifty-generators
182   - omniauth
183   - rails (= 3.0.3)
  239 + omniauth (>= 0.2.2)
  240 + rails (= 3.0.7)
  241 + rb-fsevent
  242 + redcarpet
184 243 rspec-rails
  244 + simplecov
  245 + thin
185 246 thinking-sphinx (>= 2.0.1)
186   - webrat
187 247 whenever
188 248 will_paginate (>= 3.0.pre2)
17 Guardfile
... ... @@ -0,0 +1,17 @@
  1 +# A sample Guardfile
  2 +# More info at http://github.com/guard/guard#readme
  3 +
  4 +guard 'rspec', :version => 2 do
  5 + watch('^spec/(.*)_spec.rb')
  6 + watch('^lib/(.*)\.rb') { |m| "spec/lib/#{m[1]}_spec.rb" }
  7 + watch('^spec/spec_helper.rb') { "spec" }
  8 +
  9 + # Rails example
  10 + watch('^app/views/(.*)/.*') { |m| "spec/requests/#{m[1]}_request_spec.rb" }
  11 + watch('^app/controllers/(.*)_controller\.rb') { |m| "spec/requests/#{m[1]}_request_spec.rb" }
  12 + watch('^app/(.*)\.rb') { |m| "spec/#{m[1]}_spec.rb" }
  13 + # watch('^lib/(.*)\.rb') { |m| "spec/lib/#{m[1]}_spec.rb" }
  14 + watch('^config/routes.rb') { "spec/routing" }
  15 + watch('^app/controllers/application_controller.rb') { "spec/controllers" }
  16 + watch('^spec/factories.rb') { "spec/models" }
  17 +end
2  LICENSE
... ... @@ -1,4 +1,4 @@
1   -Copyright (c) 2010 Ryan Bates, Railscasts
  1 +Copyright (c) 2011 Ryan Bates, RailsCasts
2 2
3 3 Permission is hereby granted, free of charge, to any person obtaining
4 4 a copy of this software and associated documentation files (the
4 README.markdown
Source Rendered
... ... @@ -1,6 +1,6 @@
1   -# Railscasts
  1 +# RailsCasts
2 2
3   -This is the source code for the [Railscasts site](http://railscasts.com/). If you want the source code for the episodes, see the [railscasts-episodes](http://github.com/ryanb/railscasts-episodes) project.
  3 +This is the source code for the [RailsCasts site](http://railscasts.com/). If you want the source code for the episodes, see the [railscasts-episodes](http://github.com/ryanb/railscasts-episodes) project.
4 4
5 5 Please [let me know](https://github.com/inbox/new/ryanb) if you plan to use this app for your site.
6 6
7 Rakefile
@@ -4,4 +4,11 @@
4 4 require File.expand_path('../config/application', __FILE__)
5 5 require 'rake'
6 6
  7 +desc "Run tests with coverage"
  8 +task :coverage do
  9 + ENV['COVERAGE'] = "true"
  10 + Rake::Task["spec"].execute
  11 + Launchy.open("file://" + File.expand_path("../coverage/index.html", __FILE__))
  12 +end
  13 +
7 14 Railscasts::Application.load_tasks
25 app/controllers/application_controller.rb
... ... @@ -1,34 +1,13 @@
1 1 class ApplicationController < ActionController::Base
2 2 protect_from_forgery
3   - helper_method :admin?, :current_user
  3 + enable_authorization
4 4
5 5 private
6 6
7   - def admin?
8   - current_user && current_user.admin?
9   - end
10   -
11   - def current_spam_question
12   - @current_spam_question ||= SpamQuestion.find(session[:spam_question_id]) if session[:spam_question_id]
13   - end
14   - helper_method :current_spam_question
15   -
16 7 def current_user
17 8 @current_user ||= User.find_by_token(cookies[:token]) if cookies[:token]
18 9 end
19   -
20   - def login_required
21   - unless current_user
22   - store_target_location
23   - redirect_to root_url, :alert => "You must first sign in before accessing this page."
24   - end
25   - end
26   -
27   - def admin_required
28   - unless admin?
29   - redirect_to root_url, :alert => "Not authorized to access this page."
30   - end
31   - end
  10 + helper_method :current_user
32 11
33 12 def redirect_to_target_or_default(default, *options)
34 13 redirect_to(session[:return_to] || default, *options)
74 app/controllers/comments_controller.rb
... ... @@ -1,76 +1,48 @@
1 1 class CommentsController < ApplicationController
2   - before_filter :login_required, :only => [:new, :create]
3   - before_filter :admin_required, :only => [:edit, :update, :destroy]
4   - skip_before_filter :verify_authenticity_token, :only => :destroy
5   -
6   - def index
7   - @comments = Comment.recent.all(:limit => 30)
8   - respond_to do |format|
9   - format.html
10   - format.rss
11   - end
12   - end
  2 + load_and_authorize_resource
13 3
14 4 def new
15   - redirect_to root_url, :notice => "To submit a comment, please go to a specific episode first."
  5 + @comment = Comment.new(:parent_id => params[:parent_id], :episode_id => params[:episode_id], :user => current_user)
16 6 end
17 7
18 8 def create
19 9 @comment = current_user.comments.build(params[:comment])
20 10 @comment.request = request
21   - if params[:preview_button].nil? && @comment.save
22   - redirect_to @comment.episode, :notice => "Successfully created comment."
23   - else
24   - render 'new'
  11 + @comment.save
  12 + respond_to do |format|
  13 + format.html do
  14 + if @comment.errors.present?
  15 + render :new
  16 + else
  17 + redirect_to(episode_path(@comment.episode, :view => "comments"))
  18 + end
  19 + end
  20 + format.js
25 21 end
26 22 end
27 23
28 24 def edit
29   - @comment = Comment.find(params[:id])
30 25 end
31 26
32 27 def update
33   - @comment = Comment.find(params[:id])
34   - if @comment.update_attributes(params[:comment])
35   - redirect_to @comment.episode, :notice => "Successfully updated comment."
36   - else
37   - render 'edit'
  28 + @comment.update_attributes(params[:comment])
  29 + respond_to do |format|
  30 + format.html do
  31 + if @comment.errors.present?
  32 + render :edit
  33 + else
  34 + redirect_to(episode_path(@comment.episode, :view => "comments"))
  35 + end
  36 + end
  37 + format.js
38 38 end
39 39 end
40 40
41 41 def destroy
42   - @comment = Comment.find(params[:id])
43 42 @comment.destroy
44   - flash[:notice] = "Successfully destroyed comment."
45 43 respond_to do |format|
46   - format.html { redirect_to comments_path }
  44 + format.html { redirect_to episode_path(@comment.episode, :view => "comments") }
47 45 format.js
48 46 end
49 47 end
50   -
51   - private
52   -
53   - def check_spam(comment)
54   - errors = []
55   - if comment.spam?
56   - errors << "Comment rejected. Please email me the content of your comment for approval: ryan at railscasts dot com."
57   - elsif current_spam_question
58   - if params[:spam_answer] =~ /#{current_spam_question.answer}/i
59   - session[:spam_question_id] = nil
60   - else
61   - errors << "The given answer is incorrect, please try again."
62   - end
63   - elsif comment.spammish?
64   - errors << "The provided comment looks like spam. Please answer the question below."
65   - session[:spam_question_id] = SpamQuestion.random.id
66   - end
67   - errors << "Javascript must be enabled to submit a comment." if params[:spam_key] != APP_CONFIG['spam_key']
68   - errors << "Don't fill in the fake email address below, it should be left blank." unless params[:email].blank? # fake email to catch spammers
69   -
70   - unless errors.empty?
71   - errors << "If it still doesn't work, please let me know: ryan [at] railscasts [dot] com."
72   - flash.now[:alert] = errors.join(" ")
73   - end
74   - errors.empty?
75   - end
76 48 end
49 app/controllers/episodes_controller.rb
... ... @@ -1,76 +1,57 @@
1 1 class EpisodesController < ApplicationController
2   - before_filter :admin_required, :only => [:new, :create, :edit, :update, :destroy]
  2 + load_and_authorize_resource :find_by => :param
3 3
4 4 def index
  5 + @tag = Tag.find(params[:tag_id]) if params[:tag_id]
5 6 if params[:search].blank?
6   - @episodes = Episode.published.recent
  7 + @episodes = (@tag ? @tag.episodes : Episode).published.recent
7 8 else
8 9 @episodes = Episode.search_published(params[:search])
9 10 end
10 11 respond_to do |format|
11   - format.html { @episodes = @episodes.paginate(:page => params[:page], :per_page => 10) }
  12 + format.html { @episodes = @episodes.paginate(:page => params[:page], :per_page => episodes_per_page) }
12 13 format.rss
13 14 end
14 15 end
15 16
16   - def archive
17   - if params[:search].blank?
18   - episodes = Episode.published.recent
19   - else
20   - episodes = Episode.search_published(params[:search]).sort_by(&:published_at).reverse
21   - end
22   - @episode_months = episodes.group_by(&:published_month)
23   - end
24   -
25 17 def show
26   - if admin?
27   - @episode = Episode.find_by_position!(params[:id].to_i)
28   - else
29   - @episode = Episode.published.find_by_position!(params[:id].to_i)
30   - end
31 18 if params[:id] != @episode.to_param
32 19 headers["Status"] = "301 Moved Permanently"
33 20 redirect_to episode_url(@episode)
34 21 else
35   - @comment = Comment.new(:episode => @episode)
36   - respond_to do |format|
37   - format.html
38   - format.rss
39   - end
  22 + @comment = Comment.new(:episode => @episode, :user => current_user)
40 23 end
41 24 end
42 25
43 26 def new
44   - @episode = Episode.new
45   - @episode.downloads.build(:format => 'mov')
46   - @episode.downloads.build(:format => 'm4v')
47 27 end
48 28
49 29 def create
50   - @episode = Episode.new(params[:episode])
51 30 if @episode.save
52 31 redirect_to @episode, :notice => "Successfully created episode."
53 32 else
54   - render 'new'
  33 + render :new
55 34 end
56 35 end
57 36
58 37 def edit
59   - @episode = Episode.find(params[:id])
60 38 end
61 39
62 40 def update
63   - @episode = Episode.find(params[:id])
64 41 if @episode.update_attributes(params[:episode])
65 42 redirect_to @episode, :notice => "Successfully updated episode."
66 43 else
67   - render 'edit'
  44 + render :edit
68 45 end
69 46 end
70 47
71   - def destroy
72   - @episode = Episode.find(params[:id])
73   - @episode.destroy
74   - redirect_to episodes_path, :notice => "Successfully destroyed episode."
  48 + private
  49 +
  50 + def episodes_per_page
  51 + case params[:view]
  52 + when "list" then 40
  53 + when "grid" then 24
  54 + else 10
  55 + end
75 56 end
76 57 end
15 app/controllers/feedback_messages_controller.rb
... ... @@ -0,0 +1,15 @@
  1 +class FeedbackMessagesController < ApplicationController
  2 + def new
  3 + @feedback_message = FeedbackMessage.new
  4 + end
  5 +
  6 + def create
  7 + @feedback_message = FeedbackMessage.new(params[:feedback_message])
  8 + if @feedback_message.save
  9 + Mailer.feedback(@feedback_message).deliver
  10 + redirect_to root_url, :notice => "Thank you for the feedback."
  11 + else
  12 + render :new
  13 + end
  14 + end
  15 +end
6 app/controllers/info_controller.rb
@@ -2,12 +2,6 @@ class InfoController < ApplicationController
2 2 def about
3 3 end
4 4
5   - def contest
6   - end
7   -
8   - def feeds
9   - end
10   -
11 5 def give_back
12 6 end
13 7 end
39 app/controllers/spam_checks_controller.rb
... ... @@ -1,39 +0,0 @@
1   -class SpamChecksController < ApplicationController
2   - before_filter :admin_required
3   -
4   - def index
5   - @spam_checks = SpamCheck.all
6   - end
7   -
8   - def new
9   - @spam_check = SpamCheck.new
10   - end
11   -
12   - def create
13   - @spam_check = SpamCheck.new(params[:spam_check])
14   - if @spam_check.save
15   - redirect_to spam_checks_url, :notice => "Successfully created spam check."
16   - else
17   - render :action => 'new'
18   - end
19   - end
20   -
21   - def edit
22   - @spam_check = SpamCheck.find(params[:id])
23   - end
24   -
25   - def update
26   - @spam_check = SpamCheck.find(params[:id])
27   - if @spam_check.update_attributes(params[:spam_check])
28   - redirect_to spam_checks_url, :notice => "Successfully updated spam check."
29   - else
30   - render :action => 'edit'
31   - end
32   - end
33   -
34   - def destroy
35   - @spam_check = SpamCheck.find(params[:id])
36   - @spam_check.destroy
37   - redirect_to spam_checks_url, :notice => "Successfully destroyed spam check."
38   - end
39   -end
39 app/controllers/spam_questions_controller.rb
... ... @@ -1,39 +0,0 @@
1   -class SpamQuestionsController < ApplicationController
2   - before_filter :admin_required
3   -
4   - def index
5   - @spam_questions = SpamQuestion.all
6   - end
7   -
8   - def new
9   - @spam_question = SpamQuestion.new
10   - end
11   -
12   - def create
13   - @spam_question = SpamQuestion.new(params[:spam_question])
14   - if @spam_question.save
15   - redirect_to spam_questions_url, :notice => "Successfully created spam question."
16   - else
17   - render :action => 'new'
18   - end
19   - end
20   -
21   - def edit
22   - @spam_question = SpamQuestion.find(params[:id])
23   - end
24   -
25   - def update
26   - @spam_question = SpamQuestion.find(params[:id])
27   - if @spam_question.update_attributes(params[:spam_question])
28   - redirect_to spam_questions_url, :notice => "Successfully updated spam question."
29   - else
30   - render :action => 'edit'
31   - end
32   - end
33   -
34   - def destroy
35   - @spam_question = SpamQuestion.find(params[:id])
36   - @spam_question.destroy
37   - redirect_to spam_questions_url, :notice => "Successfully destroyed spam question."
38   - end
39   -end
34 app/controllers/spam_reports_controller.rb
... ... @@ -1,34 +0,0 @@
1   -class SpamReportsController < ApplicationController
2   - before_filter :admin_required, :except => :create
3   - skip_before_filter :verify_authenticity_token, :only => :create
4   -
5   - def index
6   - @spam_reports = SpamReport.unconfirmed.popular
7   - end
8   -
9   - def show
10   - @spam_report = SpamReport.find(params[:id])
11   - end
12   -
13   - def create
14   - @comment = Comment.find(params[:comment_id])
15   - SpamReport.report_comment(@comment)
16   - flash[:notice] = "Thank you for reporting spam."
17   - respond_to do |format|
18   - format.html { redirect_to episode_path(@comment.episode_id) }
19   - format.js
20   - end
21   - end
22   -
23   - def destroy
24   - @spam_report = SpamReport.find(params[:id])
25   - @spam_report.destroy
26   - redirect_to spam_reports_url, :notice => "Successfully destroyed spam report."
27   - end
28   -
29   - def confirm
30   - @spam_reports = SpamReport.find_all_by_id(params[:id])
31   - @spam_reports.each(&:confirm!)
32   - redirect_to spam_reports_url, :notice => "Successfully confirmed spam report."
33   - end
34   -end
39 app/controllers/sponsors_controller.rb
... ... @@ -1,39 +0,0 @@
1   -class SponsorsController < ApplicationController
2   - before_filter :admin_required
3   -
4   - def index
5   - @sponsors = Sponsor.find(:all)
6   - end
7   -
8   - def new
9   - @sponsor = Sponsor.new
10   - end
11   -
12   - def create
13   - @sponsor = Sponsor.new(params[:sponsor])
14   - if @sponsor.save
15   - redirect_to sponsors_url, :notice => "Successfully created sponsor."
16   - else
17   - render 'new'
18   - end
19   - end
20   -
21   - def edit
22   - @sponsor = Sponsor.find(params[:id])
23   - end
24   -
25   - def update
26   - @sponsor = Sponsor.find(params[:id])
27   - if @sponsor.update_attributes(params[:sponsor])
28   - redirect_to sponsors_url, :notice => "Successfully updated sponsor."
29   - else
30   - render 'edit'
31   - end
32   - end
33   -
34   - def destroy
35   - @sponsor = Sponsor.find(params[:id])
36   - @sponsor.destroy
37   - redirect_to sponsors_url, :notice => "Successfully destroyed sponsor."
38   - end
39   -end
6 app/controllers/tags_controller.rb
... ... @@ -1,6 +0,0 @@
1   -class TagsController < ApplicationController
2   - def show
3   - @tag = Tag.find(params[:id])
4   - @episodes = @tag.episodes.published.recent.paginate(:page => params[:page], :per_page => 10, :count => { :select => "*" })
5   - end
6   -end
20 app/controllers/users_controller.rb
... ... @@ -1,8 +1,8 @@
1 1 class UsersController < ApplicationController
2   - before_filter :login_required, :only => [:edit, :update]
  2 + before_filter :load_current_user, :only => [:edit, :update]
  3 + load_and_authorize_resource
3 4
4 5 def show
5   - @user = User.find(params[:id])
6 6 end
7 7
8 8 def create
@@ -14,16 +14,12 @@ def create
14 14 end
15 15
16 16 def edit
17   - @user = current_user
18 17 end
19 18
20 19 def update
21   - @user = current_user
22   - if @user.update_attributes(params[:user])
23   - redirect_to @user, :notice => "Successfully updated user."
24   - else
25   - render :action => "edit"
26   - end
  20 + @user.attributes = params[:user]
  21 + @user.save!
  22 + redirect_to @user, :notice => "Successfully updated profile."
27 23 end
28 24
29 25 def login
@@ -40,4 +36,10 @@ def logout
40 36 cookies.delete(:token)
41 37 redirect_to root_url, :notice => "You have been logged out."
42 38 end
  39 +
  40 + private
  41 +
  42 + def load_current_user
  43 + @user = current_user
  44 + end
43 45 end
55 app/helpers/application_helper.rb
... ... @@ -1,5 +1,58 @@
  1 +require "builder"
  2 +
1 3 module ApplicationHelper
2 4 def textilize(text)
3   - Textilizer.new(text).to_html.html_safe unless text.blank?
  5 + CodeFormatter.new(text).to_html.html_safe unless text.blank?
  6 + end
  7 +
  8 + def tab_link(name, url)
  9 + selected = url.all? { |key, value| params[key] == value }
  10 + link_to(name, url, :class => (selected ? "selected tab" : "tab"))
  11 + end
  12 +
  13 + def avatar_url(comment_or_user, size = 64)
  14 + default_url = "#{root_url}images/guest.png"
  15 + token = gravatar_token(comment_or_user)
  16 + if token.present?
  17 + "http://gravatar.com/avatar/#{gravatar_token(comment_or_user)}.png?s=#{size}&d=#{CGI.escape(default_url)}"
  18 + else
  19 + default_url
  20 + end
  21 + end
  22 +
  23 + # TODO refactor me into comment/user class
  24 + def gravatar_token(comment_or_user)
  25 + case comment_or_user
  26 + when Comment
  27 + token = gravatar_token(comment_or_user.user)
  28 + if token.present?
  29 + token
  30 + elsif comment_or_user.email.present?
  31 + Digest::MD5.hexdigest(comment_or_user.email.downcase)
  32 + end
  33 + when User
  34 + if comment_or_user.gravatar_token.present?
  35 + comment_or_user.gravatar_token
  36 + elsif comment_or_user.email.present?
  37 + Digest::MD5.hexdigest(comment_or_user.email.downcase)
  38 + end
  39 + else nil
  40 + end
  41 + end
  42 +
  43 + def video_tag(path, options = {})
  44 + xml = Builder::XmlMarkup.new
  45 + xml.video :width => options[:width], :height => options[:height], :poster => options[:poster], :controls => "controls" do
  46 + xml.source :src => "#{path}.mp4?123", :type => "video/mp4"
  47 + # xml.source :src => "#{path}.m4v", :type => "video/mp4"
  48 + # xml.source :src => "#{path}.webm", :type => "video/webm"
  49 + # xml.source :src => "#{path}.ogv", :type => "video/ogg"
  50 + # xml.object :width => options[:width], :height => options[:height], :type => "application/x-shockwave-flash", :data => "/flash/flowplayer-3.2.7.swf" do
  51 + # xml.param :name => "movie", :value => "/flash/flowplayer-3.2.7.swf"
  52 + # xml.param :name => "allowfullscreen", :value => "true"
  53 + # xml.param :name => "bgcolor", :value => '#000000'
  54 + # xml.param :name => "flashvars", :value => %Q<config={"clip":{"url":"#{path}.mp4", "autoPlay":true, "autoBuffering":true}}>
  55 + # end
  56 + end.html_safe
4 57 end
5 58 end
14 app/helpers/comments_helper.rb
... ... @@ -1,6 +1,10 @@
1 1 module CommentsHelper
2   - def format_comment(content)
3   - simple_format(keep_spaces_at_beginning(h(content)))
  2 + def format_comment(comment)
  3 + if comment.legacy?
  4 + simple_format(keep_spaces_at_beginning(h(comment.content)))
  5 + else
  6 + CodeFormatter.new(comment.content).to_html.html_safe
  7 + end
4 8 end
5 9
6 10 def keep_spaces_at_beginning(content)
@@ -18,4 +22,10 @@ def fix_url(url)
18 22 "http://#{url}"
19 23 end
20 24 end
  25 +
  26 + def nested_comments(comments)
  27 + comments.map do |comment, sub_comments|
  28 + render(comment) + content_tag(:div, nested_comments(sub_comments), :class => "nested_comments")
  29 + end.join.html_safe
  30 + end
21 31 end
5 app/helpers/episodes_helper.rb
... ... @@ -1,7 +1,2 @@
1 1 module EpisodesHelper
2   - def fields_for_download(download, &block)
3   - new_or_existing = download.new_record? ? 'new' : 'existing'
4   - prefix = "episode[#{new_or_existing}_download_attributes][]"
5   - fields_for(prefix, download, &block)
6   - end
7 2 end
2  app/helpers/feedback_messages_helper.rb
... ... @@ -0,0 +1,2 @@
  1 +module FeedbackMessagesHelper
  2 +end
3  app/helpers/sessions_helper.rb
... ... @@ -1,3 +0,0 @@
1   -module SessionsHelper
2   -
3   -end
2  app/helpers/spam_checks_helper.rb
... ... @@ -1,2 +0,0 @@
1   -module SpamChecksHelper
2   -end
2  app/helpers/spam_questions_helper.rb
... ... @@ -1,2 +0,0 @@
1   -module SpamQuestionsHelper
2   -end
2  app/helpers/spam_reports_helper.rb
... ... @@ -1,2 +0,0 @@
1   -module SpamReportsHelper
2   -end
2  app/helpers/sponsors_helper.rb
... ... @@ -1,2 +0,0 @@
1   -module SponsorsHelper
2   -end
3  app/helpers/tags_helper.rb
... ... @@ -1,3 +0,0 @@
1   -module TagsHelper
2   -
3   -end
6 app/mailers/mailer.rb
... ... @@ -0,0 +1,6 @@
  1 +class Mailer < ActionMailer::Base
  2 + def feedback(message)
  3 + @message = message
  4 + mail :to => "feedback@railscasts.com", :from => @message.email, :subject => "Feedback from #{@message.name}"
  5 + end
  6 +end
25 app/models/ability.rb
... ... @@ -0,0 +1,25 @@
  1 +class Ability
  2 + include CanCan::Ability
  3 +
  4 + def initialize(user)
  5 + can :read, :episodes, ["published_at <= ?", Time.zone.now] do |episode|
  6 + episode.published_at <= Time.now.utc
  7 + end
  8 + can :access, :info
  9 + can :create, :feedback_messages
  10 + can [:read, :create, :login], :users
  11 +
  12 + if user
  13 + can :logout, :users
  14 + can :update, :users, :id => user.id
  15 + can :create, :comments
  16 + can [:update, :destroy], :comments do |comment|
  17 + comment.created_at >= 15.minutes.ago
  18 + end