admin_assistant 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (377) hide show
  1. data/.gitignore +16 -0
  2. data/Rakefile +34 -6
  3. data/VERSION +1 -0
  4. data/admin_assistant.gemspec +440 -0
  5. data/doc/img/blog_posts-index.png +0 -0
  6. data/install.rb +25 -4
  7. data/lib/admin_assistant/active_record_column.rb +133 -45
  8. data/lib/admin_assistant/association_target.rb +16 -3
  9. data/lib/admin_assistant/belongs_to_column.rb +18 -10
  10. data/lib/admin_assistant/builder.rb +67 -30
  11. data/lib/admin_assistant/column.rb +153 -71
  12. data/lib/admin_assistant/date_time_range_end_point_selector.rb +340 -0
  13. data/lib/admin_assistant/default_search_column.rb +3 -7
  14. data/lib/admin_assistant/form_view.rb +114 -10
  15. data/lib/admin_assistant/has_many_column.rb +56 -0
  16. data/lib/admin_assistant/index.rb +220 -83
  17. data/lib/admin_assistant/polymorphic_belongs_to_column.rb +1 -1
  18. data/lib/admin_assistant/request/base.rb +196 -67
  19. data/lib/admin_assistant/request/create.rb +55 -7
  20. data/lib/admin_assistant/request/edit.rb +1 -2
  21. data/lib/admin_assistant/request/index.rb +16 -9
  22. data/lib/admin_assistant/request/new.rb +19 -7
  23. data/lib/admin_assistant/request/update.rb +28 -13
  24. data/lib/admin_assistant/search.rb +17 -2
  25. data/lib/admin_assistant/virtual_column.rb +15 -7
  26. data/lib/admin_assistant.rb +101 -81
  27. data/lib/javascripts/admin_assistant.js +1 -1
  28. data/lib/stylesheets/activescaffold.css +6 -1
  29. data/lib/stylesheets/default.css +17 -0
  30. data/lib/views/form.html.erb +7 -3
  31. data/lib/views/index.html.erb +13 -8
  32. data/lib/views/multi_form.html.erb +71 -0
  33. data/lib/views/show.html.erb +4 -4
  34. data/test_rails_app/README +256 -0
  35. data/test_rails_app/Rakefile +13 -0
  36. data/test_rails_app/app/controllers/admin/appointments2_controller.rb +15 -0
  37. data/test_rails_app/app/controllers/admin/appointments_controller.rb +11 -0
  38. data/test_rails_app/app/controllers/admin/blog_posts2_controller.rb +138 -0
  39. data/test_rails_app/app/controllers/admin/blog_posts3_controller.rb +76 -0
  40. data/test_rails_app/app/controllers/admin/blog_posts4_controller.rb +21 -0
  41. data/test_rails_app/app/controllers/admin/blog_posts5_controller.rb +27 -0
  42. data/test_rails_app/app/controllers/admin/blog_posts6_controller.rb +10 -0
  43. data/test_rails_app/app/controllers/admin/blog_posts_controller.rb +8 -0
  44. data/test_rails_app/app/controllers/admin/blog_posts_custom_new_and_edit_controller.rb +15 -0
  45. data/test_rails_app/app/controllers/admin/blog_posts_read_only_controller.rb +19 -0
  46. data/test_rails_app/app/controllers/admin/bookmarks_controller.rb +11 -0
  47. data/test_rails_app/app/controllers/admin/comments2_controller.rb +14 -0
  48. data/test_rails_app/app/controllers/admin/comments_controller.rb +12 -0
  49. data/test_rails_app/app/controllers/admin/file_column_images2_controller.rb +10 -0
  50. data/test_rails_app/app/controllers/admin/file_column_images_controller.rb +6 -0
  51. data/test_rails_app/app/controllers/admin/images2_controller.rb +11 -0
  52. data/test_rails_app/app/controllers/admin/images_controller.rb +6 -0
  53. data/test_rails_app/app/controllers/admin/misconfigured1_controller.rb +7 -0
  54. data/test_rails_app/app/controllers/admin/not_migrated_yets_controller.rb +9 -0
  55. data/test_rails_app/app/controllers/admin/product_categories2_controller.rb +7 -0
  56. data/test_rails_app/app/controllers/admin/product_categories_controller.rb +5 -0
  57. data/test_rails_app/app/controllers/admin/products2_controller.rb +15 -0
  58. data/test_rails_app/app/controllers/admin/products_controller.rb +31 -0
  59. data/test_rails_app/app/controllers/admin/television_airings_controller.rb +5 -0
  60. data/test_rails_app/app/controllers/admin/television_time_slots_controller.rb +5 -0
  61. data/test_rails_app/app/controllers/admin/users2_controller.rb +10 -0
  62. data/test_rails_app/app/controllers/admin/users_controller.rb +63 -0
  63. data/test_rails_app/app/controllers/application.rb +16 -0
  64. data/test_rails_app/app/controllers/application_controller.rb +16 -0
  65. data/test_rails_app/app/controllers/blog_posts_controller.rb +5 -0
  66. data/test_rails_app/app/helpers/admin/appointments2_helper.rb +2 -0
  67. data/test_rails_app/app/helpers/admin/appointments_helper.rb +2 -0
  68. data/test_rails_app/app/helpers/admin/blog_posts2_helper.rb +27 -0
  69. data/test_rails_app/app/helpers/admin/blog_posts3_helper.rb +2 -0
  70. data/test_rails_app/app/helpers/admin/blog_posts4_helper.rb +2 -0
  71. data/test_rails_app/app/helpers/admin/blog_posts6_helper.rb +16 -0
  72. data/test_rails_app/app/helpers/admin/blog_posts_custom_new_and_edit_helper.rb +29 -0
  73. data/test_rails_app/app/helpers/admin/blog_posts_helper.rb +2 -0
  74. data/test_rails_app/app/helpers/admin/blog_posts_read_only_helper.rb +2 -0
  75. data/test_rails_app/app/helpers/admin/bookmarks_helper.rb +2 -0
  76. data/test_rails_app/app/helpers/admin/comments2_helper.rb +2 -0
  77. data/test_rails_app/app/helpers/admin/comments_helper.rb +2 -0
  78. data/test_rails_app/app/helpers/admin/file_column_images2_helper.rb +2 -0
  79. data/test_rails_app/app/helpers/admin/file_column_images_helper.rb +2 -0
  80. data/test_rails_app/app/helpers/admin/images2_helper.rb +8 -0
  81. data/test_rails_app/app/helpers/admin/images_helper.rb +2 -0
  82. data/test_rails_app/app/helpers/admin/misconfigured1_helper.rb +2 -0
  83. data/test_rails_app/app/helpers/admin/not_migrated_yets_helper.rb +2 -0
  84. data/test_rails_app/app/helpers/admin/product_categories2_helper.rb +2 -0
  85. data/test_rails_app/app/helpers/admin/product_categories_helper.rb +2 -0
  86. data/test_rails_app/app/helpers/admin/products2_helper.rb +3 -0
  87. data/test_rails_app/app/helpers/admin/products_helper.rb +6 -0
  88. data/test_rails_app/app/helpers/admin/television_airings_helper.rb +2 -0
  89. data/test_rails_app/app/helpers/admin/television_time_slots_helper.rb +2 -0
  90. data/test_rails_app/app/helpers/admin/users2_helper.rb +2 -0
  91. data/test_rails_app/app/helpers/admin/users_helper.rb +25 -0
  92. data/test_rails_app/app/helpers/application_helper.rb +3 -0
  93. data/test_rails_app/app/helpers/blog_posts_helper.rb +2 -0
  94. data/test_rails_app/app/models/appointment.rb +5 -0
  95. data/test_rails_app/app/models/blog_post.rb +14 -0
  96. data/test_rails_app/app/models/blog_post_tag.rb +6 -0
  97. data/test_rails_app/app/models/bookmark.rb +6 -0
  98. data/test_rails_app/app/models/comment.rb +4 -0
  99. data/test_rails_app/app/models/file_column_image.rb +3 -0
  100. data/test_rails_app/app/models/image.rb +3 -0
  101. data/test_rails_app/app/models/not_migrated_yet.rb +2 -0
  102. data/test_rails_app/app/models/product.rb +7 -0
  103. data/test_rails_app/app/models/product_category.rb +9 -0
  104. data/test_rails_app/app/models/tag.rb +4 -0
  105. data/test_rails_app/app/models/television_airing.rb +3 -0
  106. data/test_rails_app/app/models/television_time_slot.rb +11 -0
  107. data/test_rails_app/app/models/user.rb +14 -0
  108. data/test_rails_app/app/views/admin/appointments/_subject_input.html.erb +2 -0
  109. data/test_rails_app/app/views/admin/appointments2/_time_input.html.erb +31 -0
  110. data/test_rails_app/app/views/admin/blog_posts2/_after_form.html.erb +5 -0
  111. data/test_rails_app/app/views/admin/blog_posts2/_after_index.html.erb +1 -0
  112. data/test_rails_app/app/views/admin/blog_posts2/_after_tags_input.html.erb +16 -0
  113. data/test_rails_app/app/views/admin/blog_posts2/_before_index.html.erb +2 -0
  114. data/test_rails_app/app/views/admin/blog_posts5/_after_index_header.html.erb +8 -0
  115. data/test_rails_app/app/views/admin/blog_posts_read_only/_body_for_show.html.erb +1 -0
  116. data/test_rails_app/app/views/admin/products/_name_input.html.erb +2 -0
  117. data/test_rails_app/app/views/admin/products/_percent_off_input.html.erb +2 -0
  118. data/test_rails_app/app/views/admin/products/_price_input.html.erb +10 -0
  119. data/test_rails_app/app/views/blog_posts/show.html.erb +13 -0
  120. data/test_rails_app/app/views/layouts/admin.html.erb +31 -0
  121. data/test_rails_app/config/boot.rb +109 -0
  122. data/test_rails_app/config/database.yml +28 -0
  123. data/test_rails_app/config/environment.rb +78 -0
  124. data/test_rails_app/config/environments/development.rb +17 -0
  125. data/test_rails_app/config/environments/production.rb +24 -0
  126. data/test_rails_app/config/environments/test.rb +24 -0
  127. data/test_rails_app/config/initializers/inflections.rb +10 -0
  128. data/test_rails_app/config/initializers/mime_types.rb +5 -0
  129. data/test_rails_app/config/initializers/new_rails_defaults.rb +17 -0
  130. data/test_rails_app/config/locales/en.yml +5 -0
  131. data/test_rails_app/config/routes.rb +43 -0
  132. data/test_rails_app/db/migrate/20090213215514_create_blog_posts.rb +12 -0
  133. data/test_rails_app/db/migrate/20090217225542_add_body_to_blog_posts.rb +9 -0
  134. data/test_rails_app/db/migrate/20090221220917_create_tags.rb +13 -0
  135. data/test_rails_app/db/migrate/20090221220947_create_blog_post_tags.rb +14 -0
  136. data/test_rails_app/db/migrate/20090222162204_add_textile_to_blog_posts.rb +9 -0
  137. data/test_rails_app/db/migrate/20090222163231_add_published_at_to_blog_posts.rb +9 -0
  138. data/test_rails_app/db/migrate/20090301191722_create_images.rb +16 -0
  139. data/test_rails_app/db/migrate/20090305165345_create_accounts.rb +14 -0
  140. data/test_rails_app/db/migrate/20090307225027_rename_accounts_to_users.rb +9 -0
  141. data/test_rails_app/db/migrate/20090307225750_add_user_id_to_blog_posts.rb +9 -0
  142. data/test_rails_app/db/migrate/20090309185114_change_blog_posts_textile.rb +9 -0
  143. data/test_rails_app/db/migrate/20090309193635_create_products.rb +14 -0
  144. data/test_rails_app/db/migrate/20090309203056_create_comments.rb +15 -0
  145. data/test_rails_app/db/migrate/20090323005947_create_file_column_images.rb +12 -0
  146. data/test_rails_app/db/migrate/20090326160049_add_birthday_to_users.rb +9 -0
  147. data/test_rails_app/db/migrate/20090326223606_add_state_to_users.rb +9 -0
  148. data/test_rails_app/db/migrate/20090503134004_add_file_column_image_to_products.rb +9 -0
  149. data/test_rails_app/db/migrate/20090617173651_create_bookmarks.rb +15 -0
  150. data/test_rails_app/db/migrate/20090624165355_add_tags_string_to_blog_post.rb +9 -0
  151. data/test_rails_app/db/migrate/20090625144313_add_avatar_fields_to_user.rb +11 -0
  152. data/test_rails_app/db/migrate/20090629202956_add_merged_into_to_blog_posts.rb +9 -0
  153. data/test_rails_app/db/migrate/20090701171857_add_force_textile_to_users.rb +9 -0
  154. data/test_rails_app/db/migrate/20090704163647_add_deleted_at_to_products.rb +9 -0
  155. data/test_rails_app/db/migrate/20090704173800_add_sale_fields_to_products.rb +13 -0
  156. data/test_rails_app/db/migrate/20090714024501_create_product_categories.rb +15 -0
  157. data/test_rails_app/db/migrate/20090819162835_add_admin_level_to_users.rb +9 -0
  158. data/test_rails_app/db/migrate/20091115134559_add_first_and_last_names_to_users.rb +11 -0
  159. data/test_rails_app/db/migrate/20091221011256_add_position_to_product_categories.rb +9 -0
  160. data/test_rails_app/db/migrate/20091222160814_create_appointments.rb +14 -0
  161. data/test_rails_app/db/migrate/20091227224547_add_user_id_to_appointments.rb +9 -0
  162. data/test_rails_app/db/migrate/20100214213359_create_television_time_slots.rb +13 -0
  163. data/test_rails_app/db/migrate/20100214213451_create_television_airings.rb +15 -0
  164. data/test_rails_app/doc/README_FOR_APP +5 -0
  165. data/test_rails_app/lib/tasks/rspec.rake +163 -0
  166. data/test_rails_app/public/404.html +30 -0
  167. data/test_rails_app/public/422.html +30 -0
  168. data/test_rails_app/public/500.html +33 -0
  169. data/test_rails_app/public/dispatch.cgi +10 -0
  170. data/test_rails_app/public/dispatch.fcgi +24 -0
  171. data/test_rails_app/public/dispatch.rb +10 -0
  172. data/test_rails_app/public/favicon.ico +0 -0
  173. data/test_rails_app/public/images/rails.png +0 -0
  174. data/test_rails_app/public/index.html +274 -0
  175. data/test_rails_app/public/javascripts/application.js +2 -0
  176. data/test_rails_app/public/javascripts/controls.js +963 -0
  177. data/test_rails_app/public/javascripts/dragdrop.js +973 -0
  178. data/test_rails_app/public/javascripts/effects.js +1128 -0
  179. data/test_rails_app/public/javascripts/prototype.js +4320 -0
  180. data/test_rails_app/public/robots.txt +5 -0
  181. data/test_rails_app/public/stylesheets/admin.css +3 -0
  182. data/test_rails_app/public/stylesheets/scaffold.css +54 -0
  183. data/test_rails_app/script/about +4 -0
  184. data/test_rails_app/script/autospec +5 -0
  185. data/test_rails_app/script/console +3 -0
  186. data/test_rails_app/script/dbconsole +3 -0
  187. data/test_rails_app/script/destroy +3 -0
  188. data/test_rails_app/script/generate +3 -0
  189. data/test_rails_app/script/performance/benchmarker +3 -0
  190. data/test_rails_app/script/performance/profiler +3 -0
  191. data/test_rails_app/script/performance/request +3 -0
  192. data/test_rails_app/script/plugin +3 -0
  193. data/test_rails_app/script/populate_tables.rb +49 -0
  194. data/test_rails_app/script/process/inspector +3 -0
  195. data/test_rails_app/script/process/reaper +3 -0
  196. data/test_rails_app/script/process/spawner +3 -0
  197. data/test_rails_app/script/runner +3 -0
  198. data/test_rails_app/script/server +3 -0
  199. data/test_rails_app/script/spec +5 -0
  200. data/test_rails_app/script/spec_server +125 -0
  201. data/test_rails_app/spec/controllers/admin/appointments2_controller_spec.rb +88 -0
  202. data/test_rails_app/spec/controllers/admin/appointments_controller_spec.rb +419 -0
  203. data/test_rails_app/spec/controllers/admin/blog_posts2_controller_spec.rb +1021 -0
  204. data/test_rails_app/spec/controllers/admin/blog_posts3_controller_spec.rb +532 -0
  205. data/test_rails_app/spec/controllers/admin/blog_posts4_controller_spec.rb +231 -0
  206. data/test_rails_app/spec/controllers/admin/blog_posts5_controller_spec.rb +77 -0
  207. data/test_rails_app/spec/controllers/admin/blog_posts6_controller_spec.rb +49 -0
  208. data/test_rails_app/spec/controllers/admin/blog_posts_controller_spec.rb +987 -0
  209. data/test_rails_app/spec/controllers/admin/blog_posts_custom_new_and_edit_controller_spec.rb +99 -0
  210. data/test_rails_app/spec/controllers/admin/blog_posts_read_only_controller_spec.rb +94 -0
  211. data/test_rails_app/spec/controllers/admin/bookmarks_controller_spec.rb +505 -0
  212. data/test_rails_app/spec/controllers/admin/comments2_controller_spec.rb +70 -0
  213. data/test_rails_app/spec/controllers/admin/comments_controller_spec.rb +82 -0
  214. data/test_rails_app/spec/controllers/admin/file_column_images2_controller_spec.rb +25 -0
  215. data/test_rails_app/spec/controllers/admin/file_column_images_controller_spec.rb +82 -0
  216. data/test_rails_app/spec/controllers/admin/images2_controller_spec.rb +44 -0
  217. data/test_rails_app/spec/controllers/admin/images_controller_spec.rb +97 -0
  218. data/test_rails_app/spec/controllers/admin/misconfigured1_controller_spec.rb +21 -0
  219. data/test_rails_app/spec/controllers/admin/not_migrated_yets_controller_spec.rb +10 -0
  220. data/test_rails_app/spec/controllers/admin/product_categories2_controller_spec.rb +215 -0
  221. data/test_rails_app/spec/controllers/admin/product_categories_controller_spec.rb +19 -0
  222. data/test_rails_app/spec/controllers/admin/products2_controller_spec.rb +203 -0
  223. data/test_rails_app/spec/controllers/admin/products_controller_spec.rb +255 -0
  224. data/test_rails_app/spec/controllers/admin/television_airings_controller_spec.rb +32 -0
  225. data/test_rails_app/spec/controllers/admin/television_time_slots_controller_spec.rb +10 -0
  226. data/test_rails_app/spec/controllers/admin/users2_controller_spec.rb +65 -0
  227. data/test_rails_app/spec/controllers/admin/users_controller_spec.rb +344 -0
  228. data/test_rails_app/spec/controllers/blog_posts_controller_spec.rb +13 -0
  229. data/test_rails_app/spec/data/ruby_throated.jpg +0 -0
  230. data/test_rails_app/spec/data/tweenbot.jpg +0 -0
  231. data/test_rails_app/spec/fixtures/appointments.yml +9 -0
  232. data/test_rails_app/spec/fixtures/blog_post_tags.yml +9 -0
  233. data/test_rails_app/spec/fixtures/blog_posts.yml +7 -0
  234. data/test_rails_app/spec/fixtures/bookmarks.yml +11 -0
  235. data/test_rails_app/spec/fixtures/comments.yml +11 -0
  236. data/test_rails_app/spec/fixtures/file_column_images.yml +7 -0
  237. data/test_rails_app/spec/fixtures/images.yml +7 -0
  238. data/test_rails_app/spec/fixtures/not_migrated_yets.yml +7 -0
  239. data/test_rails_app/spec/fixtures/product_categories.yml +7 -0
  240. data/test_rails_app/spec/fixtures/products.yml +9 -0
  241. data/test_rails_app/spec/fixtures/tags.yml +7 -0
  242. data/test_rails_app/spec/fixtures/television_airings.yml +11 -0
  243. data/test_rails_app/spec/fixtures/television_time_slots.yml +7 -0
  244. data/test_rails_app/spec/fixtures/users.yml +9 -0
  245. data/test_rails_app/spec/helpers/admin/appointments2_helper_spec.rb +11 -0
  246. data/test_rails_app/spec/helpers/admin/appointments_helper_spec.rb +11 -0
  247. data/test_rails_app/spec/helpers/admin/blog_posts2_helper_spec.rb +11 -0
  248. data/test_rails_app/spec/helpers/admin/blog_posts3_helper_spec.rb +11 -0
  249. data/test_rails_app/spec/helpers/admin/blog_posts4_helper_spec.rb +11 -0
  250. data/test_rails_app/spec/helpers/admin/blog_posts_custom_new_and_edit_helper_spec.rb +11 -0
  251. data/test_rails_app/spec/helpers/admin/blog_posts_helper_spec.rb +11 -0
  252. data/test_rails_app/spec/helpers/admin/blog_posts_read_only_helper_spec.rb +11 -0
  253. data/test_rails_app/spec/helpers/admin/bookmarks_helper_spec.rb +11 -0
  254. data/test_rails_app/spec/helpers/admin/comments2_helper_spec.rb +11 -0
  255. data/test_rails_app/spec/helpers/admin/comments_helper_spec.rb +11 -0
  256. data/test_rails_app/spec/helpers/admin/file_column_images2_helper_spec.rb +11 -0
  257. data/test_rails_app/spec/helpers/admin/file_column_images_helper_spec.rb +11 -0
  258. data/test_rails_app/spec/helpers/admin/images2_helper_spec.rb +11 -0
  259. data/test_rails_app/spec/helpers/admin/images_helper_spec.rb +11 -0
  260. data/test_rails_app/spec/helpers/admin/misconfigured1_helper_spec.rb +11 -0
  261. data/test_rails_app/spec/helpers/admin/not_migrated_yets_helper_spec.rb +11 -0
  262. data/test_rails_app/spec/helpers/admin/product_categories2_helper_spec.rb +11 -0
  263. data/test_rails_app/spec/helpers/admin/product_categories_helper_spec.rb +11 -0
  264. data/test_rails_app/spec/helpers/admin/products2_helper_spec.rb +11 -0
  265. data/test_rails_app/spec/helpers/admin/products_helper_spec.rb +11 -0
  266. data/test_rails_app/spec/helpers/admin/television_airings_helper_spec.rb +11 -0
  267. data/test_rails_app/spec/helpers/admin/television_time_slots_helper_spec.rb +11 -0
  268. data/test_rails_app/spec/helpers/admin/users2_helper_spec.rb +11 -0
  269. data/test_rails_app/spec/helpers/admin/users_helper_spec.rb +11 -0
  270. data/test_rails_app/spec/helpers/blog_posts_helper_spec.rb +11 -0
  271. data/test_rails_app/spec/models/appointment_spec.rb +16 -0
  272. data/test_rails_app/spec/models/blog_post_spec.rb +13 -0
  273. data/test_rails_app/spec/models/blog_post_tag_spec.rb +14 -0
  274. data/test_rails_app/spec/models/bookmark_spec.rb +15 -0
  275. data/test_rails_app/spec/models/comment_spec.rb +15 -0
  276. data/test_rails_app/spec/models/file_column_image_spec.rb +12 -0
  277. data/test_rails_app/spec/models/image_spec.rb +12 -0
  278. data/test_rails_app/spec/models/not_migrated_yet_spec.rb +15 -0
  279. data/test_rails_app/spec/models/product_category_spec.rb +15 -0
  280. data/test_rails_app/spec/models/product_spec.rb +14 -0
  281. data/test_rails_app/spec/models/tag_spec.rb +13 -0
  282. data/test_rails_app/spec/models/television_airing_spec.rb +15 -0
  283. data/test_rails_app/spec/models/television_time_slot_spec.rb +13 -0
  284. data/test_rails_app/spec/models/user_spec.rb +14 -0
  285. data/test_rails_app/spec/rcov.opts +2 -0
  286. data/test_rails_app/spec/spec.opts +4 -0
  287. data/test_rails_app/spec/spec_helper.rb +88 -0
  288. data/test_rails_app/spec/spec_or_test_helper.rb +49 -0
  289. data/test_rails_app/test/fixtures/file_column_images.yml +7 -0
  290. data/test_rails_app/test/integration/admin_blog_posts2_integration_test.rb +16 -0
  291. data/test_rails_app/test/integration/admin_blog_posts5_integration_test.rb +19 -0
  292. data/test_rails_app/test/integration/admin_blog_posts_integration_test.rb +25 -0
  293. data/test_rails_app/test/test_helper.rb +28 -0
  294. data/test_rails_app/vendor/plugins/file_column/CHANGELOG +69 -0
  295. data/test_rails_app/vendor/plugins/file_column/README +54 -0
  296. data/test_rails_app/vendor/plugins/file_column/Rakefile +36 -0
  297. data/test_rails_app/vendor/plugins/file_column/TODO +6 -0
  298. data/test_rails_app/vendor/plugins/file_column/init.rb +13 -0
  299. data/test_rails_app/vendor/plugins/file_column/lib/file_column.rb +723 -0
  300. data/test_rails_app/vendor/plugins/file_column/lib/file_column_helper.rb +150 -0
  301. data/test_rails_app/vendor/plugins/file_column/lib/file_compat.rb +28 -0
  302. data/test_rails_app/vendor/plugins/file_column/lib/magick_file_column.rb +260 -0
  303. data/test_rails_app/vendor/plugins/file_column/lib/rails_file_column.rb +19 -0
  304. data/test_rails_app/vendor/plugins/file_column/lib/test_case.rb +124 -0
  305. data/test_rails_app/vendor/plugins/file_column/lib/validations.rb +112 -0
  306. data/test_rails_app/vendor/plugins/file_column/test/abstract_unit.rb +63 -0
  307. data/test_rails_app/vendor/plugins/file_column/test/connection.rb +17 -0
  308. data/test_rails_app/vendor/plugins/file_column/test/file_column_helper_test.rb +97 -0
  309. data/test_rails_app/vendor/plugins/file_column/test/file_column_test.rb +650 -0
  310. data/test_rails_app/vendor/plugins/file_column/test/fixtures/entry.rb +32 -0
  311. data/test_rails_app/vendor/plugins/file_column/test/fixtures/invalid-image.jpg +1 -0
  312. data/test_rails_app/vendor/plugins/file_column/test/fixtures/kerb.jpg +0 -0
  313. data/test_rails_app/vendor/plugins/file_column/test/fixtures/mysql.sql +25 -0
  314. data/test_rails_app/vendor/plugins/file_column/test/fixtures/schema.rb +10 -0
  315. data/test_rails_app/vendor/plugins/file_column/test/fixtures/skanthak.png +0 -0
  316. data/test_rails_app/vendor/plugins/file_column/test/magick_test.rb +380 -0
  317. data/test_rails_app/vendor/plugins/file_column/test/magick_view_only_test.rb +21 -0
  318. data/vendor/ar_query/ar_query.gemspec +16 -0
  319. data/website/_layouts/api.html +39 -0
  320. data/website/_layouts/default.html +34 -0
  321. data/website/api/core.markdown +106 -0
  322. data/website/api/destroy.markdown +25 -0
  323. data/website/api/form.markdown +291 -0
  324. data/website/api/idx.markdown +286 -0
  325. data/website/api/index.markdown +147 -0
  326. data/website/api/search.markdown +108 -0
  327. data/website/api/show.markdown +22 -0
  328. data/website/community.markdown +27 -0
  329. data/website/css/lightbox.css +29 -0
  330. data/website/css/main.css +70 -0
  331. data/website/design_principles.markdown +50 -0
  332. data/website/getting_started.markdown +10 -0
  333. data/website/img/blog_posts-index.png +0 -0
  334. data/website/img/blog_posts-search.png +0 -0
  335. data/website/img/lightbox/bullet.gif +0 -0
  336. data/website/img/lightbox/close.gif +0 -0
  337. data/website/img/lightbox/closelabel.gif +0 -0
  338. data/website/img/lightbox/donate-button.gif +0 -0
  339. data/website/img/lightbox/download-icon.gif +0 -0
  340. data/website/img/lightbox/image-1.jpg +0 -0
  341. data/website/img/lightbox/loading.gif +0 -0
  342. data/website/img/lightbox/nextlabel.gif +0 -0
  343. data/website/img/lightbox/prevlabel.gif +0 -0
  344. data/website/img/lightbox/thumb-1.jpg +0 -0
  345. data/website/img/screen1-thumb.png +0 -0
  346. data/website/img/screen1.png +0 -0
  347. data/website/img/screen10-thumb.png +0 -0
  348. data/website/img/screen10.png +0 -0
  349. data/website/img/screen11-thumb.png +0 -0
  350. data/website/img/screen11.png +0 -0
  351. data/website/img/screen2-thumb.png +0 -0
  352. data/website/img/screen2.png +0 -0
  353. data/website/img/screen3-thumb.png +0 -0
  354. data/website/img/screen3.png +0 -0
  355. data/website/img/screen4-thumb.png +0 -0
  356. data/website/img/screen4.png +0 -0
  357. data/website/img/screen5-thumb.png +0 -0
  358. data/website/img/screen5.png +0 -0
  359. data/website/img/screen6-thumb.png +0 -0
  360. data/website/img/screen6.png +0 -0
  361. data/website/img/screen7-thumb.png +0 -0
  362. data/website/img/screen7.png +0 -0
  363. data/website/img/screen8-thumb.png +0 -0
  364. data/website/img/screen8.png +0 -0
  365. data/website/img/screen9-thumb.png +0 -0
  366. data/website/img/screen9.png +0 -0
  367. data/website/img/user-form.png +0 -0
  368. data/website/index.markdown +35 -0
  369. data/website/js/builder.js +136 -0
  370. data/website/js/effects.js +1122 -0
  371. data/website/js/lightbox.js +497 -0
  372. data/website/js/prototype.js +4221 -0
  373. data/website/js/scriptaculous.js +58 -0
  374. data/website/quick_start.markdown +44 -0
  375. data/website/screenshots.markdown +27 -0
  376. data/website/tutorial.markdown +56 -0
  377. metadata +391 -23
@@ -0,0 +1,203 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe Admin::Products2Controller do
4
+ integrate_views
5
+
6
+ describe '#new' do
7
+ before :all do
8
+ ProductCategory.destroy_all
9
+ @shiny = ProductCategory.create!(
10
+ :category_name => 'shiny', :position => 1
11
+ )
12
+ @fuzzy = ProductCategory.create!(
13
+ :category_name => 'fuzzy', :position => 2
14
+ )
15
+ end
16
+
17
+ before :each do
18
+ get :new
19
+ end
20
+
21
+ it 'should be successful' do
22
+ response.should be_success
23
+ end
24
+
25
+ it 'should show a product category selector with category name strings' do
26
+ response.should have_tag(
27
+ "select[name=?]", "product[product_category_id]"
28
+ ) do
29
+ with_tag "option[value=#{@fuzzy.id}]", :text => "fuzzy"
30
+ with_tag "option[value=#{@shiny.id}]", :text => "shiny"
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '#index' do
36
+ before :all do
37
+ if Product.count == 0
38
+ Product.create! :name => random_word
39
+ end
40
+ end
41
+
42
+ before :each do
43
+ get :index
44
+ end
45
+
46
+ it 'should show a search range widget' do
47
+ response.should have_tag('form#search_form') do
48
+ with_tag 'input[name=?]', 'search[price][gt]'
49
+ with_tag 'input[name=?]', 'search[price][lt]'
50
+ without_tag 'input[type=checkbox]'
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#index when searching for a product greater than a specific price' do
56
+ before :all do
57
+ @five_dollars = Product.find_by_price 500
58
+ @five_dollars ||= Product.create!(:name => random_word, :price => 500)
59
+ @fifty_dollars = Product.find_by_price 5000
60
+ @fifty_dollars ||= Product.create!(:name => random_word, :price => 5000)
61
+ @five_hundred_dollars = Product.find_by_price 50000
62
+ @five_hundred_dollars ||= Product.create!(
63
+ :name => random_word, :price => 50000
64
+ )
65
+ end
66
+
67
+ before :each do
68
+ get :index, :search => {:price => {:gt => "5000", :lt => ""}}
69
+ end
70
+
71
+ it 'should prefill the search form fields' do
72
+ response.should have_tag('form#search_form') do
73
+ with_tag 'input[name=?][value=?]', 'search[price][gt]', 5000
74
+ with_tag 'input:not([value])[name=?]', 'search[price][lt]'
75
+ without_tag 'input[type=checkbox]'
76
+ end
77
+ end
78
+
79
+ it 'should not show a product lower than that price' do
80
+ response.should_not have_tag('td', :text => @five_dollars.name)
81
+ end
82
+
83
+ it 'should not show a product at exactly that price' do
84
+ response.should_not have_tag('td', :text => @fifty_dollars.name)
85
+ end
86
+
87
+ it 'should show a product greater than that price' do
88
+ response.should have_tag('td', :text => @five_hundred_dollars.name)
89
+ end
90
+ end
91
+
92
+ describe '#index when searching for a product lower than a specific price' do
93
+ before :all do
94
+ @five_dollars = Product.find_by_price 500
95
+ @five_dollars ||= Product.create!(:name => random_word, :price => 500)
96
+ @fifty_dollars = Product.find_by_price 5000
97
+ @fifty_dollars ||= Product.create!(:name => random_word, :price => 5000)
98
+ @five_hundred_dollars = Product.find_by_price 50000
99
+ @five_hundred_dollars ||= Product.create!(
100
+ :name => random_word, :price => 50000
101
+ )
102
+ end
103
+
104
+ before :each do
105
+ get :index, :search => {:price => {:gt => "", :lt => "5000"}}
106
+ end
107
+
108
+ it 'should prefill the search form fields' do
109
+ response.should have_tag('form#search_form') do
110
+ with_tag 'input:not([value])[name=?]', 'search[price][gt]'
111
+ with_tag 'input[name=?][value=?]', 'search[price][lt]', 5000
112
+ without_tag 'input[type=checkbox]'
113
+ end
114
+ end
115
+
116
+ it 'should show a product lower than that price' do
117
+ response.should have_tag('td', :text => @five_dollars.name)
118
+ end
119
+
120
+ it 'should not show a product at exactly that price' do
121
+ response.should_not have_tag('td', :text => @fifty_dollars.name)
122
+ end
123
+
124
+ it 'should not show a product greater than that price' do
125
+ response.should_not have_tag('td', :text => @five_hundred_dollars.name)
126
+ end
127
+ end
128
+
129
+ describe '#index when searching for a product within a price range' do
130
+ before :all do
131
+ @five_dollars = Product.find_by_price 500
132
+ @five_dollars ||= Product.create!(:name => random_word, :price => 500)
133
+ @fifty_dollars = Product.find_by_price 5000
134
+ @fifty_dollars ||= Product.create!(:name => random_word, :price => 5000)
135
+ @five_hundred_dollars = Product.find_by_price 50000
136
+ @five_hundred_dollars ||= Product.create!(
137
+ :name => random_word, :price => 50000
138
+ )
139
+ end
140
+
141
+ before :each do
142
+ get :index, :search => {:price => {:gt => "1000", :lt => "10000"}}
143
+ end
144
+
145
+ it 'should prefill the search form fields' do
146
+ response.should have_tag('form#search_form') do
147
+ with_tag 'input[name=?][value=?]', 'search[price][gt]', 1000
148
+ with_tag 'input[name=?][value=?]', 'search[price][lt]', 10000
149
+ without_tag 'input[type=checkbox]'
150
+ end
151
+ end
152
+
153
+ it 'should not show a product lower than that range' do
154
+ response.should_not have_tag('td', :text => @five_dollars.name)
155
+ end
156
+
157
+ it 'should show a product in that range' do
158
+ response.should have_tag('td', :text => @fifty_dollars.name)
159
+ end
160
+
161
+ it 'should not show a product higher than that range' do
162
+ response.should_not have_tag('td', :text => @five_hundred_dollars.name)
163
+ end
164
+ end
165
+
166
+ describe '#index sort by product category' do
167
+ before :all do
168
+ ProductCategory.destroy_all
169
+ Product.destroy_all
170
+ diamond_cat = ProductCategory.create!(
171
+ :category_name => 'diamond', :position => 1
172
+ )
173
+ @diamond = Product.create!(
174
+ :name => 'Diamond', :price => 200_000, :product_category => diamond_cat
175
+ )
176
+ choc_cat = ProductCategory.create!(
177
+ :category_name => 'chocolate', :position => 2
178
+ )
179
+ @chocolate = Product.create!(
180
+ :name => 'Chocolate bar', :price => 200, :product_category => choc_cat
181
+ )
182
+ diamond_cat.id.should be < choc_cat.id
183
+ end
184
+
185
+ before :each do
186
+ get :index, :sort_order => "asc", :sort => "product_category"
187
+ end
188
+
189
+ it 'should be a success' do
190
+ response.should be_success
191
+ end
192
+
193
+ it 'should order chocolate before diamonds' do
194
+ response.body.should match(
195
+ %r|product_#{@chocolate.id}.*product_#{@diamond.id}|m
196
+ )
197
+ end
198
+
199
+ it "should show ProductCategory#category_name because it's defined a #name_for_admin_assistant method" do
200
+ response.should have_tag('td', :text => 'chocolate')
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,255 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe Admin::ProductsController do
4
+ integrate_views
5
+
6
+ describe '#destroy' do
7
+ before :all do
8
+ @product = Product.find_or_create_by_name 'Chocolate bar'
9
+ end
10
+
11
+ before :each do
12
+ post :destroy, :id => @product.id
13
+ end
14
+
15
+ it 'should call the custom destroy block' do
16
+ @product.reload
17
+ @product.deleted_at.should_not be_nil
18
+ end
19
+ end
20
+
21
+ describe '#index with at least one Product' do
22
+ before :all do
23
+ @product = (
24
+ Product.find(:first) || Product.create!(:name => 'product name')
25
+ )
26
+ end
27
+
28
+ before :each do
29
+ get :index
30
+ end
31
+
32
+ it 'should have a search form that allows you to specify equals or other options' do
33
+ response.should have_tag('form[id=search_form][method=get]') do
34
+ with_tag("select[name=?]", "search[price(comparator)]") do
35
+ with_tag("option[value='>']", :text => 'greater than')
36
+ with_tag("option[value='>=']", :text => 'greater than or equal to')
37
+ with_tag("option[value='='][selected=selected]", :text => 'equal to')
38
+ with_tag("option[value='<=']", :text => 'less than or equal to')
39
+ with_tag("option[value='<']", :text => 'less than')
40
+ end
41
+ with_tag('input[name=?]', 'search[price]')
42
+ end
43
+ end
44
+
45
+ it 'should not have a comparator for the name search field' do
46
+ response.should have_tag('form[id=search_form][method=get]') do
47
+ without_tag("select[name=?]", "search[name(comparator)]")
48
+ end
49
+ end
50
+
51
+ it 'should not have a Show link' do
52
+ response.should_not have_tag(
53
+ "a[href=/admin/products/show/#{@product.id}]", 'Show'
54
+ )
55
+ end
56
+ end
57
+
58
+ describe '#index search by price' do
59
+ before :all do
60
+ Product.destroy_all
61
+ Product.create!(:name => 'Chocolate bar', :price => 200)
62
+ Product.create!(:name => 'Diamond ring', :price => 200_000)
63
+ end
64
+
65
+ before :each do
66
+ get :index, :search => {"price(comparator)" => '>', :price => 1000}
67
+ end
68
+
69
+ it 'should only show products more expensive than $10' do
70
+ response.should_not have_tag('td', :text => 'Chocolate bar')
71
+ response.should have_tag('td', :text => 'Diamond ring')
72
+ end
73
+
74
+ it 'should show the price comparison in the search form' do
75
+ response.should have_tag('form[id=search_form][method=get]') do
76
+ with_tag("select[name=?]", "search[price(comparator)]") do
77
+ with_tag(
78
+ "option[value='>'][selected=selected]", :text => 'greater than'
79
+ )
80
+ with_tag("option[value='>=']", :text => 'greater than or equal to')
81
+ with_tag("option[value='=']", :text => 'equal to')
82
+ with_tag("option[value='<=']", :text => 'less than or equal to')
83
+ with_tag("option[value='<']", :text => 'less than')
84
+ end
85
+ with_tag('input[name=?]', 'search[price]')
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#index sort by product category' do
91
+ before :all do
92
+ ProductCategory.destroy_all
93
+ Product.destroy_all
94
+ diamond_cat = ProductCategory.create!(
95
+ :category_name => 'diamond', :position => 1
96
+ )
97
+ @diamond = Product.create!(
98
+ :name => 'Diamond', :price => 200_000, :product_category => diamond_cat
99
+ )
100
+ choc_cat = ProductCategory.create!(
101
+ :category_name => 'chocolate', :position => 2
102
+ )
103
+ @chocolate = Product.create!(
104
+ :name => 'Chocolate bar', :price => 200, :product_category => choc_cat
105
+ )
106
+ diamond_cat.id.should be < choc_cat.id
107
+ end
108
+
109
+ before :each do
110
+ get :index, :sort_order => "asc", :sort => "product_category"
111
+ end
112
+
113
+ it 'should be a success' do
114
+ response.should be_success
115
+ end
116
+
117
+ it 'should order by product_category_id' do
118
+ response.body.should match(
119
+ %r|product_#{@diamond.id}.*product_#{@chocolate.id}|m
120
+ )
121
+ end
122
+ end
123
+
124
+ describe '#new' do
125
+ before :each do
126
+ get :new
127
+ response.should be_success
128
+ end
129
+
130
+ it 'should not render the default price input' do
131
+ response.should_not have_tag("input[name=?]", 'product[price]')
132
+ end
133
+
134
+ it 'should render the custom price input from _price_input.html.erb' do
135
+ response.should have_tag("input[name=?]", 'product[price][dollars]')
136
+ end
137
+
138
+ it 'should show clear links for sale_starts_at and sale_ends_at' do
139
+ response.body.should have_tag('a', :text => "Not on sale")
140
+ response.body.should have_tag('a', :text => "Sale doesn't end")
141
+ end
142
+ end
143
+
144
+ describe '#edit' do
145
+ before :all do
146
+ @product = Product.find_or_create_by_name 'a bird'
147
+ @product.update_attributes(
148
+ :name => 'a bird', :price => 100_00,
149
+ :file_column_image => File.open("./spec/data/ruby_throated.jpg"),
150
+ :percent_off => 25
151
+ )
152
+ end
153
+
154
+ before :each do
155
+ get :edit, :id => @product.id
156
+ response.should be_success
157
+ end
158
+
159
+ it "should have a multipart form" do
160
+ response.should have_tag('form[enctype=multipart/form-data]')
161
+ end
162
+
163
+ it 'should have a file input for image' do
164
+ response.should have_tag(
165
+ 'input[name=?][type=file]', 'product[file_column_image]'
166
+ )
167
+ end
168
+
169
+ it 'should show the current image' do
170
+ response.should have_tag(
171
+ "img[src^=?][height=100][width=100]",
172
+ "/product/file_column_image/#{@product.id}/ruby_throated.jpg"
173
+ )
174
+ end
175
+
176
+ it 'should have a remove-image option' do
177
+ response.should have_tag(
178
+ "input[type=checkbox][name=?]", 'product[file_column_image(destroy)]'
179
+ )
180
+ end
181
+
182
+ it 'should the percent_off value pre-filled' do
183
+ response.should have_tag(
184
+ 'input[name=?][value=25]', 'product[percent_off]'
185
+ )
186
+ end
187
+ end
188
+
189
+ describe '#update' do
190
+ before :all do
191
+ @product = Product.find_or_create_by_name 'a bird'
192
+ @product.update_attributes(
193
+ :name => 'a bird', :price => 100_00,
194
+ :file_column_image => File.open("./spec/data/ruby_throated.jpg")
195
+ )
196
+ end
197
+
198
+ describe 'while updating a current image' do
199
+ before :each do
200
+ file = File.new './spec/data/tweenbot.jpg'
201
+ post(
202
+ :update, :id => @product.id, :product => {:file_column_image => file}
203
+ )
204
+ end
205
+
206
+ it 'should update the image' do
207
+ product_prime = Product.find_by_id @product.id
208
+ product_prime.file_column_image.should match(/tweenbot/)
209
+ end
210
+
211
+ it 'should save the image locally' do
212
+ assert(
213
+ File.exist?(
214
+ "./public/product/file_column_image/#{@product.id}/tweenbot.jpg"
215
+ )
216
+ )
217
+ end
218
+ end
219
+
220
+ describe 'while removing the current image' do
221
+ before :each do
222
+ post(
223
+ :update,
224
+ :id => @product.id,
225
+ :product => {
226
+ 'file_column_image(destroy)' => '1', :file_column_image => ''
227
+ }
228
+ )
229
+ end
230
+
231
+ it 'should remove the existing image' do
232
+ product_prime = Product.find_by_id @product.id
233
+ product_prime.file_column_image.should be_nil
234
+ end
235
+ end
236
+
237
+ describe 'while trying to update and remove at the same time' do
238
+ before :each do
239
+ file = File.new './spec/data/tweenbot.jpg'
240
+ post(
241
+ :update,
242
+ :id => @product.id,
243
+ :product => {
244
+ :file_column_image => file, 'file_column_image(destroy)' => '1'
245
+ }
246
+ )
247
+ end
248
+
249
+ it 'should assume you meant to update' do
250
+ product_prime = Product.find_by_id @product.id
251
+ product_prime.file_column_image.should match(/tweenbot/)
252
+ end
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Admin::TelevisionAiringsController do
4
+ integrate_views
5
+
6
+ describe '#new' do
7
+ before :all do
8
+ TelevisionTimeSlot.destroy_all
9
+ @tv_time_slot1 = TelevisionTimeSlot.create!(
10
+ :time => Time.utc(2010, 2, 14, 9)
11
+ )
12
+ @tv_time_slot2 = TelevisionTimeSlot.create!(
13
+ :time => Time.utc(2010, 2, 14, 14)
14
+ )
15
+ end
16
+
17
+ before :each do
18
+ get :new
19
+ response.should be_success
20
+ end
21
+
22
+ it 'should sort television time slots by time, not by the time string' do
23
+ response.should have_tag(
24
+ 'select[name=?]', 'television_airing[television_time_slot_id]'
25
+ ) do
26
+ with_tag 'option:first-child[value=""]'
27
+ with_tag 'option:nth-child(2)[value=?]', @tv_time_slot1.id
28
+ with_tag 'option:nth-child(3)[value=?]', @tv_time_slot2.id
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Admin::TelevisionTimeSlotsController do
4
+
5
+ #Delete this example and add some real ones
6
+ it "should use Admin::TelevisionTimeSlotsController" do
7
+ controller.should be_an_instance_of(Admin::TelevisionTimeSlotsController)
8
+ end
9
+
10
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Admin::Users2Controller do
4
+ integrate_views
5
+
6
+ describe '#index' do
7
+ before :all do
8
+ User.create!(:username => random_word) if User.count == 0
9
+ end
10
+
11
+ before :each do
12
+ get :index
13
+ end
14
+
15
+ it 'should show the empty search form' do
16
+ response.should have_tag('form#search_form') do
17
+ with_tag('input[name=?]', 'search[blog_posts]')
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '#index when searching by blog post' do
23
+ before :all do
24
+ User.destroy_all
25
+ @soren = User.create! :username => 'soren'
26
+ @jean_paul = User.create! :username => 'jean_paul'
27
+ BlogPost.create!(
28
+ :user => @jean_paul, :title => 'No Foobar',
29
+ :body => 'Hell is other foobars'
30
+ )
31
+ @friedrich = User.create! :username => 'friedrich'
32
+ BlogPost.create!(
33
+ :user => @friedrich, :title => 'Thus Spake Zarafoobar',
34
+ :body => 'Man is something that shall be overfoobared.'
35
+ )
36
+ BlogPost.create!(
37
+ :user => @friedrich, :title => 'Beyond Good and Foobar',
38
+ :body =>
39
+ 'And when you gaze long into a foobar the foobar also gazes into you.'
40
+ )
41
+ end
42
+
43
+ before :each do
44
+ get :index, :search => {:blog_posts => 'foobar'}
45
+ end
46
+
47
+ it 'should prefill the search form fields' do
48
+ response.should have_tag('form#search_form') do
49
+ with_tag('input[name=?][value=?]', 'search[blog_posts]', 'foobar')
50
+ end
51
+ end
52
+
53
+ it 'should not match a user without any matching blog posts' do
54
+ response.should_not have_tag('td', :text => @soren.username)
55
+ end
56
+
57
+ it 'should match a user with one matching blog post' do
58
+ response.should have_tag('td', :text => @jean_paul.username)
59
+ end
60
+
61
+ it 'should match a user with two matching blog posts, only presenting that user once' do
62
+ response.should have_tag('td', :text => @friedrich.username, :count => 1)
63
+ end
64
+ end
65
+ end