admin_assistant 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. data/Rakefile +2 -2
  2. data/VERSION +1 -1
  3. data/admin_assistant.gemspec +404 -8
  4. data/rails_2_test/README +256 -0
  5. data/rails_2_test/Rakefile +13 -0
  6. data/rails_2_test/app/controllers/admin/appointments2_controller.rb +15 -0
  7. data/rails_2_test/app/controllers/admin/appointments_controller.rb +11 -0
  8. data/rails_2_test/app/controllers/admin/blog_posts2_controller.rb +138 -0
  9. data/rails_2_test/app/controllers/admin/blog_posts3_controller.rb +76 -0
  10. data/rails_2_test/app/controllers/admin/blog_posts4_controller.rb +21 -0
  11. data/rails_2_test/app/controllers/admin/blog_posts5_controller.rb +27 -0
  12. data/rails_2_test/app/controllers/admin/blog_posts6_controller.rb +10 -0
  13. data/rails_2_test/app/controllers/admin/blog_posts_controller.rb +8 -0
  14. data/rails_2_test/app/controllers/admin/blog_posts_custom_new_and_edit_controller.rb +15 -0
  15. data/rails_2_test/app/controllers/admin/blog_posts_read_only_controller.rb +19 -0
  16. data/rails_2_test/app/controllers/admin/bookmarks_controller.rb +11 -0
  17. data/rails_2_test/app/controllers/admin/comments2_controller.rb +14 -0
  18. data/rails_2_test/app/controllers/admin/comments_controller.rb +12 -0
  19. data/rails_2_test/app/controllers/admin/file_column_images2_controller.rb +10 -0
  20. data/rails_2_test/app/controllers/admin/file_column_images_controller.rb +6 -0
  21. data/rails_2_test/app/controllers/admin/images2_controller.rb +11 -0
  22. data/rails_2_test/app/controllers/admin/images_controller.rb +6 -0
  23. data/rails_2_test/app/controllers/admin/misconfigured1_controller.rb +7 -0
  24. data/rails_2_test/app/controllers/admin/not_migrated_yets_controller.rb +9 -0
  25. data/rails_2_test/app/controllers/admin/product_categories2_controller.rb +7 -0
  26. data/rails_2_test/app/controllers/admin/product_categories_controller.rb +5 -0
  27. data/rails_2_test/app/controllers/admin/products2_controller.rb +15 -0
  28. data/rails_2_test/app/controllers/admin/products_controller.rb +31 -0
  29. data/rails_2_test/app/controllers/admin/television_airings_controller.rb +5 -0
  30. data/rails_2_test/app/controllers/admin/television_time_slots_controller.rb +5 -0
  31. data/rails_2_test/app/controllers/admin/users2_controller.rb +10 -0
  32. data/rails_2_test/app/controllers/admin/users_controller.rb +63 -0
  33. data/rails_2_test/app/controllers/application.rb +16 -0
  34. data/rails_2_test/app/controllers/application_controller.rb +16 -0
  35. data/rails_2_test/app/controllers/blog_posts_controller.rb +5 -0
  36. data/rails_2_test/app/helpers/admin/appointments2_helper.rb +2 -0
  37. data/rails_2_test/app/helpers/admin/appointments_helper.rb +2 -0
  38. data/rails_2_test/app/helpers/admin/blog_posts2_helper.rb +27 -0
  39. data/rails_2_test/app/helpers/admin/blog_posts3_helper.rb +2 -0
  40. data/rails_2_test/app/helpers/admin/blog_posts4_helper.rb +2 -0
  41. data/rails_2_test/app/helpers/admin/blog_posts6_helper.rb +16 -0
  42. data/rails_2_test/app/helpers/admin/blog_posts_custom_new_and_edit_helper.rb +29 -0
  43. data/rails_2_test/app/helpers/admin/blog_posts_helper.rb +2 -0
  44. data/rails_2_test/app/helpers/admin/blog_posts_read_only_helper.rb +2 -0
  45. data/rails_2_test/app/helpers/admin/bookmarks_helper.rb +2 -0
  46. data/rails_2_test/app/helpers/admin/comments2_helper.rb +2 -0
  47. data/rails_2_test/app/helpers/admin/comments_helper.rb +2 -0
  48. data/rails_2_test/app/helpers/admin/file_column_images2_helper.rb +2 -0
  49. data/rails_2_test/app/helpers/admin/file_column_images_helper.rb +2 -0
  50. data/rails_2_test/app/helpers/admin/images2_helper.rb +8 -0
  51. data/rails_2_test/app/helpers/admin/images_helper.rb +2 -0
  52. data/rails_2_test/app/helpers/admin/misconfigured1_helper.rb +2 -0
  53. data/rails_2_test/app/helpers/admin/not_migrated_yets_helper.rb +2 -0
  54. data/rails_2_test/app/helpers/admin/product_categories2_helper.rb +2 -0
  55. data/rails_2_test/app/helpers/admin/product_categories_helper.rb +2 -0
  56. data/rails_2_test/app/helpers/admin/products2_helper.rb +3 -0
  57. data/rails_2_test/app/helpers/admin/products_helper.rb +6 -0
  58. data/rails_2_test/app/helpers/admin/television_airings_helper.rb +2 -0
  59. data/rails_2_test/app/helpers/admin/television_time_slots_helper.rb +2 -0
  60. data/rails_2_test/app/helpers/admin/users2_helper.rb +2 -0
  61. data/rails_2_test/app/helpers/admin/users_helper.rb +25 -0
  62. data/rails_2_test/app/helpers/application_helper.rb +3 -0
  63. data/rails_2_test/app/helpers/blog_posts_helper.rb +2 -0
  64. data/rails_2_test/app/models/appointment.rb +5 -0
  65. data/rails_2_test/app/models/blog_post.rb +14 -0
  66. data/rails_2_test/app/models/blog_post_tag.rb +6 -0
  67. data/rails_2_test/app/models/bookmark.rb +6 -0
  68. data/rails_2_test/app/models/comment.rb +4 -0
  69. data/rails_2_test/app/models/file_column_image.rb +3 -0
  70. data/rails_2_test/app/models/image.rb +3 -0
  71. data/rails_2_test/app/models/not_migrated_yet.rb +2 -0
  72. data/rails_2_test/app/models/product.rb +7 -0
  73. data/rails_2_test/app/models/product_category.rb +9 -0
  74. data/rails_2_test/app/models/tag.rb +4 -0
  75. data/rails_2_test/app/models/television_airing.rb +3 -0
  76. data/rails_2_test/app/models/television_time_slot.rb +11 -0
  77. data/rails_2_test/app/models/user.rb +14 -0
  78. data/rails_2_test/app/views/admin/appointments/_subject_input.html.erb +2 -0
  79. data/rails_2_test/app/views/admin/appointments2/_time_input.html.erb +31 -0
  80. data/rails_2_test/app/views/admin/blog_posts2/_after_form.html.erb +5 -0
  81. data/rails_2_test/app/views/admin/blog_posts2/_after_index.html.erb +1 -0
  82. data/rails_2_test/app/views/admin/blog_posts2/_after_tags_input.html.erb +16 -0
  83. data/rails_2_test/app/views/admin/blog_posts2/_before_index.html.erb +2 -0
  84. data/rails_2_test/app/views/admin/blog_posts5/_after_index_header.html.erb +8 -0
  85. data/rails_2_test/app/views/admin/blog_posts_read_only/_body_for_show.html.erb +1 -0
  86. data/rails_2_test/app/views/admin/products/_name_input.html.erb +2 -0
  87. data/rails_2_test/app/views/admin/products/_percent_off_input.html.erb +2 -0
  88. data/rails_2_test/app/views/admin/products/_price_input.html.erb +10 -0
  89. data/rails_2_test/app/views/blog_posts/show.html.erb +13 -0
  90. data/rails_2_test/app/views/layouts/admin.html.erb +31 -0
  91. data/rails_2_test/config/boot.rb +109 -0
  92. data/rails_2_test/config/database.yml +28 -0
  93. data/rails_2_test/config/environment.rb +78 -0
  94. data/rails_2_test/config/environments/development.rb +17 -0
  95. data/rails_2_test/config/environments/production.rb +24 -0
  96. data/rails_2_test/config/environments/test.rb +24 -0
  97. data/rails_2_test/config/initializers/inflections.rb +10 -0
  98. data/rails_2_test/config/initializers/mime_types.rb +5 -0
  99. data/rails_2_test/config/initializers/new_rails_defaults.rb +17 -0
  100. data/rails_2_test/config/locales/en.yml +5 -0
  101. data/rails_2_test/config/routes.rb +43 -0
  102. data/rails_2_test/db/migrate/20090213215514_create_blog_posts.rb +12 -0
  103. data/rails_2_test/db/migrate/20090217225542_add_body_to_blog_posts.rb +9 -0
  104. data/rails_2_test/db/migrate/20090221220917_create_tags.rb +13 -0
  105. data/rails_2_test/db/migrate/20090221220947_create_blog_post_tags.rb +14 -0
  106. data/rails_2_test/db/migrate/20090222162204_add_textile_to_blog_posts.rb +9 -0
  107. data/rails_2_test/db/migrate/20090222163231_add_published_at_to_blog_posts.rb +9 -0
  108. data/rails_2_test/db/migrate/20090301191722_create_images.rb +16 -0
  109. data/rails_2_test/db/migrate/20090305165345_create_accounts.rb +14 -0
  110. data/rails_2_test/db/migrate/20090307225027_rename_accounts_to_users.rb +9 -0
  111. data/rails_2_test/db/migrate/20090307225750_add_user_id_to_blog_posts.rb +9 -0
  112. data/rails_2_test/db/migrate/20090309185114_change_blog_posts_textile.rb +9 -0
  113. data/rails_2_test/db/migrate/20090309193635_create_products.rb +14 -0
  114. data/rails_2_test/db/migrate/20090309203056_create_comments.rb +15 -0
  115. data/rails_2_test/db/migrate/20090323005947_create_file_column_images.rb +12 -0
  116. data/rails_2_test/db/migrate/20090326160049_add_birthday_to_users.rb +9 -0
  117. data/rails_2_test/db/migrate/20090326223606_add_state_to_users.rb +9 -0
  118. data/rails_2_test/db/migrate/20090503134004_add_file_column_image_to_products.rb +9 -0
  119. data/rails_2_test/db/migrate/20090617173651_create_bookmarks.rb +15 -0
  120. data/rails_2_test/db/migrate/20090624165355_add_tags_string_to_blog_post.rb +9 -0
  121. data/rails_2_test/db/migrate/20090625144313_add_avatar_fields_to_user.rb +11 -0
  122. data/rails_2_test/db/migrate/20090629202956_add_merged_into_to_blog_posts.rb +9 -0
  123. data/rails_2_test/db/migrate/20090701171857_add_force_textile_to_users.rb +9 -0
  124. data/rails_2_test/db/migrate/20090704163647_add_deleted_at_to_products.rb +9 -0
  125. data/rails_2_test/db/migrate/20090704173800_add_sale_fields_to_products.rb +13 -0
  126. data/rails_2_test/db/migrate/20090714024501_create_product_categories.rb +15 -0
  127. data/rails_2_test/db/migrate/20090819162835_add_admin_level_to_users.rb +9 -0
  128. data/rails_2_test/db/migrate/20091115134559_add_first_and_last_names_to_users.rb +11 -0
  129. data/rails_2_test/db/migrate/20091221011256_add_position_to_product_categories.rb +9 -0
  130. data/rails_2_test/db/migrate/20091222160814_create_appointments.rb +14 -0
  131. data/rails_2_test/db/migrate/20091227224547_add_user_id_to_appointments.rb +9 -0
  132. data/rails_2_test/db/migrate/20100214213359_create_television_time_slots.rb +13 -0
  133. data/rails_2_test/db/migrate/20100214213451_create_television_airings.rb +15 -0
  134. data/rails_2_test/doc/README_FOR_APP +5 -0
  135. data/rails_2_test/lib/tasks/rspec.rake +163 -0
  136. data/rails_2_test/public/404.html +30 -0
  137. data/rails_2_test/public/422.html +30 -0
  138. data/rails_2_test/public/500.html +33 -0
  139. data/rails_2_test/public/dispatch.cgi +10 -0
  140. data/rails_2_test/public/dispatch.fcgi +24 -0
  141. data/rails_2_test/public/dispatch.rb +10 -0
  142. data/rails_2_test/public/favicon.ico +0 -0
  143. data/rails_2_test/public/images/rails.png +0 -0
  144. data/rails_2_test/public/index.html +274 -0
  145. data/rails_2_test/public/javascripts/application.js +2 -0
  146. data/rails_2_test/public/javascripts/jquery-1.4.4.min.js +167 -0
  147. data/rails_2_test/public/robots.txt +5 -0
  148. data/rails_2_test/public/stylesheets/admin.css +3 -0
  149. data/rails_2_test/public/stylesheets/scaffold.css +54 -0
  150. data/rails_2_test/script/about +4 -0
  151. data/rails_2_test/script/autospec +5 -0
  152. data/rails_2_test/script/console +3 -0
  153. data/rails_2_test/script/dbconsole +3 -0
  154. data/rails_2_test/script/destroy +3 -0
  155. data/rails_2_test/script/generate +3 -0
  156. data/rails_2_test/script/performance/benchmarker +3 -0
  157. data/rails_2_test/script/performance/profiler +3 -0
  158. data/rails_2_test/script/performance/request +3 -0
  159. data/rails_2_test/script/plugin +3 -0
  160. data/rails_2_test/script/populate_tables.rb +49 -0
  161. data/rails_2_test/script/process/inspector +3 -0
  162. data/rails_2_test/script/process/reaper +3 -0
  163. data/rails_2_test/script/process/spawner +3 -0
  164. data/rails_2_test/script/runner +3 -0
  165. data/rails_2_test/script/server +3 -0
  166. data/rails_2_test/script/spec +5 -0
  167. data/rails_2_test/script/spec_server +125 -0
  168. data/rails_2_test/test/data/ruby_throated.jpg +0 -0
  169. data/rails_2_test/test/data/tweenbot.jpg +0 -0
  170. data/rails_2_test/test/fixtures/file_column_images.yml +7 -0
  171. data/rails_2_test/test/integration/admin/appointments2_integration_test.rb +79 -0
  172. data/rails_2_test/test/integration/admin/appointments_integration_test.rb +367 -0
  173. data/rails_2_test/test/integration/admin/blog_posts2_integration_test.rb +806 -0
  174. data/rails_2_test/test/integration/admin/blog_posts3_integration_test.rb +418 -0
  175. data/rails_2_test/test/integration/admin/blog_posts4_integration_test.rb +189 -0
  176. data/rails_2_test/test/integration/admin/blog_posts5_integration_test.rb +75 -0
  177. data/rails_2_test/test/integration/admin/blog_posts6_integration_test.rb +39 -0
  178. data/rails_2_test/test/integration/admin/blog_posts_custom_new_and_edit_integration_test.rb +89 -0
  179. data/rails_2_test/test/integration/admin/blog_posts_integration_test.rb +788 -0
  180. data/rails_2_test/test/integration/admin/blog_posts_read_only_integration_test.rb +69 -0
  181. data/rails_2_test/test/integration/admin/bookmarks_integration_test.rb +445 -0
  182. data/rails_2_test/test/integration/admin/comments2_integration_test.rb +52 -0
  183. data/rails_2_test/test/integration/admin/comments_integration_test.rb +50 -0
  184. data/rails_2_test/test/integration/admin/file_column_images2_integration_test.rb +19 -0
  185. data/rails_2_test/test/integration/admin/file_column_images_integration_test.rb +69 -0
  186. data/rails_2_test/test/integration/admin/images2_integration_test.rb +33 -0
  187. data/rails_2_test/test/integration/admin/images_integration_test.rb +79 -0
  188. data/rails_2_test/test/integration/admin/misconfigured1_integration_test.rb +17 -0
  189. data/rails_2_test/test/integration/admin/product_categories2_integration_test.rb +179 -0
  190. data/rails_2_test/test/integration/admin/product_categories_integration_test.rb +12 -0
  191. data/rails_2_test/test/integration/admin/products2_integration_test.rb +155 -0
  192. data/rails_2_test/test/integration/admin/products_integration_test.rb +210 -0
  193. data/rails_2_test/test/integration/admin/television_airings_integration_test.rb +25 -0
  194. data/rails_2_test/test/integration/admin/users2_integration_test.rb +48 -0
  195. data/rails_2_test/test/integration/admin/users_integration_test.rb +266 -0
  196. data/rails_2_test/test/integration/blog_posts_integration_test.rb +9 -0
  197. data/rails_2_test/test/test_helper.rb +114 -0
  198. data/rails_2_test/vendor/plugins/file_column/CHANGELOG +69 -0
  199. data/rails_2_test/vendor/plugins/file_column/README +54 -0
  200. data/rails_2_test/vendor/plugins/file_column/Rakefile +36 -0
  201. data/rails_2_test/vendor/plugins/file_column/TODO +6 -0
  202. data/rails_2_test/vendor/plugins/file_column/init.rb +13 -0
  203. data/rails_2_test/vendor/plugins/file_column/lib/file_column.rb +723 -0
  204. data/rails_2_test/vendor/plugins/file_column/lib/file_column_helper.rb +150 -0
  205. data/rails_2_test/vendor/plugins/file_column/lib/file_compat.rb +28 -0
  206. data/rails_2_test/vendor/plugins/file_column/lib/magick_file_column.rb +260 -0
  207. data/rails_2_test/vendor/plugins/file_column/lib/rails_file_column.rb +19 -0
  208. data/rails_2_test/vendor/plugins/file_column/lib/test_case.rb +124 -0
  209. data/rails_2_test/vendor/plugins/file_column/lib/validations.rb +112 -0
  210. data/rails_2_test/vendor/plugins/file_column/test/abstract_unit.rb +63 -0
  211. data/rails_2_test/vendor/plugins/file_column/test/connection.rb +17 -0
  212. data/rails_2_test/vendor/plugins/file_column/test/file_column_helper_test.rb +97 -0
  213. data/rails_2_test/vendor/plugins/file_column/test/file_column_test.rb +650 -0
  214. data/rails_2_test/vendor/plugins/file_column/test/fixtures/entry.rb +32 -0
  215. data/rails_2_test/vendor/plugins/file_column/test/fixtures/invalid-image.jpg +1 -0
  216. data/rails_2_test/vendor/plugins/file_column/test/fixtures/kerb.jpg +0 -0
  217. data/rails_2_test/vendor/plugins/file_column/test/fixtures/mysql.sql +25 -0
  218. data/rails_2_test/vendor/plugins/file_column/test/fixtures/schema.rb +10 -0
  219. data/rails_2_test/vendor/plugins/file_column/test/fixtures/skanthak.png +0 -0
  220. data/rails_2_test/vendor/plugins/file_column/test/magick_test.rb +380 -0
  221. data/rails_2_test/vendor/plugins/file_column/test/magick_view_only_test.rb +21 -0
  222. data/rails_3_test/.gitignore +4 -0
  223. data/rails_3_test/Gemfile +12 -0
  224. data/rails_3_test/Gemfile.lock +100 -0
  225. data/rails_3_test/README +256 -0
  226. data/rails_3_test/Rakefile +7 -0
  227. data/rails_3_test/app/controllers/admin/appointments2_controller.rb +15 -0
  228. data/rails_3_test/app/controllers/admin/appointments_controller.rb +11 -0
  229. data/rails_3_test/app/controllers/admin/blog_posts2_controller.rb +138 -0
  230. data/rails_3_test/app/controllers/admin/blog_posts3_controller.rb +76 -0
  231. data/rails_3_test/app/controllers/admin/blog_posts4_controller.rb +21 -0
  232. data/rails_3_test/app/controllers/admin/blog_posts5_controller.rb +27 -0
  233. data/rails_3_test/app/controllers/admin/blog_posts6_controller.rb +10 -0
  234. data/rails_3_test/app/controllers/admin/blog_posts_controller.rb +9 -0
  235. data/rails_3_test/app/controllers/admin/blog_posts_custom_new_and_edit_controller.rb +15 -0
  236. data/rails_3_test/app/controllers/admin/blog_posts_read_only_controller.rb +19 -0
  237. data/rails_3_test/app/controllers/admin/bookmarks_controller.rb +11 -0
  238. data/rails_3_test/app/controllers/admin/comments2_controller.rb +14 -0
  239. data/rails_3_test/app/controllers/admin/comments_controller.rb +12 -0
  240. data/rails_3_test/app/controllers/admin/images2_controller.rb +11 -0
  241. data/rails_3_test/app/controllers/admin/images_controller.rb +6 -0
  242. data/rails_3_test/app/controllers/admin/misconfigured1_controller.rb +7 -0
  243. data/rails_3_test/app/controllers/admin/not_migrated_yets_controller.rb +9 -0
  244. data/rails_3_test/app/controllers/admin/product_categories2_controller.rb +7 -0
  245. data/rails_3_test/app/controllers/admin/product_categories_controller.rb +5 -0
  246. data/rails_3_test/app/controllers/admin/television_airings_controller.rb +5 -0
  247. data/rails_3_test/app/controllers/admin/television_time_slots_controller.rb +5 -0
  248. data/rails_3_test/app/controllers/admin/users2_controller.rb +10 -0
  249. data/rails_3_test/app/controllers/admin/users_controller.rb +48 -0
  250. data/rails_3_test/app/controllers/application_controller.rb +7 -0
  251. data/rails_3_test/app/controllers/blog_posts_controller.rb +5 -0
  252. data/rails_3_test/app/helpers/admin/appointments_helper.rb +2 -0
  253. data/rails_3_test/app/helpers/admin/blog_posts2_helper.rb +27 -0
  254. data/rails_3_test/app/helpers/admin/blog_posts3_helper.rb +2 -0
  255. data/rails_3_test/app/helpers/admin/blog_posts4_helper.rb +2 -0
  256. data/rails_3_test/app/helpers/admin/blog_posts6_helper.rb +13 -0
  257. data/rails_3_test/app/helpers/admin/blog_posts_custom_new_and_edit_helper.rb +29 -0
  258. data/rails_3_test/app/helpers/admin/blog_posts_helper.rb +2 -0
  259. data/rails_3_test/app/helpers/admin/blog_posts_read_only_helper.rb +2 -0
  260. data/rails_3_test/app/helpers/admin/bookmarks_helper.rb +2 -0
  261. data/rails_3_test/app/helpers/admin/comments2_helper.rb +2 -0
  262. data/rails_3_test/app/helpers/admin/comments_helper.rb +2 -0
  263. data/rails_3_test/app/helpers/admin/images2_helper.rb +8 -0
  264. data/rails_3_test/app/helpers/admin/images_helper.rb +2 -0
  265. data/rails_3_test/app/helpers/admin/misconfigured1_helper.rb +2 -0
  266. data/rails_3_test/app/helpers/admin/not_migrated_yets_helper.rb +2 -0
  267. data/rails_3_test/app/helpers/admin/product_categories2_helper.rb +2 -0
  268. data/rails_3_test/app/helpers/admin/product_categories_helper.rb +2 -0
  269. data/rails_3_test/app/helpers/admin/television_airings_helper.rb +2 -0
  270. data/rails_3_test/app/helpers/admin/television_time_slots_helper.rb +2 -0
  271. data/rails_3_test/app/helpers/admin/users2_helper.rb +2 -0
  272. data/rails_3_test/app/helpers/admin/users_helper.rb +13 -0
  273. data/rails_3_test/app/helpers/application_helper.rb +2 -0
  274. data/rails_3_test/app/models/appointment.rb +5 -0
  275. data/rails_3_test/app/models/blog_post.rb +14 -0
  276. data/rails_3_test/app/models/blog_post_tag.rb +6 -0
  277. data/rails_3_test/app/models/bookmark.rb +6 -0
  278. data/rails_3_test/app/models/comment.rb +4 -0
  279. data/rails_3_test/app/models/image.rb +3 -0
  280. data/rails_3_test/app/models/not_migrated_yet.rb +2 -0
  281. data/rails_3_test/app/models/product.rb +5 -0
  282. data/rails_3_test/app/models/product_category.rb +9 -0
  283. data/rails_3_test/app/models/tag.rb +4 -0
  284. data/rails_3_test/app/models/television_airing.rb +3 -0
  285. data/rails_3_test/app/models/television_time_slot.rb +11 -0
  286. data/rails_3_test/app/models/user.rb +11 -0
  287. data/rails_3_test/app/views/admin/appointments/_subject_input.html.erb +2 -0
  288. data/rails_3_test/app/views/admin/appointments2/_time_input.html.erb +31 -0
  289. data/rails_3_test/app/views/admin/blog_posts2/_after_form.html.erb +5 -0
  290. data/rails_3_test/app/views/admin/blog_posts2/_after_index.html.erb +1 -0
  291. data/rails_3_test/app/views/admin/blog_posts2/_after_tags_input.html.erb +16 -0
  292. data/rails_3_test/app/views/admin/blog_posts2/_before_index.html.erb +2 -0
  293. data/rails_3_test/app/views/admin/blog_posts5/_after_index_header.html.erb +8 -0
  294. data/rails_3_test/app/views/admin/blog_posts_read_only/_body_for_show.html.erb +1 -0
  295. data/rails_3_test/app/views/layouts/admin.html.erb +32 -0
  296. data/rails_3_test/app/views/layouts/application.html.erb +14 -0
  297. data/rails_3_test/config/application.rb +42 -0
  298. data/rails_3_test/config/boot.rb +6 -0
  299. data/rails_3_test/config/database.yml +22 -0
  300. data/rails_3_test/config/environment.rb +5 -0
  301. data/rails_3_test/config/environments/development.rb +26 -0
  302. data/rails_3_test/config/environments/production.rb +49 -0
  303. data/rails_3_test/config/environments/test.rb +35 -0
  304. data/rails_3_test/config/initializers/backtrace_silencers.rb +7 -0
  305. data/rails_3_test/config/initializers/inflections.rb +10 -0
  306. data/rails_3_test/config/initializers/mime_types.rb +5 -0
  307. data/rails_3_test/config/initializers/secret_token.rb +7 -0
  308. data/rails_3_test/config/initializers/session_store.rb +8 -0
  309. data/rails_3_test/config/locales/en.yml +5 -0
  310. data/rails_3_test/config/routes.rb +63 -0
  311. data/rails_3_test/config.ru +4 -0
  312. data/rails_3_test/db/migrate/20090213215514_create_blog_posts.rb +12 -0
  313. data/rails_3_test/db/migrate/20090217225542_add_body_to_blog_posts.rb +9 -0
  314. data/rails_3_test/db/migrate/20090221220917_create_tags.rb +13 -0
  315. data/rails_3_test/db/migrate/20090221220947_create_blog_post_tags.rb +14 -0
  316. data/rails_3_test/db/migrate/20090222162204_add_textile_to_blog_posts.rb +9 -0
  317. data/rails_3_test/db/migrate/20090222163231_add_published_at_to_blog_posts.rb +9 -0
  318. data/rails_3_test/db/migrate/20090301191722_create_images.rb +16 -0
  319. data/rails_3_test/db/migrate/20090305165345_create_accounts.rb +14 -0
  320. data/rails_3_test/db/migrate/20090307225027_rename_accounts_to_users.rb +9 -0
  321. data/rails_3_test/db/migrate/20090307225750_add_user_id_to_blog_posts.rb +9 -0
  322. data/rails_3_test/db/migrate/20090309185114_change_blog_posts_textile.rb +9 -0
  323. data/rails_3_test/db/migrate/20090309193635_create_products.rb +14 -0
  324. data/rails_3_test/db/migrate/20090309203056_create_comments.rb +15 -0
  325. data/rails_3_test/db/migrate/20090323005947_create_file_column_images.rb +12 -0
  326. data/rails_3_test/db/migrate/20090326160049_add_birthday_to_users.rb +9 -0
  327. data/rails_3_test/db/migrate/20090326223606_add_state_to_users.rb +9 -0
  328. data/rails_3_test/db/migrate/20090503134004_add_file_column_image_to_products.rb +9 -0
  329. data/rails_3_test/db/migrate/20090617173651_create_bookmarks.rb +15 -0
  330. data/rails_3_test/db/migrate/20090624165355_add_tags_string_to_blog_post.rb +9 -0
  331. data/rails_3_test/db/migrate/20090625144313_add_avatar_fields_to_user.rb +11 -0
  332. data/rails_3_test/db/migrate/20090629202956_add_merged_into_to_blog_posts.rb +9 -0
  333. data/rails_3_test/db/migrate/20090701171857_add_force_textile_to_users.rb +9 -0
  334. data/rails_3_test/db/migrate/20090704163647_add_deleted_at_to_products.rb +9 -0
  335. data/rails_3_test/db/migrate/20090704173800_add_sale_fields_to_products.rb +13 -0
  336. data/rails_3_test/db/migrate/20090714024501_create_product_categories.rb +15 -0
  337. data/rails_3_test/db/migrate/20090819162835_add_admin_level_to_users.rb +9 -0
  338. data/rails_3_test/db/migrate/20091115134559_add_first_and_last_names_to_users.rb +11 -0
  339. data/rails_3_test/db/migrate/20091221011256_add_position_to_product_categories.rb +9 -0
  340. data/rails_3_test/db/migrate/20091222160814_create_appointments.rb +14 -0
  341. data/rails_3_test/db/migrate/20091227224547_add_user_id_to_appointments.rb +9 -0
  342. data/rails_3_test/db/migrate/20100214213359_create_television_time_slots.rb +13 -0
  343. data/rails_3_test/db/migrate/20100214213451_create_television_airings.rb +15 -0
  344. data/rails_3_test/db/migrate/20110426215702_remove_avatar_fields_from_users.rb +11 -0
  345. data/rails_3_test/db/seeds.rb +7 -0
  346. data/rails_3_test/doc/README_FOR_APP +2 -0
  347. data/rails_3_test/lib/tasks/.gitkeep +0 -0
  348. data/rails_3_test/public/404.html +26 -0
  349. data/rails_3_test/public/422.html +26 -0
  350. data/rails_3_test/public/500.html +26 -0
  351. data/rails_3_test/public/favicon.ico +0 -0
  352. data/rails_3_test/public/images/rails.png +0 -0
  353. data/rails_3_test/public/index.html +239 -0
  354. data/rails_3_test/public/javascripts/application.js +2 -0
  355. data/rails_3_test/public/javascripts/jquery-1.4.4.min.js +167 -0
  356. data/rails_3_test/public/javascripts/rails.js +191 -0
  357. data/rails_3_test/public/robots.txt +5 -0
  358. data/rails_3_test/public/stylesheets/.gitkeep +0 -0
  359. data/rails_3_test/public/stylesheets/admin.css +3 -0
  360. data/rails_3_test/public/stylesheets/scaffold.css +54 -0
  361. data/rails_3_test/script/rails +6 -0
  362. data/rails_3_test/test/data/ruby_throated.jpg +0 -0
  363. data/rails_3_test/test/data/tweenbot.jpg +0 -0
  364. data/rails_3_test/test/fixtures/placeholder.txt +0 -0
  365. data/rails_3_test/test/integration/admin/appointments2_integration_test.rb +79 -0
  366. data/rails_3_test/test/integration/admin/appointments_integration_test.rb +367 -0
  367. data/rails_3_test/test/integration/admin/blog_posts2_integration_test.rb +789 -0
  368. data/rails_3_test/test/integration/admin/blog_posts3_integration_test.rb +418 -0
  369. data/rails_3_test/test/integration/admin/blog_posts4_integration_test.rb +189 -0
  370. data/rails_3_test/test/integration/admin/blog_posts5_integration_test.rb +75 -0
  371. data/rails_3_test/test/integration/admin/blog_posts6_integration_test.rb +39 -0
  372. data/rails_3_test/test/integration/admin/blog_posts_custom_new_and_edit_integration_test.rb +89 -0
  373. data/rails_3_test/test/integration/admin/blog_posts_integration_test.rb +784 -0
  374. data/rails_3_test/test/integration/admin/blog_posts_read_only_integration_test.rb +69 -0
  375. data/rails_3_test/test/integration/admin/bookmarks_integration_test.rb +445 -0
  376. data/rails_3_test/test/integration/admin/comments2_integration_test.rb +52 -0
  377. data/rails_3_test/test/integration/admin/comments_integration_test.rb +50 -0
  378. data/rails_3_test/test/integration/admin/images2_integration_test.rb +33 -0
  379. data/rails_3_test/test/integration/admin/images_integration_test.rb +79 -0
  380. data/rails_3_test/test/integration/admin/misconfigured1_integration_test.rb +21 -0
  381. data/rails_3_test/test/integration/admin/product_categories2_integration_test.rb +179 -0
  382. data/rails_3_test/test/integration/admin/product_categories_integration_test.rb +12 -0
  383. data/rails_3_test/test/integration/admin/television_airings_integration_test.rb +25 -0
  384. data/rails_3_test/test/integration/admin/users2_integration_test.rb +48 -0
  385. data/rails_3_test/test/integration/admin/users_integration_test.rb +182 -0
  386. data/rails_3_test/test/integration/blog_posts_integration_test.rb +10 -0
  387. data/rails_3_test/test/performance/browsing_test.rb +9 -0
  388. data/rails_3_test/test/test_helper.rb +98 -0
  389. data/rails_3_test/vendor/plugins/.gitkeep +0 -0
  390. data/website/_layouts/api.html +20 -17
  391. data/website/_layouts/api1.html +42 -0
  392. data/website/_layouts/default.html +42 -18
  393. data/website/api/core.markdown +6 -3
  394. data/website/api/destroy.markdown +4 -2
  395. data/website/api/form.markdown +6 -5
  396. data/website/api/idx.markdown +8 -7
  397. data/website/api/index.markdown +9 -7
  398. data/website/api/search.markdown +5 -3
  399. data/website/api/show.markdown +4 -2
  400. data/website/community.markdown +3 -2
  401. data/website/css/main.css +83 -17
  402. data/website/design_principles.markdown +3 -8
  403. data/website/index.markdown +13 -9
  404. data/website/js/lightbox.js +2 -2
  405. data/website/quick_start.markdown +10 -10
  406. data/website/screenshots.markdown +11 -11
  407. data/website/tutorial.markdown +23 -14
  408. data/website/v1/api/core.markdown +108 -0
  409. data/website/v1/api/destroy.markdown +27 -0
  410. data/website/v1/api/form.markdown +293 -0
  411. data/website/v1/api/idx.markdown +288 -0
  412. data/website/v1/api/index.markdown +149 -0
  413. data/website/v1/api/search.markdown +110 -0
  414. data/website/v1/api/show.markdown +24 -0
  415. data/website/v1/index.markdown +10 -0
  416. data/website/v1/quick_start.markdown +48 -0
  417. data/website/v1/tutorial.markdown +60 -0
  418. metadata +407 -9
@@ -0,0 +1,150 @@
1
+ # This module contains helper methods for displaying and uploading files
2
+ # for attributes created by +FileColumn+'s +file_column+ method. It will be
3
+ # automatically included into ActionView::Base, thereby making this module's
4
+ # methods available in all your views.
5
+ module FileColumnHelper
6
+
7
+ # Use this helper to create an upload field for a file_column attribute. This will generate
8
+ # an additional hidden field to keep uploaded files during form-redisplays. For example,
9
+ # when called with
10
+ #
11
+ # <%= file_column_field("entry", "image") %>
12
+ #
13
+ # the following HTML will be generated (assuming the form is redisplayed and something has
14
+ # already been uploaded):
15
+ #
16
+ # <input type="hidden" name="entry[image_temp]" value="..." />
17
+ # <input type="file" name="entry[image]" />
18
+ #
19
+ # You can use the +option+ argument to pass additional options to the file-field tag.
20
+ #
21
+ # Be sure to set the enclosing form's encoding to 'multipart/form-data', by
22
+ # using something like this:
23
+ #
24
+ # <%= form_tag {:action => "create", ...}, :multipart => true %>
25
+ def file_column_field(object, method, options={})
26
+ result = ActionView::Helpers::InstanceTag.new(object.dup, method.to_s+"_temp", self).to_input_field_tag("hidden", {})
27
+ result << ActionView::Helpers::InstanceTag.new(object.dup, method, self).to_input_field_tag("file", options)
28
+ end
29
+
30
+ # Creates an URL where an uploaded file can be accessed. When called for an Entry object with
31
+ # id 42 (stored in <tt>@entry</tt>) like this
32
+ #
33
+ # <%= url_for_file_column(@entry, "image")
34
+ #
35
+ # the following URL will be produced, assuming the file "test.png" has been stored in
36
+ # the "image"-column of an Entry object stored in <tt>@entry</tt>:
37
+ #
38
+ # /entry/image/42/test.png
39
+ #
40
+ # This will produce a valid URL even for temporary uploaded files, e.g. files where the object
41
+ # they are belonging to has not been saved in the database yet.
42
+ #
43
+ # The URL produces, although starting with a slash, will be relative
44
+ # to your app's root. If you pass it to one rails' +image_tag+
45
+ # helper, rails will properly convert it to an absolute
46
+ # URL. However, this will not be the case, if you create a link with
47
+ # the +link_to+ helper. In this case, you can pass <tt>:absolute =>
48
+ # true</tt> to +options+, which will make sure, the generated URL is
49
+ # absolute on your server. Examples:
50
+ #
51
+ # <%= image_tag url_for_file_column(@entry, "image") %>
52
+ # <%= link_to "Download", url_for_file_column(@entry, "image", :absolute => true) %>
53
+ #
54
+ # If there is currently no uploaded file stored in the object's column this method will
55
+ # return +nil+.
56
+ def url_for_file_column(object, method, options=nil)
57
+ case object
58
+ when String, Symbol
59
+ object = instance_variable_get("@#{object.to_s}")
60
+ end
61
+
62
+ # parse options
63
+ subdir = nil
64
+ absolute = false
65
+ if options
66
+ case options
67
+ when Hash
68
+ subdir = options[:subdir]
69
+ absolute = options[:absolute]
70
+ when String, Symbol
71
+ subdir = options
72
+ end
73
+ end
74
+
75
+ relative_path = object.send("#{method}_relative_path", subdir)
76
+ return nil unless relative_path
77
+
78
+ url = ""
79
+ url << request.relative_url_root.to_s if absolute
80
+ url << "/"
81
+ url << object.send("#{method}_options")[:base_url] << "/"
82
+ url << relative_path
83
+ end
84
+
85
+ # Same as +url_for_file_colum+ but allows you to access different versions
86
+ # of the image that have been processed by RMagick.
87
+ #
88
+ # If your +options+ parameter is non-nil this will
89
+ # access a different version of an image that will be produced by
90
+ # RMagick. You can use the following types for +options+:
91
+ #
92
+ # * a <tt>:symbol</tt> will select a version defined in the model
93
+ # via FileColumn::Magick's <tt>:versions</tt> feature.
94
+ # * a <tt>geometry_string</tt> will dynamically create an
95
+ # image resized as specified by <tt>geometry_string</tt>. The image will
96
+ # be stored so that it does not have to be recomputed the next time the
97
+ # same version string is used.
98
+ # * <tt>some_hash</tt> will dynamically create an image
99
+ # that is created according to the options in <tt>some_hash</tt>. This
100
+ # accepts exactly the same options as Magick's version feature.
101
+ #
102
+ # The version produced by RMagick will be stored in a special sub-directory.
103
+ # The directory's name will be derived from the options you specified
104
+ # (via a hash function) but if you want
105
+ # to set it yourself, you can use the <tt>:name => name</tt> option.
106
+ #
107
+ # Examples:
108
+ #
109
+ # <%= url_for_image_column @entry, "image", "640x480" %>
110
+ #
111
+ # will produce an URL like this
112
+ #
113
+ # /entry/image/42/bdn19n/filename.jpg
114
+ # # "640x480".hash.abs.to_s(36) == "bdn19n"
115
+ #
116
+ # and
117
+ #
118
+ # <%= url_for_image_column @entry, "image",
119
+ # :size => "50x50", :crop => "1:1", :name => "thumb" %>
120
+ #
121
+ # will produce something like this:
122
+ #
123
+ # /entry/image/42/thumb/filename.jpg
124
+ #
125
+ # Hint: If you are using the same geometry string / options hash multiple times, you should
126
+ # define it in a helper to stay with DRY. Another option is to define it in the model via
127
+ # FileColumn::Magick's <tt>:versions</tt> feature and then refer to it via a symbol.
128
+ #
129
+ # The URL produced by this method is relative to your application's root URL,
130
+ # although it will start with a slash.
131
+ # If you pass this URL to rails' +image_tag+ helper, it will be converted to an
132
+ # absolute URL automatically.
133
+ # If there is currently no image uploaded, or there is a problem while loading
134
+ # the image this method will return +nil+.
135
+ def url_for_image_column(object, method, options=nil)
136
+ case object
137
+ when String, Symbol
138
+ object = instance_variable_get("@#{object.to_s}")
139
+ end
140
+ subdir = nil
141
+ if options
142
+ subdir = object.send("#{method}_state").create_magick_version_if_needed(options)
143
+ end
144
+ if subdir.nil?
145
+ nil
146
+ else
147
+ url_for_file_column(object, method, subdir)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,28 @@
1
+ module FileColumn
2
+
3
+ # This bit of code allows you to pass regular old files to
4
+ # file_column. file_column depends on a few extra methods that the
5
+ # CGI uploaded file class adds. We will add the equivalent methods
6
+ # to file objects if necessary by extending them with this module. This
7
+ # avoids opening up the standard File class which might result in
8
+ # naming conflicts.
9
+
10
+ module FileCompat # :nodoc:
11
+ def original_filename
12
+ File.basename(path)
13
+ end
14
+
15
+ def size
16
+ File.size(path)
17
+ end
18
+
19
+ def local_path
20
+ path
21
+ end
22
+
23
+ def content_type
24
+ nil
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,260 @@
1
+ module FileColumn # :nodoc:
2
+
3
+ class BaseUploadedFile # :nodoc:
4
+ def transform_with_magick
5
+ if needs_transform?
6
+ begin
7
+ img = ::Magick::Image::read(absolute_path).first
8
+ rescue ::Magick::ImageMagickError
9
+ if options[:magick][:image_required]
10
+ @magick_errors ||= []
11
+ @magick_errors << "invalid image"
12
+ end
13
+ return
14
+ end
15
+
16
+ if options[:magick][:versions]
17
+ options[:magick][:versions].each_pair do |version, version_options|
18
+ next if version_options[:lazy]
19
+ dirname = version_options[:name]
20
+ FileUtils.mkdir File.join(@dir, dirname)
21
+ transform_image(img, version_options, absolute_path(dirname))
22
+ end
23
+ end
24
+ if options[:magick][:size] or options[:magick][:crop] or options[:magick][:transformation] or options[:magick][:attributes]
25
+ transform_image(img, options[:magick], absolute_path)
26
+ end
27
+
28
+ GC.start
29
+ end
30
+ end
31
+
32
+ def create_magick_version_if_needed(version)
33
+ # RMagick might not have been loaded so far.
34
+ # We do not want to require it on every call of this method
35
+ # as this might be fairly expensive, so we just try if ::Magick
36
+ # exists and require it if not.
37
+ begin
38
+ ::Magick
39
+ rescue NameError
40
+ require 'RMagick'
41
+ end
42
+
43
+ if version.is_a?(Symbol)
44
+ version_options = options[:magick][:versions][version]
45
+ else
46
+ version_options = MagickExtension::process_options(version)
47
+ end
48
+
49
+ unless File.exists?(absolute_path(version_options[:name]))
50
+ begin
51
+ img = ::Magick::Image::read(absolute_path).first
52
+ rescue ::Magick::ImageMagickError
53
+ # we might be called directly from the view here
54
+ # so we just return nil if we cannot load the image
55
+ return nil
56
+ end
57
+ dirname = version_options[:name]
58
+ FileUtils.mkdir File.join(@dir, dirname)
59
+ transform_image(img, version_options, absolute_path(dirname))
60
+ end
61
+
62
+ version_options[:name]
63
+ end
64
+
65
+ attr_reader :magick_errors
66
+
67
+ def has_magick_errors?
68
+ @magick_errors and !@magick_errors.empty?
69
+ end
70
+
71
+ private
72
+
73
+ def needs_transform?
74
+ options[:magick] and just_uploaded? and
75
+ (options[:magick][:size] or options[:magick][:versions] or options[:magick][:transformation] or options[:magick][:attributes])
76
+ end
77
+
78
+ def transform_image(img, img_options, dest_path)
79
+ begin
80
+ if img_options[:transformation]
81
+ if img_options[:transformation].is_a?(Symbol)
82
+ img = @instance.send(img_options[:transformation], img)
83
+ else
84
+ img = img_options[:transformation].call(img)
85
+ end
86
+ end
87
+ if img_options[:crop]
88
+ dx, dy = img_options[:crop].split(':').map { |x| x.to_f }
89
+ w, h = (img.rows * dx / dy), (img.columns * dy / dx)
90
+ img = img.crop(::Magick::CenterGravity, [img.columns, w].min,
91
+ [img.rows, h].min, true)
92
+ end
93
+
94
+ if img_options[:size]
95
+ img = img.change_geometry(img_options[:size]) do |c, r, i|
96
+ i.resize(c, r)
97
+ end
98
+ end
99
+ ensure
100
+ img.write(dest_path) do
101
+ if img_options[:attributes]
102
+ img_options[:attributes].each_pair do |property, value|
103
+ self.send "#{property}=", value
104
+ end
105
+ end
106
+ end
107
+ File.chmod options[:permissions], dest_path
108
+ end
109
+ end
110
+ end
111
+
112
+ # If you are using file_column to upload images, you can
113
+ # directly process the images with RMagick,
114
+ # a ruby extension
115
+ # for accessing the popular imagemagick libraries. You can find
116
+ # more information about RMagick at http://rmagick.rubyforge.org.
117
+ #
118
+ # You can control what to do by adding a <tt>:magick</tt> option
119
+ # to your options hash. All operations are performed immediately
120
+ # after a new file is assigned to the file_column attribute (i.e.,
121
+ # when a new file has been uploaded).
122
+ #
123
+ # == Resizing images
124
+ #
125
+ # To resize the uploaded image according to an imagemagick geometry
126
+ # string, just use the <tt>:size</tt> option:
127
+ #
128
+ # file_column :image, :magick => {:size => "800x600>"}
129
+ #
130
+ # If the uploaded file cannot be loaded by RMagick, file_column will
131
+ # signal a validation error for the corresponding attribute. If you
132
+ # want to allow non-image files to be uploaded in a column that uses
133
+ # the <tt>:magick</tt> option, you can set the <tt>:image_required</tt>
134
+ # attribute to +false+:
135
+ #
136
+ # file_column :image, :magick => {:size => "800x600>",
137
+ # :image_required => false }
138
+ #
139
+ # == Multiple versions
140
+ #
141
+ # You can also create additional versions of your image, for example
142
+ # thumb-nails, like this:
143
+ # file_column :image, :magick => {:versions => {
144
+ # :thumb => {:size => "50x50"},
145
+ # :medium => {:size => "640x480>"}
146
+ # }
147
+ #
148
+ # These versions will be stored in separate sub-directories, named like the
149
+ # symbol you used to identify the version. So in the previous example, the
150
+ # image versions will be stored in "thumb", "screen" and "widescreen"
151
+ # directories, resp.
152
+ # A name different from the symbol can be set via the <tt>:name</tt> option.
153
+ #
154
+ # These versions can be accessed via FileColumnHelper's +url_for_image_column+
155
+ # method like this:
156
+ #
157
+ # <%= url_for_image_column "entry", "image", :thumb %>
158
+ #
159
+ # == Cropping images
160
+ #
161
+ # If you wish to crop your images with a size ratio before scaling
162
+ # them according to your version geometry, you can use the :crop directive.
163
+ # file_column :image, :magick => {:versions => {
164
+ # :square => {:crop => "1:1", :size => "50x50", :name => "thumb"},
165
+ # :screen => {:crop => "4:3", :size => "640x480>"},
166
+ # :widescreen => {:crop => "16:9", :size => "640x360!"},
167
+ # }
168
+ # }
169
+ #
170
+ # == Custom attributes
171
+ #
172
+ # To change some of the image properties like compression level before they
173
+ # are saved you can set the <tt>:attributes</tt> option.
174
+ # For a list of available attributes go to http://www.simplesystems.org/RMagick/doc/info.html
175
+ #
176
+ # file_column :image, :magick => { :attributes => { :quality => 30 } }
177
+ #
178
+ # == Custom transformations
179
+ #
180
+ # To perform custom transformations on uploaded images, you can pass a
181
+ # callback to file_column:
182
+ # file_column :image, :magick =>
183
+ # Proc.new { |image| image.quantize(256, Magick::GRAYColorspace) }
184
+ #
185
+ # The callback you give, receives one argument, which is an instance
186
+ # of Magick::Image, the RMagick image class. It should return a transformed
187
+ # image. Instead of passing a <tt>Proc</tt> object, you can also give a
188
+ # <tt>Symbol</tt>, the name of an instance method of your model.
189
+ #
190
+ # Custom transformations can be combined via the standard :size and :crop
191
+ # features, by using the :transformation option:
192
+ # file_column :image, :magick => {
193
+ # :transformation => Proc.new { |image| ... },
194
+ # :size => "640x480"
195
+ # }
196
+ #
197
+ # In this case, the standard resizing operations will be performed after the
198
+ # custom transformation.
199
+ #
200
+ # Of course, custom transformations can be used in versions, as well.
201
+ #
202
+ # <b>Note:</b> You'll need the
203
+ # RMagick extension being installed in order to use file_column's
204
+ # imagemagick integration.
205
+ module MagickExtension
206
+
207
+ def self.file_column(klass, attr, options) # :nodoc:
208
+ require 'RMagick'
209
+ options[:magick] = process_options(options[:magick],false) if options[:magick]
210
+ if options[:magick][:versions]
211
+ options[:magick][:versions].each_pair do |name, value|
212
+ options[:magick][:versions][name] = process_options(value, name.to_s)
213
+ end
214
+ end
215
+ state_method = "#{attr}_state".to_sym
216
+ after_assign_method = "#{attr}_magick_after_assign".to_sym
217
+
218
+ klass.send(:define_method, after_assign_method) do
219
+ self.send(state_method).transform_with_magick
220
+ end
221
+
222
+ options[:after_upload] ||= []
223
+ options[:after_upload] << after_assign_method
224
+
225
+ klass.validate do |record|
226
+ state = record.send(state_method)
227
+ if state.has_magick_errors?
228
+ state.magick_errors.each do |error|
229
+ record.errors.add attr, error
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+
236
+ def self.process_options(options,create_name=true)
237
+ case options
238
+ when String then options = {:size => options}
239
+ when Proc, Symbol then options = {:transformation => options }
240
+ end
241
+ if options[:geometry]
242
+ options[:size] = options.delete(:geometry)
243
+ end
244
+ options[:image_required] = true unless options.key?(:image_required)
245
+ if options[:name].nil? and create_name
246
+ if create_name == true
247
+ hash = 0
248
+ for key in [:size, :crop]
249
+ hash = hash ^ options[key].hash if options[key]
250
+ end
251
+ options[:name] = hash.abs.to_s(36)
252
+ else
253
+ options[:name] = create_name
254
+ end
255
+ end
256
+ options
257
+ end
258
+
259
+ end
260
+ end
@@ -0,0 +1,19 @@
1
+ # require this file from your "config/environment.rb" (after rails has been loaded)
2
+ # to integrate the file_column extension into rails.
3
+
4
+ require 'file_column'
5
+ require 'file_column_helper'
6
+
7
+
8
+ module ActiveRecord # :nodoc:
9
+ class Base # :nodoc:
10
+ # make file_column method available in all active record decendants
11
+ include FileColumn
12
+ end
13
+ end
14
+
15
+ module ActionView # :nodoc:
16
+ class Base # :nodoc:
17
+ include FileColumnHelper
18
+ end
19
+ end
@@ -0,0 +1,124 @@
1
+ require 'test/unit'
2
+
3
+ # Add the methods +upload+, the <tt>setup_file_fixtures</tt> and
4
+ # <tt>teardown_file_fixtures</tt> to the class Test::Unit::TestCase.
5
+ class Test::Unit::TestCase
6
+ # Returns a +Tempfile+ object as it would have been generated on file upload.
7
+ # Use this method to create the parameters when emulating form posts with
8
+ # file fields.
9
+ #
10
+ # === Example:
11
+ #
12
+ # def test_file_column_post
13
+ # entry = { :title => 'foo', :file => upload('/tmp/foo.txt')}
14
+ # post :upload, :entry => entry
15
+ #
16
+ # # ...
17
+ # end
18
+ #
19
+ # === Parameters
20
+ #
21
+ # * <tt>path</tt> The path to the file to upload.
22
+ # * <tt>content_type</tt> The MIME type of the file. If it is <tt>:guess</tt>,
23
+ # the method will try to guess it.
24
+ def upload(path, content_type=:guess, type=:tempfile)
25
+ if content_type == :guess
26
+ case path
27
+ when /\.jpg$/ then content_type = "image/jpeg"
28
+ when /\.png$/ then content_type = "image/png"
29
+ else content_type = nil
30
+ end
31
+ end
32
+ uploaded_file(path, content_type, File.basename(path), type)
33
+ end
34
+
35
+ # Copies the fixture files from "RAILS_ROOT/test/fixtures/file_column" into
36
+ # the temporary storage directory used for testing
37
+ # ("RAILS_ROOT/test/tmp/file_column"). Call this method in your
38
+ # <tt>setup</tt> methods to get the file fixtures (images, for example) into
39
+ # the directory used by file_column in testing.
40
+ #
41
+ # Note that the files and directories in the "fixtures/file_column" directory
42
+ # must have the same structure as you would expect in your "/public" directory
43
+ # after uploading with FileColumn.
44
+ #
45
+ # For example, the directory structure could look like this:
46
+ #
47
+ # test/fixtures/file_column/
48
+ # `-- container
49
+ # |-- first_image
50
+ # | |-- 1
51
+ # | | `-- image1.jpg
52
+ # | `-- tmp
53
+ # `-- second_image
54
+ # |-- 1
55
+ # | `-- image2.jpg
56
+ # `-- tmp
57
+ #
58
+ # Your fixture file for this one "container" class fixture could look like this:
59
+ #
60
+ # first:
61
+ # id: 1
62
+ # first_image: image1.jpg
63
+ # second_image: image1.jpg
64
+ #
65
+ # A usage example:
66
+ #
67
+ # def setup
68
+ # setup_fixture_files
69
+ #
70
+ # # ...
71
+ # end
72
+ def setup_fixture_files
73
+ tmp_path = File.join(RAILS_ROOT, "test", "tmp", "file_column")
74
+ file_fixtures = Dir.glob File.join(RAILS_ROOT, "test", "fixtures", "file_column", "*")
75
+
76
+ FileUtils.mkdir_p tmp_path unless File.exists?(tmp_path)
77
+ FileUtils.cp_r file_fixtures, tmp_path
78
+ end
79
+
80
+ # Removes the directory "RAILS_ROOT/test/tmp/file_column/" so the files
81
+ # copied on test startup are removed. Call this in your unit test's +teardown+
82
+ # method.
83
+ #
84
+ # A usage example:
85
+ #
86
+ # def teardown
87
+ # teardown_fixture_files
88
+ #
89
+ # # ...
90
+ # end
91
+ def teardown_fixture_files
92
+ FileUtils.rm_rf File.join(RAILS_ROOT, "test", "tmp", "file_column")
93
+ end
94
+
95
+ private
96
+
97
+ def uploaded_file(path, content_type, filename, type=:tempfile) # :nodoc:
98
+ if type == :tempfile
99
+ t = Tempfile.new(File.basename(filename))
100
+ FileUtils.copy_file(path, t.path)
101
+ else
102
+ if path
103
+ t = StringIO.new(IO.read(path))
104
+ else
105
+ t = StringIO.new
106
+ end
107
+ end
108
+ (class << t; self; end).class_eval do
109
+ alias local_path path if type == :tempfile
110
+ define_method(:local_path) { "" } if type == :stringio
111
+ define_method(:original_filename) {filename}
112
+ define_method(:content_type) {content_type}
113
+ end
114
+ return t
115
+ end
116
+ end
117
+
118
+ # If we are running in the "test" environment, we overwrite the default
119
+ # settings for FileColumn so that files are not uploaded into "/public/"
120
+ # in tests but rather into the directory "/test/tmp/file_column".
121
+ if RAILS_ENV == "test"
122
+ FileColumn::ClassMethods::DEFAULT_OPTIONS[:root_path] =
123
+ File.join(RAILS_ROOT, "test", "tmp", "file_column")
124
+ end
@@ -0,0 +1,112 @@
1
+ module FileColumn
2
+ module Validations #:nodoc:
3
+
4
+ def self.append_features(base)
5
+ super
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ # This module contains methods to create validations of uploaded files. All methods
10
+ # in this module will be included as class methods into <tt>ActiveRecord::Base</tt>
11
+ # so that you can use them in your models like this:
12
+ #
13
+ # class Entry < ActiveRecord::Base
14
+ # file_column :image
15
+ # validates_filesize_of :image, :in => 0..1.megabyte
16
+ # end
17
+ module ClassMethods
18
+ EXT_REGEXP = /\.([A-z0-9]+)$/
19
+
20
+ # This validates the file type of one or more file_columns. A list of file columns
21
+ # should be given followed by an options hash.
22
+ #
23
+ # Required options:
24
+ # * <tt>:in</tt> => list of extensions or mime types. If mime types are used they
25
+ # will be mapped into an extension via FileColumn::ClassMethods::MIME_EXTENSIONS.
26
+ #
27
+ # Examples:
28
+ # validates_file_format_of :field, :in => ["gif", "png", "jpg"]
29
+ # validates_file_format_of :field, :in => ["image/jpeg"]
30
+ def validates_file_format_of(*attrs)
31
+
32
+ options = attrs.pop if attrs.last.is_a?Hash
33
+ raise ArgumentError, "Please include the :in option." if !options || !options[:in]
34
+ options[:in] = [options[:in]] if options[:in].is_a?String
35
+ raise ArgumentError, "Invalid value for option :in" unless options[:in].is_a?Array
36
+
37
+ validates_each(attrs, options) do |record, attr, value|
38
+ unless value.blank?
39
+ mime_extensions = record.send("#{attr}_options")[:mime_extensions]
40
+ extensions = options[:in].map{|o| mime_extensions[o] || o }
41
+ record.errors.add attr, "is not a valid format." unless extensions.include?(value.scan(EXT_REGEXP).flatten.first)
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ # This validates the file size of one or more file_columns. A list of file columns
48
+ # should be given followed by an options hash.
49
+ #
50
+ # Required options:
51
+ # * <tt>:in</tt> => A size range. Note that you can use ActiveSupport's
52
+ # numeric extensions for kilobytes, etc.
53
+ #
54
+ # Examples:
55
+ # validates_filesize_of :field, :in => 0..100.megabytes
56
+ # validates_filesize_of :field, :in => 15.kilobytes..1.megabyte
57
+ def validates_filesize_of(*attrs)
58
+
59
+ options = attrs.pop if attrs.last.is_a?Hash
60
+ raise ArgumentError, "Please include the :in option." if !options || !options[:in]
61
+ raise ArgumentError, "Invalid value for option :in" unless options[:in].is_a?Range
62
+
63
+ validates_each(attrs, options) do |record, attr, value|
64
+ unless value.blank?
65
+ size = File.size(value)
66
+ record.errors.add attr, "is smaller than the allowed size range." if size < options[:in].first
67
+ record.errors.add attr, "is larger than the allowed size range." if size > options[:in].last
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ IMAGE_SIZE_REGEXP = /^(\d+)x(\d+)$/
74
+
75
+ # Validates the image size of one or more file_columns. A list of file columns
76
+ # should be given followed by an options hash. The validation will pass
77
+ # if both image dimensions (rows and columns) are at least as big as
78
+ # given in the <tt>:min</tt> option.
79
+ #
80
+ # Required options:
81
+ # * <tt>:min</tt> => minimum image dimension string, in the format NNxNN
82
+ # (columns x rows).
83
+ #
84
+ # Example:
85
+ # validates_image_size :field, :min => "1200x1800"
86
+ #
87
+ # This validation requires RMagick to be installed on your system
88
+ # to check the image's size.
89
+ def validates_image_size(*attrs)
90
+ options = attrs.pop if attrs.last.is_a?Hash
91
+ raise ArgumentError, "Please include a :min option." if !options || !options[:min]
92
+ minimums = options[:min].scan(IMAGE_SIZE_REGEXP).first.collect{|n| n.to_i} rescue []
93
+ raise ArgumentError, "Invalid value for option :min (should be 'XXxYY')" unless minimums.size == 2
94
+
95
+ require 'RMagick'
96
+
97
+ validates_each(attrs, options) do |record, attr, value|
98
+ unless value.blank?
99
+ begin
100
+ img = ::Magick::Image::read(value).first
101
+ record.errors.add('image', "is too small, must be at least #{minimums[0]}x#{minimums[1]}") if ( img.rows < minimums[1] || img.columns < minimums[0] )
102
+ rescue ::Magick::ImageMagickError
103
+ record.errors.add('image', "invalid image")
104
+ end
105
+ img = nil
106
+ GC.start
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end