simple_attachments 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (326) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +132 -0
  3. data/lib/simple_attachments.rb +15 -0
  4. data/lib/simple_attachments/attachment_model.rb +128 -0
  5. data/lib/simple_attachments/attachments_controller.rb +100 -0
  6. data/lib/simple_attachments/container_model.rb +73 -0
  7. data/lib/simple_attachments/migration_helpers.rb +14 -0
  8. data/lib/simple_attachments/view_helpers.rb +92 -0
  9. data/locales/en.yml +5 -0
  10. data/test/Rakefile +10 -0
  11. data/test/app/assets/javascripts/attachments.js +18 -0
  12. data/test/app/assets/stylesheets/attachments.css +17 -0
  13. data/test/app/controllers/application_controller.rb +3 -0
  14. data/test/app/controllers/avatars_controller.rb +3 -0
  15. data/test/app/controllers/documents_controller.rb +3 -0
  16. data/test/app/controllers/users_controller.rb +18 -0
  17. data/test/app/models/avatar.rb +5 -0
  18. data/test/app/models/document.rb +5 -0
  19. data/test/app/models/user.rb +4 -0
  20. data/test/app/views/layouts/application.html.erb +12 -0
  21. data/test/app/views/users/edit.html.erb +6 -0
  22. data/test/config.ru +4 -0
  23. data/test/config/application.rb +10 -0
  24. data/test/config/boot.rb +3 -0
  25. data/test/config/database.yml +5 -0
  26. data/test/config/environment.rb +5 -0
  27. data/test/config/environments/test.rb +12 -0
  28. data/test/config/initializers/secret_token.rb +7 -0
  29. data/test/config/initializers/session_store.rb +8 -0
  30. data/test/config/initializers/wrap_parameters.rb +14 -0
  31. data/test/config/routes.rb +5 -0
  32. data/test/db/migrate/1_create_users.rb +6 -0
  33. data/test/db/migrate/2_create_avatars.rb +8 -0
  34. data/test/db/migrate/3_create_documents.rb +8 -0
  35. data/test/db/schema.rb +34 -0
  36. data/test/db/test.sqlite3 +0 -0
  37. data/test/log/test.log +11774 -0
  38. data/test/script/rails +6 -0
  39. data/test/spec/multiple_spec.rb +36 -0
  40. data/test/spec/samples/sample.jpg +0 -0
  41. data/test/spec/samples/sample.pdf +0 -0
  42. data/test/spec/samples/sample.png +0 -0
  43. data/test/spec/singleton_spec.rb +54 -0
  44. data/test/spec/spec_helper.rb +22 -0
  45. data/test/tmp/cache/2CB/9B1/http%3A%2F%2Flocalhost%3A3000%2Fassets%2Fattachments.js%3F +0 -0
  46. data/test/tmp/cache/337/6A1/http%3A%2F%2Flocalhost%3A3000%2Fassets%2Fattachments.css%3F +0 -0
  47. data/test/tmp/cache/A03/C30/86cd82a38406e2cc75af040321554265d148882e +0 -0
  48. data/test/tmp/cache/BDE/BD0/7d763b3bac537e97ea5f3fb558c2bdbba05b72bc +0 -0
  49. data/test/tmp/cache/assets/C2E/6F0/sprockets%2F99a77a1d4d8767343010e1153d993839 +0 -0
  50. data/test/tmp/cache/assets/C5A/590/sprockets%2F2993f5a3d21b3e477143358534c68f55 +0 -0
  51. data/test/tmp/cache/assets/C5B/6F0/sprockets%2F19824e4169877bb010cd8163319f3f95 +0 -0
  52. data/test/tmp/cache/assets/CEB/450/sprockets%2Fada5663796684365b3e4ab36529bc86b +0 -0
  53. data/test/tmp/cache/assets/CF4/E60/sprockets%2F96b74d34978f2759ec2af602cd969d00 +0 -0
  54. data/test/tmp/cache/assets/D0B/600/sprockets%2F0b1b45e6991800f2911a6bcccf54a679 +0 -0
  55. data/test/tmp/cache/assets/D48/590/sprockets%2F522d019dab47a2617f2c2a99e98a99ed +0 -0
  56. data/test/tmp/cache/assets/D64/BF0/sprockets%2Fbd0d2396f3797000ffd901eba90b4d0e +0 -0
  57. data/test/tmp/cache/assets/D6B/150/sprockets%2F0b6cebd1717e9da4183329be9a2d77c0 +0 -0
  58. data/test/tmp/cache/assets/D70/120/sprockets%2F0f56b864e2eba6c4199d4171bdf391ae +0 -0
  59. data/test/tmp/cache/assets/D91/580/sprockets%2Fb5e4430a5a0af8eee00d262f82b565ed +0 -0
  60. data/test/tmp/cache/assets/D9A/760/sprockets%2F8df77fdd2c3c1f3d04f450c72a635be2 +0 -0
  61. data/test/tmp/cache/assets/DA1/380/sprockets%2F5e06b3974a8f9ca4452d4dfea337dba5 +0 -0
  62. data/test/tmp/cache/assets/DA9/EC0/sprockets%2F73f61f04eb2d87aced83787a0f14cf8e +0 -0
  63. data/test/uploads/1330732189.40513.sample.jpg +0 -0
  64. data/test/uploads/1330732621.7381.sample.jpg +0 -0
  65. data/test/uploads/1330732672.36763.sample.jpg +0 -0
  66. data/test/uploads/1330732847.98348.sample.jpg +0 -0
  67. data/test/uploads/1330732967.05269.sample.jpg +0 -0
  68. data/test/uploads/1330733025.52707.sample.jpg +0 -0
  69. data/test/uploads/1330733381.60733.sample.jpg +0 -0
  70. data/test/uploads/1330733822.51761.sample.jpg +0 -0
  71. data/test/uploads/1330733887.44114.sample.jpg +0 -0
  72. data/test/uploads/1330738615.68437.sample.jpg +0 -0
  73. data/test/uploads/1330738616.82401.sample.jpg +0 -0
  74. data/test/uploads/1330738618.00278.sample.jpg +0 -0
  75. data/test/uploads/1330738771.92631.sample.jpg +0 -0
  76. data/test/uploads/1330738772.94099.sample.jpg +0 -0
  77. data/test/uploads/1330738901.69933.sample.jpg +0 -0
  78. data/test/uploads/1330738904.3815.sample.jpg +0 -0
  79. data/test/uploads/1330739046.59901.sample.jpg +0 -0
  80. data/test/uploads/1330739125.79463.sample.jpg +0 -0
  81. data/test/uploads/1330739131.09163.sample.pdf +0 -0
  82. data/test/uploads/1330739735.52707.sample.jpg +0 -0
  83. data/test/uploads/1330739738.11937.sample.jpg +0 -0
  84. data/test/uploads/1330739742.76692.sample.jpg +0 -0
  85. data/test/uploads/1330739911.78046.sample.jpg +0 -0
  86. data/test/uploads/1330739914.46047.sample.jpg +0 -0
  87. data/test/uploads/1330739918.80359.sample.jpg +0 -0
  88. data/test/uploads/1330739921.39005.sample.jpg +0 -0
  89. data/test/uploads/1330739988.04537.sample.jpg +0 -0
  90. data/test/uploads/1330739990.65212.sample.jpg +0 -0
  91. data/test/uploads/1330739994.98225.sample.jpg +0 -0
  92. data/test/uploads/1330739997.45622.sample.jpg +0 -0
  93. data/test/uploads/1330740765.24516.sample.jpg +0 -0
  94. data/test/uploads/1330740767.71798.sample.jpg +0 -0
  95. data/test/uploads/1330740771.9889.sample.jpg +0 -0
  96. data/test/uploads/1330740774.56759.sample.jpg +0 -0
  97. data/test/uploads/1330741058.17571.sample.jpg +0 -0
  98. data/test/uploads/1330741060.65483.sample.jpg +0 -0
  99. data/test/uploads/1330741067.79574.sample.jpg +0 -0
  100. data/test/uploads/1330741154.42055.sample.jpg +0 -0
  101. data/test/uploads/1330741157.28718.sample.jpg +0 -0
  102. data/test/uploads/1330741164.64669.sample.jpg +0 -0
  103. data/test/uploads/1330741776.05725.sample.jpg +0 -0
  104. data/test/uploads/1330741778.80256.sample.jpg +0 -0
  105. data/test/uploads/1330741785.96345.sample.jpg +0 -0
  106. data/test/uploads/1330742286.07361.sample.jpg +0 -0
  107. data/test/uploads/1330742288.59918.sample.jpg +0 -0
  108. data/test/uploads/1330742295.83963.sample.jpg +0 -0
  109. data/test/uploads/1330742576.6398.sample.jpg +0 -0
  110. data/test/uploads/1330742579.54181.sample.jpg +0 -0
  111. data/test/uploads/1330742586.88996.sample.jpg +0 -0
  112. data/test/uploads/1330743983.91544.shen-logic-part1.pdf +0 -0
  113. data/test/uploads/1330744294.55912.sample.jpg +0 -0
  114. data/test/uploads/1330744296.94811.sample.jpg +0 -0
  115. data/test/uploads/1330744304.25529.sample.jpg +0 -0
  116. data/test/uploads/1330744307.08498.sample.pdf +0 -0
  117. data/test/uploads/1330744309.25872.sample.pdf +0 -0
  118. data/test/uploads/1330744443.49578.sample.jpg +0 -0
  119. data/test/uploads/1330744446.09032.sample.jpg +0 -0
  120. data/test/uploads/1330744453.55965.sample.jpg +0 -0
  121. data/test/uploads/1330744456.32318.sample.pdf +0 -0
  122. data/test/uploads/1330744458.42931.sample.pdf +0 -0
  123. data/test/uploads/1330744533.52631.sample.jpg +0 -0
  124. data/test/uploads/1330744536.13208.sample.jpg +0 -0
  125. data/test/uploads/1330744543.29535.sample.jpg +0 -0
  126. data/test/uploads/1330744546.16477.sample.pdf +0 -0
  127. data/test/uploads/1330744548.27125.sample.pdf +0 -0
  128. data/test/uploads/1330744696.43953.sample.jpg +0 -0
  129. data/test/uploads/1330744698.95043.sample.jpg +0 -0
  130. data/test/uploads/1330744706.28901.sample.jpg +0 -0
  131. data/test/uploads/1330744711.24284.sample.pdf +0 -0
  132. data/test/uploads/1330744713.6281.sample.pdf +0 -0
  133. data/test/uploads/1330744782.91673.sample.jpg +0 -0
  134. data/test/uploads/1330744785.53684.sample.jpg +0 -0
  135. data/test/uploads/1330744792.74599.sample.jpg +0 -0
  136. data/test/uploads/1330744797.90608.sample.pdf +0 -0
  137. data/test/uploads/1330744800.55736.sample.pdf +0 -0
  138. data/test/uploads/1330771358.91882.sample.jpg +0 -0
  139. data/test/uploads/1330771359.23929.sample.jpg +0 -0
  140. data/test/uploads/1330771359.70574.sample.jpg +0 -0
  141. data/test/uploads/1330771360.07645.sample.png +0 -0
  142. data/test/uploads/1330771364.83802.sample.pdf +0 -0
  143. data/test/uploads/1330771367.18498.sample.pdf +0 -0
  144. data/test/uploads/1330771514.28703.sample.jpg +0 -0
  145. data/test/uploads/1330771514.66497.sample.jpg +0 -0
  146. data/test/uploads/1330771515.12563.sample.jpg +0 -0
  147. data/test/uploads/1330771515.72515.sample.png +0 -0
  148. data/test/uploads/1330771519.30014.sample.pdf +0 -0
  149. data/test/uploads/1330771519.55784.sample.pdf +0 -0
  150. data/test/uploads/1330771519.89044.sample.pdf +0 -0
  151. data/test/uploads/1330771522.50763.sample.pdf +0 -0
  152. data/test/uploads/1330771522.75458.sample.pdf +0 -0
  153. data/test/uploads/1330775627.9105.sample.pdf +0 -0
  154. data/test/uploads/1330775628.40671.sample.pdf +0 -0
  155. data/test/uploads/1330775628.68645.sample.pdf +0 -0
  156. data/test/uploads/1330775631.48519.sample.pdf +0 -0
  157. data/test/uploads/1330775631.9586.sample.pdf +0 -0
  158. data/test/uploads/1330775676.5146.sample.pdf +0 -0
  159. data/test/uploads/1330775703.20143.sample.pdf +0 -0
  160. data/test/uploads/1330775704.36145.sample.pdf +0 -0
  161. data/test/uploads/1330775705.27831.sample.pdf +0 -0
  162. data/test/uploads/1330775706.66539.sample.pdf +0 -0
  163. data/test/uploads/1330776988.21579.sample.pdf +0 -0
  164. data/test/uploads/1330776988.69155.sample.pdf +0 -0
  165. data/test/uploads/1330776989.12114.sample.pdf +0 -0
  166. data/test/uploads/1330776992.1201.sample.pdf +0 -0
  167. data/test/uploads/1330776992.57634.sample.pdf +0 -0
  168. data/test/uploads/1330777152.6597.sample.jpg +0 -0
  169. data/test/uploads/1330777153.00459.sample.jpg +0 -0
  170. data/test/uploads/1330777153.45871.sample.jpg +0 -0
  171. data/test/uploads/1330777153.86376.sample.png +0 -0
  172. data/test/uploads/1330777157.91465.sample.pdf +0 -0
  173. data/test/uploads/1330777158.23816.sample.pdf +0 -0
  174. data/test/uploads/1330777158.74465.sample.pdf +0 -0
  175. data/test/uploads/1330777161.59586.sample.pdf +0 -0
  176. data/test/uploads/1330777161.93334.sample.pdf +0 -0
  177. data/test/uploads/1330777833.73591.sample.jpg +0 -0
  178. data/test/uploads/1330777834.05449.sample.jpg +0 -0
  179. data/test/uploads/1330777834.50661.sample.jpg +0 -0
  180. data/test/uploads/1330777834.87967.sample.jpg +0 -0
  181. data/test/uploads/1330777835.22949.sample.jpg +0 -0
  182. data/test/uploads/1330777835.55546.sample.png +0 -0
  183. data/test/uploads/1330777840.54959.sample.jpg +0 -0
  184. data/test/uploads/1330777844.18911.sample.pdf +0 -0
  185. data/test/uploads/1330777844.58364.sample.pdf +0 -0
  186. data/test/uploads/1330777844.96998.sample.pdf +0 -0
  187. data/test/uploads/1330777847.62838.sample.pdf +0 -0
  188. data/test/uploads/1330777848.0192.sample.pdf +0 -0
  189. data/test/uploads/1330778979.41703.sample.jpg +0 -0
  190. data/test/uploads/1330778979.74093.sample.jpg +0 -0
  191. data/test/uploads/1330778980.16769.sample.jpg +0 -0
  192. data/test/uploads/1330778980.54831.sample.jpg +0 -0
  193. data/test/uploads/1330778980.91033.sample.jpg +0 -0
  194. data/test/uploads/1330778981.23582.sample.png +0 -0
  195. data/test/uploads/1330778986.50795.sample.jpg +0 -0
  196. data/test/uploads/1330778989.07307.sample.pdf +0 -0
  197. data/test/uploads/1330778989.59241.sample.pdf +0 -0
  198. data/test/uploads/1330778990.06415.sample.pdf +0 -0
  199. data/test/uploads/1330778990.44233.sample.pdf +0 -0
  200. data/test/uploads/1330779134.25647.sample.jpg +0 -0
  201. data/test/uploads/1330779134.67957.sample.jpg +0 -0
  202. data/test/uploads/1330779135.15349.sample.jpg +0 -0
  203. data/test/uploads/1330779135.6793.sample.jpg +0 -0
  204. data/test/uploads/1330779136.14714.sample.jpg +0 -0
  205. data/test/uploads/1330779136.70598.sample.png +0 -0
  206. data/test/uploads/1330779141.75878.sample.jpg +0 -0
  207. data/test/uploads/1330779145.79811.sample.pdf +0 -0
  208. data/test/uploads/1330779146.40945.sample.pdf +0 -0
  209. data/test/uploads/1330779146.75038.sample.pdf +0 -0
  210. data/test/uploads/1330779149.67101.sample.pdf +0 -0
  211. data/test/uploads/1330779150.033.sample.pdf +0 -0
  212. data/test/uploads/1330779251.92468.sample.jpg +0 -0
  213. data/test/uploads/1330779252.33759.sample.jpg +0 -0
  214. data/test/uploads/1330779252.79211.sample.jpg +0 -0
  215. data/test/uploads/1330779253.16365.sample.jpg +0 -0
  216. data/test/uploads/1330779253.51459.sample.jpg +0 -0
  217. data/test/uploads/1330779253.82932.sample.png +0 -0
  218. data/test/uploads/1330779259.04186.sample.jpg +0 -0
  219. data/test/uploads/1330779262.79998.sample.pdf +0 -0
  220. data/test/uploads/1330779263.19534.sample.pdf +0 -0
  221. data/test/uploads/1330779263.51726.sample.pdf +0 -0
  222. data/test/uploads/1330779266.23965.sample.pdf +0 -0
  223. data/test/uploads/1330779266.65453.sample.pdf +0 -0
  224. data/test/uploads/1330780162.71983.1.gif +0 -0
  225. data/test/uploads/1330780370.60224.sample.jpg +0 -0
  226. data/test/uploads/1330780370.95202.sample.jpg +0 -0
  227. data/test/uploads/1330780371.44543.sample.jpg +0 -0
  228. data/test/uploads/1330780371.88658.sample.jpg +0 -0
  229. data/test/uploads/1330780372.30293.sample.jpg +0 -0
  230. data/test/uploads/1330780372.79723.sample.png +0 -0
  231. data/test/uploads/1330780378.19075.sample.jpg +0 -0
  232. data/test/uploads/1330780382.07736.sample.pdf +0 -0
  233. data/test/uploads/1330780382.61497.sample.pdf +0 -0
  234. data/test/uploads/1330780383.10458.sample.pdf +0 -0
  235. data/test/uploads/1330780385.85251.sample.pdf +0 -0
  236. data/test/uploads/1330780386.24973.sample.pdf +0 -0
  237. data/test/uploads/1330781258.12109.sample.pdf +0 -0
  238. data/test/uploads/1330781258.63862.sample.pdf +0 -0
  239. data/test/uploads/1330781259.10465.sample.pdf +0 -0
  240. data/test/uploads/1330781262.08459.sample.pdf +0 -0
  241. data/test/uploads/1330781262.52448.sample.pdf +0 -0
  242. data/test/uploads/1330781278.37307.sample.jpg +0 -0
  243. data/test/uploads/1330781278.7309.sample.jpg +0 -0
  244. data/test/uploads/1330781279.18693.sample.jpg +0 -0
  245. data/test/uploads/1330781279.55913.sample.jpg +0 -0
  246. data/test/uploads/1330781279.92436.sample.jpg +0 -0
  247. data/test/uploads/1330781280.27391.sample.png +0 -0
  248. data/test/uploads/1330886711.00348.sample.pdf +0 -0
  249. data/test/uploads/1330886711.78495.sample.pdf +0 -0
  250. data/test/uploads/1330886712.4033.sample.pdf +0 -0
  251. data/test/uploads/1330886716.09532.sample.pdf +0 -0
  252. data/test/uploads/1330886716.7663.sample.pdf +0 -0
  253. data/test/uploads/1330886735.38676.sample.jpg +0 -0
  254. data/test/uploads/1330886736.28739.sample.jpg +0 -0
  255. data/test/uploads/1330886736.84868.sample.jpg +0 -0
  256. data/test/uploads/1330886737.64167.sample.jpg +0 -0
  257. data/test/uploads/1330886738.33938.sample.jpg +0 -0
  258. data/test/uploads/1330886738.92271.sample.png +0 -0
  259. data/test/uploads/1330886985.6679.sample.pdf +0 -0
  260. data/test/uploads/1330886986.4568.sample.pdf +0 -0
  261. data/test/uploads/1330886987.00302.sample.pdf +0 -0
  262. data/test/uploads/1330886990.4604.sample.pdf +0 -0
  263. data/test/uploads/1330886991.04681.sample.pdf +0 -0
  264. data/test/uploads/1330887008.68477.sample.jpg +0 -0
  265. data/test/uploads/1330887009.23077.sample.jpg +0 -0
  266. data/test/uploads/1330887009.82498.sample.jpg +0 -0
  267. data/test/uploads/1330887010.48937.sample.jpg +0 -0
  268. data/test/uploads/1330887011.23496.sample.jpg +0 -0
  269. data/test/uploads/1330887011.92032.sample.png +0 -0
  270. data/test/uploads/1330887633.41769.sample.pdf +0 -0
  271. data/test/uploads/1330887633.81961.sample.pdf +0 -0
  272. data/test/uploads/1330887634.25582.sample.pdf +0 -0
  273. data/test/uploads/1330887637.47958.sample.pdf +0 -0
  274. data/test/uploads/1330887638.14348.sample.pdf +0 -0
  275. data/test/uploads/1330887655.10619.sample.jpg +0 -0
  276. data/test/uploads/1330887655.80139.sample.jpg +0 -0
  277. data/test/uploads/1330887656.35041.sample.jpg +0 -0
  278. data/test/uploads/1330887656.86876.sample.jpg +0 -0
  279. data/test/uploads/1330887657.60467.sample.jpg +0 -0
  280. data/test/uploads/1330887658.23424.sample.png +0 -0
  281. data/test/uploads/1330888133.62299.WIN.gif +0 -0
  282. data/test/uploads/1330888504.16714.1.gif +0 -0
  283. data/test/uploads/1330888586.99975.1.gif +0 -0
  284. data/test/uploads/1330888607.58249.shen-logic-part1.pdf +0 -0
  285. data/test/uploads/1330889585.30006.shen-logic-part2.pdf +0 -0
  286. data/test/uploads/1330890565.79547.shen-logic-part1.pdf +0 -0
  287. data/test/uploads/1330890992.45693.sample.jpg +0 -0
  288. data/test/uploads/1330890998.10996.sample.pdf +0 -0
  289. data/test/uploads/1330890998.76199.sample.pdf +0 -0
  290. data/test/uploads/1330890999.14516.sample.pdf +0 -0
  291. data/test/uploads/1330891002.0989.sample.pdf +0 -0
  292. data/test/uploads/1330891002.49258.sample.pdf +0 -0
  293. data/test/uploads/1330891004.89888.sample.jpg +0 -0
  294. data/test/uploads/1330891007.45147.sample.jpg +0 -0
  295. data/test/uploads/1330891052.00842.sample.jpg +0 -0
  296. data/test/uploads/1330891056.46428.sample.pdf +0 -0
  297. data/test/uploads/1330891056.83678.sample.pdf +0 -0
  298. data/test/uploads/1330891057.31732.sample.pdf +0 -0
  299. data/test/uploads/1330891057.86036.sample.pdf +0 -0
  300. data/test/uploads/1330891058.49616.sample.pdf +0 -0
  301. data/test/uploads/1330891058.91288.sample.pdf +0 -0
  302. data/test/uploads/1330891138.7408.sample.pdf +0 -0
  303. data/test/uploads/1330891139.14067.sample.pdf +0 -0
  304. data/test/uploads/1330891139.46755.sample.pdf +0 -0
  305. data/test/uploads/1330891142.26432.sample.pdf +0 -0
  306. data/test/uploads/1330891142.684.sample.pdf +0 -0
  307. data/test/uploads/1330891158.04426.sample.jpg +0 -0
  308. data/test/uploads/1330891158.44159.sample.jpg +0 -0
  309. data/test/uploads/1330891158.85135.sample.jpg +0 -0
  310. data/test/uploads/1330891159.3765.sample.jpg +0 -0
  311. data/test/uploads/1330891159.79503.sample.jpg +0 -0
  312. data/test/uploads/1330891160.15479.sample.png +0 -0
  313. data/test/uploads/1330900466.37214.sample.pdf +0 -0
  314. data/test/uploads/1330900466.77443.sample.pdf +0 -0
  315. data/test/uploads/1330900467.32831.sample.pdf +0 -0
  316. data/test/uploads/1330900470.07702.sample.pdf +0 -0
  317. data/test/uploads/1330900470.48767.sample.pdf +0 -0
  318. data/test/uploads/1330900486.92727.sample.jpg +0 -0
  319. data/test/uploads/1330900487.4311.sample.jpg +0 -0
  320. data/test/uploads/1330900488.03152.sample.jpg +0 -0
  321. data/test/uploads/1330900488.43945.sample.jpg +0 -0
  322. data/test/uploads/1330900489.01433.sample.jpg +0 -0
  323. data/test/uploads/1330900489.43854.sample.png +0 -0
  324. data/vendor/assets/javascripts/simple_attachments.js +138 -0
  325. data/vendor/assets/stylesheets/simple_attachments.css +23 -0
  326. metadata +729 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Tsokurov Alex <me@ximik.net>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,132 @@
1
+ = Simple Attachments
2
+
3
+ Simple Attachments is a plugin for Ruby on Rails 3 which implements complex solution for working with file attachments.
4
+
5
+ == Requirements
6
+
7
+ Plugin contains some CSS and JavaScript code, so Asset Pipeline should be switched on (by default).
8
+ Also you need {jQuery library}[http://jquery.com/] to make JavaScript work.
9
+
10
+ == Installation
11
+
12
+ Add this to your Gemfile and run the +bundle+ command.
13
+
14
+ gem 'simple_attachments'
15
+
16
+ == Getting Started
17
+
18
+ Let's say you have a +User+ which has one +Avatar+ and many +Document+.
19
+ The avatar can be change from user edit form. And the avatar data updates only after submiting the form.
20
+ The documents are shown on the same page. They can be managed separately with auto saving all changes in background.
21
+ You can find this app in +test+.
22
+
23
+ === Migrations
24
+
25
+ class CreateAvatars < ActiveRecord::Migration
26
+ def change
27
+ create_table :avatars do |t|
28
+ t.references :avatar, :null => true
29
+ t.attachment
30
+ end
31
+ end
32
+ end
33
+
34
+ class CreateDocuments < ActiveRecord::Migration
35
+ def change
36
+ create_table :documents do |t|
37
+ t.references :avatar, :null => true
38
+ t.attachment
39
+ end
40
+ end
41
+ end
42
+
43
+ *WARNING*: it's important to permit null value for container.
44
+
45
+ === Routes
46
+
47
+ resources :avatars, :only => [:create, :show, :destroy]
48
+ resources :documents, :only => [:create, :show, :destroy]
49
+
50
+ === Models
51
+
52
+ class User < ActiveRecord::Base
53
+ has_one_attachment :avatar, :dependent => :destroy
54
+ has_many_attachments :books, :dependent => :destroy
55
+ end
56
+
57
+ class Avatar < ActiveRecord::Base
58
+ attached_to :user
59
+ validates_mimetype %w(image/png image/gif image/jpeg)
60
+ validates_filesize :less_than_or_equal_to => 5e4
61
+ end
62
+
63
+ class Document < ActiveRecord::Base
64
+ attached_to :user
65
+ validates_mimetype %w(application/pdf)
66
+ validates_filesize :less_than_or_equal_to => 20e6
67
+ end
68
+
69
+ You can use a lot of options here. Just like with +has_one+, +has_many+ and +belongs_to+.
70
+
71
+ === Controllers
72
+
73
+ class AvatarsController < ApplicationController
74
+ attachment_controller
75
+ end
76
+
77
+ class DocumentsController < ApplicationController
78
+ attachment_controller
79
+ end
80
+
81
+ === View
82
+
83
+ <%= form_for @user do |f| %>
84
+ <%= f.file :avatar, :auto_associate => false %>
85
+ <% end %>
86
+
87
+ <%= files @user, :documents %>
88
+
89
+ *WARNING*: you also need +csrf_meta_tags+ in your layout to work with +protect_from_forgery+ filter.
90
+
91
+ === JavaScript
92
+
93
+ Plugin doesn't provide any implementation of the file appearance.
94
+ Instead it triggers events, which are easy to handle.
95
+
96
+ //= require_self
97
+ //= require simple_attachments
98
+
99
+ $(function() {
100
+ // Div is loaded and engine is ready.
101
+ $(".simple_attachments_div").bind("init", function() {
102
+ // You can add your own init features here.
103
+ });
104
+ // New field was created.
105
+ // Field is a div displaying attachment information.
106
+ $(".simple_attachments_div").bind("new_field", function(event, field) {
107
+ // You have to set field in the right place and add binds.
108
+ field.appendTo(this);
109
+ // Attachment was loaded
110
+ // data contains attachment properties and some little support variables
111
+ field.bind("loaded", function(event, data) {
112
+ // You have to create and/or set field content here
113
+ data.destroy_link.appendTo(this);
114
+ data.attachment_link.html(data.filename).appendTo(this);
115
+ });
116
+ // Attachment upload was failed
117
+ // errors is an array of strings
118
+ field.bind("failed", function(event, errors) {
119
+ // You can do something here before field would be deleted
120
+ });
121
+ });
122
+ });
123
+
124
+ *WARNING*: +simple_attachments.js+ should be required after binds.
125
+
126
+ === CSS
127
+
128
+ +simple_attachments.css+ contains some code to decorate default file input. So better require it, but it's not so necessary.
129
+
130
+ ---
131
+
132
+ (c) 2012 Tsokurov Alex <{me@ximik.net}[mailto:me@ximik.net]>, released under the MIT license
@@ -0,0 +1,15 @@
1
+ # :main: README.rdoc
2
+
3
+ module SimpleAttachments # :nodoc:
4
+ class Engine < ::Rails::Engine # :nodoc:
5
+ end
6
+ end
7
+
8
+ dir = File.expand_path(File.dirname(__FILE__))
9
+ I18n.load_path << File.join(dir, '..', 'locales', 'en.yml')
10
+
11
+ require File.join(dir, 'simple_attachments', 'attachment_model')
12
+ require File.join(dir, 'simple_attachments', 'container_model')
13
+ require File.join(dir, 'simple_attachments', 'attachments_controller')
14
+ require File.join(dir, 'simple_attachments', 'view_helpers')
15
+ require File.join(dir, 'simple_attachments', 'migration_helpers')
@@ -0,0 +1,128 @@
1
+ module SimpleAttachments::AttachmentModel
2
+
3
+ module Helpers
4
+
5
+ # Mark model as attachment and create association.
6
+ #
7
+ # Syntax is identical to +belongs_to+.
8
+ #
9
+ # attached_to :post
10
+ #
11
+ # Do not use more than one time in one model.
12
+ # However you can use polymorphic associations.
13
+ #
14
+ # attached_to :container, :polymorphic => true
15
+
16
+ def attached_to(name, options = {})
17
+ reflection = belongs_to name, options
18
+ self.class.send(:attr_accessor, :container_name)
19
+ self.container_name = reflection.name
20
+ before_save :save_file
21
+ after_destroy :destroy_file
22
+ send :extend, ClassMethods
23
+ send :include, InstanceMethods
24
+ end
25
+
26
+ end
27
+
28
+ module ClassMethods
29
+
30
+ # Validate mimetype of uploaded file.
31
+ #
32
+ # validates_mimetype %w(image/png image/gif image/jpeg), :message => 'should be an image'
33
+ #
34
+ # :message is optional.
35
+
36
+ def validates_mimetype(types, options = {})
37
+ options[:message] ||= I18n.t('simple_attachments.mimetype_isnt_allowed')
38
+ validates :mimetype, :inclusion => { :in => types, :message => options[:message] }
39
+ end
40
+
41
+ # Validate filesize. Syntax is identical to numericality validator. Filesize is given in bytes.
42
+ #
43
+ # validates_filesize :less_than_or_equal_to => 12e6, :message => 'file is too large'
44
+ #
45
+ # :message is optional.
46
+
47
+ def validates_filesize(options)
48
+ options[:message] ||= I18n.t('simple_attachments.file_is_too_large')
49
+ validates :filesize, :numericality => options
50
+ end
51
+
52
+ end
53
+
54
+ module InstanceMethods
55
+
56
+ # Set file for attachment.
57
+ # +file+ is +UploadedFile+ object
58
+
59
+ def file=(file)
60
+ if file.nil?
61
+ uploading_error
62
+ else
63
+ @file = file
64
+ self.mimetype = @file.content_type
65
+ self.filesize = @file.tempfile.size
66
+ self.filename = File.basename(@file.original_filename) # old browsers hack
67
+ self.filepath = file_path
68
+ end
69
+ end
70
+
71
+ # Generate path to file.
72
+ # Redefine this method if you want another naming logic.
73
+
74
+ def file_path
75
+ "#{Time.now.to_f}.#{filename}"
76
+ end
77
+
78
+ # Generate full path to file.
79
+ # Redefine this method if you have another place to hold files.
80
+
81
+ def full_file_path
82
+ Rails.root.join('uploads', filepath).to_s
83
+ end
84
+
85
+ # Save file in the filesystem.
86
+
87
+ def save_file
88
+ File.open(full_file_path, 'w') { |file| file.write @file.read } unless @file.nil?
89
+ rescue
90
+ uploading_error
91
+ end
92
+
93
+ # Delete file from the filesystem.
94
+
95
+ def destroy_file
96
+ File.delete full_file_path
97
+ rescue
98
+ end
99
+
100
+ def serializable_hash # :nodoc:
101
+ data = super
102
+ data['filepath'] = path # changing filepath to file url
103
+ data
104
+ end
105
+
106
+ # Test if attached to any container.
107
+
108
+ def attached?
109
+ not send(self.class.container_name).nil?
110
+ end
111
+
112
+ # Generate error connected to any server problems.
113
+
114
+ def uploading_error
115
+ errors[:base] << I18n.t('simple_attachments.uploading_error')
116
+ end
117
+
118
+ # Get url to the attachment.
119
+
120
+ def path
121
+ Rails.application.routes.url_helpers.send(self.class.to_s.underscore.concat('_path'), id)
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+
128
+ ActiveRecord::Base.extend SimpleAttachments::AttachmentModel::Helpers
@@ -0,0 +1,100 @@
1
+ module SimpleAttachments::AttachmentsController
2
+
3
+ module Helpers
4
+
5
+ # Mark controller as controller for attachment resource.
6
+ #
7
+ # Just put at any place of your controller.
8
+ #
9
+ # attachment_controller
10
+ #
11
+ # Sometimes you have to specify your resource manually.
12
+ #
13
+ # attachment_controller :resource => MyNamespace::Attachment
14
+
15
+ def attachment_controller(options = {})
16
+ before_filter :load_attachment, :except => :create
17
+ self.class.send(:attr_accessor, :attachment_model)
18
+ self.attachment_model = (options[:resource] or controller_path.classify.constantize)
19
+ send :include, InstanceMethods
20
+ end
21
+
22
+ end
23
+
24
+ module InstanceMethods
25
+
26
+ def create # :nodoc:
27
+ @attachment = self.class.attachment_model.new
28
+ @attachment.file = params[:file]
29
+ if @attachment.save and params[:container_id] != 'null'
30
+ begin
31
+ container = params[:container_model].classify.constantize.find params[:container_id]
32
+ associate(container, params[:method])
33
+ container.save
34
+ rescue
35
+ @attachment.uploading_error
36
+ end
37
+ end
38
+ if @attachment.errors.any?
39
+ succeed = false
40
+ data = @attachment.errors.messages.values.flatten
41
+ @attachment.destroy
42
+ else
43
+ succeed = true
44
+ data = @attachment.serializable_hash
45
+ end
46
+ render_answer(succeed, data)
47
+ end
48
+
49
+ def show # :nodoc:
50
+ send_file @attachment.full_file_path, :type => @attachment.mimetype, :filename => @attachment.filename
51
+ end
52
+
53
+ def destroy # :nodoc:
54
+ @attachment.destroy
55
+ render :nothing => true
56
+ end
57
+
58
+ private
59
+
60
+ # Before filter to load attachment resource.
61
+ #
62
+ # If you use another way to load it then just skip this filter.
63
+ #
64
+ # skip_before_filter :load_attachment
65
+
66
+ def load_attachment # :doc:
67
+ @attachment = self.class.attachment_model.find params[:id]
68
+ rescue
69
+ raise ActionController::RoutingError.new('Not Found')
70
+ end
71
+
72
+ # Associate attachment with container.
73
+ # Works only if you use +:auto_associate+ option (switched on by default).
74
+ #
75
+ # Redefine it if you want to have some extra control. E.g. CanCan authorization.
76
+ #
77
+ # def associate(container, method)
78
+ # authorize! :update, container
79
+ # super
80
+ # end
81
+
82
+ def associate(container, method) # :doc:
83
+ container.add_attachment method, @attachment
84
+ end
85
+
86
+ # Renders answer for javascript.
87
+
88
+ def render_answer(succeed, data) # :nodoc:
89
+ render :text => {'succeed' => succeed, 'data' => data}.to_json
90
+ end
91
+
92
+ def handle_unverified_request # :nodoc:
93
+ render :nothing => true
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+
100
+ ActionController::Base.extend SimpleAttachments::AttachmentsController::Helpers
@@ -0,0 +1,73 @@
1
+ module SimpleAttachments::ContainerModel
2
+
3
+ module Helpers
4
+
5
+ # Mark model as container and create association.
6
+ #
7
+ # Syntax is identical to +has_many+.
8
+ #
9
+ # has_many_attachments :attachments
10
+
11
+ def has_many_attachments(name, options = {})
12
+ reflection = has_many name, options
13
+ send(:define_method, reflection.plural_name + '_=') do |attachment_ids|
14
+ method, model = recover_vars(__method__)
15
+ old_attachment_ids = send method.singularize.concat('_ids')
16
+ attachment_ids = attachment_ids.map { |id| id.to_i }
17
+ model.destroy_all :id => (old_attachment_ids - attachment_ids)
18
+ (attachment_ids - old_attachment_ids).each do |attachment_id|
19
+ find_and_add_attachment(method, model, attachment_id)
20
+ end
21
+ end
22
+ send :include, InstanceMethods
23
+ end
24
+
25
+ # Mark model as container and create association.
26
+ #
27
+ # Syntax is identical to +has_one+.
28
+ #
29
+ # has_one_attachment :attachment
30
+
31
+ def has_one_attachment(name, options = {})
32
+ reflection = has_one name, options
33
+ send(:define_method, reflection.name.to_s + '_=') do |attachment_id|
34
+ method, model = recover_vars(__method__)
35
+ find_and_add_attachment(method, model, attachment_id)
36
+ end
37
+ send :include, InstanceMethods
38
+ end
39
+
40
+ end
41
+
42
+ module InstanceMethods
43
+
44
+ def add_attachment(method, attachment) # :nodoc:
45
+ if reflections[method.to_sym].instance_variable_get :@collection
46
+ send(method) << attachment
47
+ else
48
+ old_attachment = send(method)
49
+ old_attachment.destroy unless old_attachment.nil?
50
+ send (method + '='), attachment
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def recover_vars(method) # :nodoc:
57
+ method = method.to_s.chomp('_=')
58
+ model = reflections[method.to_sym].klass
59
+ [method, model]
60
+ end
61
+
62
+ def find_and_add_attachment(method, model, attachment_id) # :nodoc:
63
+ attachment = model.find_by_id attachment_id
64
+ return if attachment.nil?
65
+ return if attachment.attached?
66
+ add_attachment method, attachment
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ ActiveRecord::Base.extend SimpleAttachments::ContainerModel::Helpers