admin_assistant 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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