simple_attachments 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +132 -0
- data/lib/simple_attachments.rb +15 -0
- data/lib/simple_attachments/attachment_model.rb +128 -0
- data/lib/simple_attachments/attachments_controller.rb +100 -0
- data/lib/simple_attachments/container_model.rb +73 -0
- data/lib/simple_attachments/migration_helpers.rb +14 -0
- data/lib/simple_attachments/view_helpers.rb +92 -0
- data/locales/en.yml +5 -0
- data/test/Rakefile +10 -0
- data/test/app/assets/javascripts/attachments.js +18 -0
- data/test/app/assets/stylesheets/attachments.css +17 -0
- data/test/app/controllers/application_controller.rb +3 -0
- data/test/app/controllers/avatars_controller.rb +3 -0
- data/test/app/controllers/documents_controller.rb +3 -0
- data/test/app/controllers/users_controller.rb +18 -0
- data/test/app/models/avatar.rb +5 -0
- data/test/app/models/document.rb +5 -0
- data/test/app/models/user.rb +4 -0
- data/test/app/views/layouts/application.html.erb +12 -0
- data/test/app/views/users/edit.html.erb +6 -0
- data/test/config.ru +4 -0
- data/test/config/application.rb +10 -0
- data/test/config/boot.rb +3 -0
- data/test/config/database.yml +5 -0
- data/test/config/environment.rb +5 -0
- data/test/config/environments/test.rb +12 -0
- data/test/config/initializers/secret_token.rb +7 -0
- data/test/config/initializers/session_store.rb +8 -0
- data/test/config/initializers/wrap_parameters.rb +14 -0
- data/test/config/routes.rb +5 -0
- data/test/db/migrate/1_create_users.rb +6 -0
- data/test/db/migrate/2_create_avatars.rb +8 -0
- data/test/db/migrate/3_create_documents.rb +8 -0
- data/test/db/schema.rb +34 -0
- data/test/db/test.sqlite3 +0 -0
- data/test/log/test.log +11774 -0
- data/test/script/rails +6 -0
- data/test/spec/multiple_spec.rb +36 -0
- data/test/spec/samples/sample.jpg +0 -0
- data/test/spec/samples/sample.pdf +0 -0
- data/test/spec/samples/sample.png +0 -0
- data/test/spec/singleton_spec.rb +54 -0
- data/test/spec/spec_helper.rb +22 -0
- data/test/tmp/cache/2CB/9B1/http%3A%2F%2Flocalhost%3A3000%2Fassets%2Fattachments.js%3F +0 -0
- data/test/tmp/cache/337/6A1/http%3A%2F%2Flocalhost%3A3000%2Fassets%2Fattachments.css%3F +0 -0
- data/test/tmp/cache/A03/C30/86cd82a38406e2cc75af040321554265d148882e +0 -0
- data/test/tmp/cache/BDE/BD0/7d763b3bac537e97ea5f3fb558c2bdbba05b72bc +0 -0
- data/test/tmp/cache/assets/C2E/6F0/sprockets%2F99a77a1d4d8767343010e1153d993839 +0 -0
- data/test/tmp/cache/assets/C5A/590/sprockets%2F2993f5a3d21b3e477143358534c68f55 +0 -0
- data/test/tmp/cache/assets/C5B/6F0/sprockets%2F19824e4169877bb010cd8163319f3f95 +0 -0
- data/test/tmp/cache/assets/CEB/450/sprockets%2Fada5663796684365b3e4ab36529bc86b +0 -0
- data/test/tmp/cache/assets/CF4/E60/sprockets%2F96b74d34978f2759ec2af602cd969d00 +0 -0
- data/test/tmp/cache/assets/D0B/600/sprockets%2F0b1b45e6991800f2911a6bcccf54a679 +0 -0
- data/test/tmp/cache/assets/D48/590/sprockets%2F522d019dab47a2617f2c2a99e98a99ed +0 -0
- data/test/tmp/cache/assets/D64/BF0/sprockets%2Fbd0d2396f3797000ffd901eba90b4d0e +0 -0
- data/test/tmp/cache/assets/D6B/150/sprockets%2F0b6cebd1717e9da4183329be9a2d77c0 +0 -0
- data/test/tmp/cache/assets/D70/120/sprockets%2F0f56b864e2eba6c4199d4171bdf391ae +0 -0
- data/test/tmp/cache/assets/D91/580/sprockets%2Fb5e4430a5a0af8eee00d262f82b565ed +0 -0
- data/test/tmp/cache/assets/D9A/760/sprockets%2F8df77fdd2c3c1f3d04f450c72a635be2 +0 -0
- data/test/tmp/cache/assets/DA1/380/sprockets%2F5e06b3974a8f9ca4452d4dfea337dba5 +0 -0
- data/test/tmp/cache/assets/DA9/EC0/sprockets%2F73f61f04eb2d87aced83787a0f14cf8e +0 -0
- data/test/uploads/1330732189.40513.sample.jpg +0 -0
- data/test/uploads/1330732621.7381.sample.jpg +0 -0
- data/test/uploads/1330732672.36763.sample.jpg +0 -0
- data/test/uploads/1330732847.98348.sample.jpg +0 -0
- data/test/uploads/1330732967.05269.sample.jpg +0 -0
- data/test/uploads/1330733025.52707.sample.jpg +0 -0
- data/test/uploads/1330733381.60733.sample.jpg +0 -0
- data/test/uploads/1330733822.51761.sample.jpg +0 -0
- data/test/uploads/1330733887.44114.sample.jpg +0 -0
- data/test/uploads/1330738615.68437.sample.jpg +0 -0
- data/test/uploads/1330738616.82401.sample.jpg +0 -0
- data/test/uploads/1330738618.00278.sample.jpg +0 -0
- data/test/uploads/1330738771.92631.sample.jpg +0 -0
- data/test/uploads/1330738772.94099.sample.jpg +0 -0
- data/test/uploads/1330738901.69933.sample.jpg +0 -0
- data/test/uploads/1330738904.3815.sample.jpg +0 -0
- data/test/uploads/1330739046.59901.sample.jpg +0 -0
- data/test/uploads/1330739125.79463.sample.jpg +0 -0
- data/test/uploads/1330739131.09163.sample.pdf +0 -0
- data/test/uploads/1330739735.52707.sample.jpg +0 -0
- data/test/uploads/1330739738.11937.sample.jpg +0 -0
- data/test/uploads/1330739742.76692.sample.jpg +0 -0
- data/test/uploads/1330739911.78046.sample.jpg +0 -0
- data/test/uploads/1330739914.46047.sample.jpg +0 -0
- data/test/uploads/1330739918.80359.sample.jpg +0 -0
- data/test/uploads/1330739921.39005.sample.jpg +0 -0
- data/test/uploads/1330739988.04537.sample.jpg +0 -0
- data/test/uploads/1330739990.65212.sample.jpg +0 -0
- data/test/uploads/1330739994.98225.sample.jpg +0 -0
- data/test/uploads/1330739997.45622.sample.jpg +0 -0
- data/test/uploads/1330740765.24516.sample.jpg +0 -0
- data/test/uploads/1330740767.71798.sample.jpg +0 -0
- data/test/uploads/1330740771.9889.sample.jpg +0 -0
- data/test/uploads/1330740774.56759.sample.jpg +0 -0
- data/test/uploads/1330741058.17571.sample.jpg +0 -0
- data/test/uploads/1330741060.65483.sample.jpg +0 -0
- data/test/uploads/1330741067.79574.sample.jpg +0 -0
- data/test/uploads/1330741154.42055.sample.jpg +0 -0
- data/test/uploads/1330741157.28718.sample.jpg +0 -0
- data/test/uploads/1330741164.64669.sample.jpg +0 -0
- data/test/uploads/1330741776.05725.sample.jpg +0 -0
- data/test/uploads/1330741778.80256.sample.jpg +0 -0
- data/test/uploads/1330741785.96345.sample.jpg +0 -0
- data/test/uploads/1330742286.07361.sample.jpg +0 -0
- data/test/uploads/1330742288.59918.sample.jpg +0 -0
- data/test/uploads/1330742295.83963.sample.jpg +0 -0
- data/test/uploads/1330742576.6398.sample.jpg +0 -0
- data/test/uploads/1330742579.54181.sample.jpg +0 -0
- data/test/uploads/1330742586.88996.sample.jpg +0 -0
- data/test/uploads/1330743983.91544.shen-logic-part1.pdf +0 -0
- data/test/uploads/1330744294.55912.sample.jpg +0 -0
- data/test/uploads/1330744296.94811.sample.jpg +0 -0
- data/test/uploads/1330744304.25529.sample.jpg +0 -0
- data/test/uploads/1330744307.08498.sample.pdf +0 -0
- data/test/uploads/1330744309.25872.sample.pdf +0 -0
- data/test/uploads/1330744443.49578.sample.jpg +0 -0
- data/test/uploads/1330744446.09032.sample.jpg +0 -0
- data/test/uploads/1330744453.55965.sample.jpg +0 -0
- data/test/uploads/1330744456.32318.sample.pdf +0 -0
- data/test/uploads/1330744458.42931.sample.pdf +0 -0
- data/test/uploads/1330744533.52631.sample.jpg +0 -0
- data/test/uploads/1330744536.13208.sample.jpg +0 -0
- data/test/uploads/1330744543.29535.sample.jpg +0 -0
- data/test/uploads/1330744546.16477.sample.pdf +0 -0
- data/test/uploads/1330744548.27125.sample.pdf +0 -0
- data/test/uploads/1330744696.43953.sample.jpg +0 -0
- data/test/uploads/1330744698.95043.sample.jpg +0 -0
- data/test/uploads/1330744706.28901.sample.jpg +0 -0
- data/test/uploads/1330744711.24284.sample.pdf +0 -0
- data/test/uploads/1330744713.6281.sample.pdf +0 -0
- data/test/uploads/1330744782.91673.sample.jpg +0 -0
- data/test/uploads/1330744785.53684.sample.jpg +0 -0
- data/test/uploads/1330744792.74599.sample.jpg +0 -0
- data/test/uploads/1330744797.90608.sample.pdf +0 -0
- data/test/uploads/1330744800.55736.sample.pdf +0 -0
- data/test/uploads/1330771358.91882.sample.jpg +0 -0
- data/test/uploads/1330771359.23929.sample.jpg +0 -0
- data/test/uploads/1330771359.70574.sample.jpg +0 -0
- data/test/uploads/1330771360.07645.sample.png +0 -0
- data/test/uploads/1330771364.83802.sample.pdf +0 -0
- data/test/uploads/1330771367.18498.sample.pdf +0 -0
- data/test/uploads/1330771514.28703.sample.jpg +0 -0
- data/test/uploads/1330771514.66497.sample.jpg +0 -0
- data/test/uploads/1330771515.12563.sample.jpg +0 -0
- data/test/uploads/1330771515.72515.sample.png +0 -0
- data/test/uploads/1330771519.30014.sample.pdf +0 -0
- data/test/uploads/1330771519.55784.sample.pdf +0 -0
- data/test/uploads/1330771519.89044.sample.pdf +0 -0
- data/test/uploads/1330771522.50763.sample.pdf +0 -0
- data/test/uploads/1330771522.75458.sample.pdf +0 -0
- data/test/uploads/1330775627.9105.sample.pdf +0 -0
- data/test/uploads/1330775628.40671.sample.pdf +0 -0
- data/test/uploads/1330775628.68645.sample.pdf +0 -0
- data/test/uploads/1330775631.48519.sample.pdf +0 -0
- data/test/uploads/1330775631.9586.sample.pdf +0 -0
- data/test/uploads/1330775676.5146.sample.pdf +0 -0
- data/test/uploads/1330775703.20143.sample.pdf +0 -0
- data/test/uploads/1330775704.36145.sample.pdf +0 -0
- data/test/uploads/1330775705.27831.sample.pdf +0 -0
- data/test/uploads/1330775706.66539.sample.pdf +0 -0
- data/test/uploads/1330776988.21579.sample.pdf +0 -0
- data/test/uploads/1330776988.69155.sample.pdf +0 -0
- data/test/uploads/1330776989.12114.sample.pdf +0 -0
- data/test/uploads/1330776992.1201.sample.pdf +0 -0
- data/test/uploads/1330776992.57634.sample.pdf +0 -0
- data/test/uploads/1330777152.6597.sample.jpg +0 -0
- data/test/uploads/1330777153.00459.sample.jpg +0 -0
- data/test/uploads/1330777153.45871.sample.jpg +0 -0
- data/test/uploads/1330777153.86376.sample.png +0 -0
- data/test/uploads/1330777157.91465.sample.pdf +0 -0
- data/test/uploads/1330777158.23816.sample.pdf +0 -0
- data/test/uploads/1330777158.74465.sample.pdf +0 -0
- data/test/uploads/1330777161.59586.sample.pdf +0 -0
- data/test/uploads/1330777161.93334.sample.pdf +0 -0
- data/test/uploads/1330777833.73591.sample.jpg +0 -0
- data/test/uploads/1330777834.05449.sample.jpg +0 -0
- data/test/uploads/1330777834.50661.sample.jpg +0 -0
- data/test/uploads/1330777834.87967.sample.jpg +0 -0
- data/test/uploads/1330777835.22949.sample.jpg +0 -0
- data/test/uploads/1330777835.55546.sample.png +0 -0
- data/test/uploads/1330777840.54959.sample.jpg +0 -0
- data/test/uploads/1330777844.18911.sample.pdf +0 -0
- data/test/uploads/1330777844.58364.sample.pdf +0 -0
- data/test/uploads/1330777844.96998.sample.pdf +0 -0
- data/test/uploads/1330777847.62838.sample.pdf +0 -0
- data/test/uploads/1330777848.0192.sample.pdf +0 -0
- data/test/uploads/1330778979.41703.sample.jpg +0 -0
- data/test/uploads/1330778979.74093.sample.jpg +0 -0
- data/test/uploads/1330778980.16769.sample.jpg +0 -0
- data/test/uploads/1330778980.54831.sample.jpg +0 -0
- data/test/uploads/1330778980.91033.sample.jpg +0 -0
- data/test/uploads/1330778981.23582.sample.png +0 -0
- data/test/uploads/1330778986.50795.sample.jpg +0 -0
- data/test/uploads/1330778989.07307.sample.pdf +0 -0
- data/test/uploads/1330778989.59241.sample.pdf +0 -0
- data/test/uploads/1330778990.06415.sample.pdf +0 -0
- data/test/uploads/1330778990.44233.sample.pdf +0 -0
- data/test/uploads/1330779134.25647.sample.jpg +0 -0
- data/test/uploads/1330779134.67957.sample.jpg +0 -0
- data/test/uploads/1330779135.15349.sample.jpg +0 -0
- data/test/uploads/1330779135.6793.sample.jpg +0 -0
- data/test/uploads/1330779136.14714.sample.jpg +0 -0
- data/test/uploads/1330779136.70598.sample.png +0 -0
- data/test/uploads/1330779141.75878.sample.jpg +0 -0
- data/test/uploads/1330779145.79811.sample.pdf +0 -0
- data/test/uploads/1330779146.40945.sample.pdf +0 -0
- data/test/uploads/1330779146.75038.sample.pdf +0 -0
- data/test/uploads/1330779149.67101.sample.pdf +0 -0
- data/test/uploads/1330779150.033.sample.pdf +0 -0
- data/test/uploads/1330779251.92468.sample.jpg +0 -0
- data/test/uploads/1330779252.33759.sample.jpg +0 -0
- data/test/uploads/1330779252.79211.sample.jpg +0 -0
- data/test/uploads/1330779253.16365.sample.jpg +0 -0
- data/test/uploads/1330779253.51459.sample.jpg +0 -0
- data/test/uploads/1330779253.82932.sample.png +0 -0
- data/test/uploads/1330779259.04186.sample.jpg +0 -0
- data/test/uploads/1330779262.79998.sample.pdf +0 -0
- data/test/uploads/1330779263.19534.sample.pdf +0 -0
- data/test/uploads/1330779263.51726.sample.pdf +0 -0
- data/test/uploads/1330779266.23965.sample.pdf +0 -0
- data/test/uploads/1330779266.65453.sample.pdf +0 -0
- data/test/uploads/1330780162.71983.1.gif +0 -0
- data/test/uploads/1330780370.60224.sample.jpg +0 -0
- data/test/uploads/1330780370.95202.sample.jpg +0 -0
- data/test/uploads/1330780371.44543.sample.jpg +0 -0
- data/test/uploads/1330780371.88658.sample.jpg +0 -0
- data/test/uploads/1330780372.30293.sample.jpg +0 -0
- data/test/uploads/1330780372.79723.sample.png +0 -0
- data/test/uploads/1330780378.19075.sample.jpg +0 -0
- data/test/uploads/1330780382.07736.sample.pdf +0 -0
- data/test/uploads/1330780382.61497.sample.pdf +0 -0
- data/test/uploads/1330780383.10458.sample.pdf +0 -0
- data/test/uploads/1330780385.85251.sample.pdf +0 -0
- data/test/uploads/1330780386.24973.sample.pdf +0 -0
- data/test/uploads/1330781258.12109.sample.pdf +0 -0
- data/test/uploads/1330781258.63862.sample.pdf +0 -0
- data/test/uploads/1330781259.10465.sample.pdf +0 -0
- data/test/uploads/1330781262.08459.sample.pdf +0 -0
- data/test/uploads/1330781262.52448.sample.pdf +0 -0
- data/test/uploads/1330781278.37307.sample.jpg +0 -0
- data/test/uploads/1330781278.7309.sample.jpg +0 -0
- data/test/uploads/1330781279.18693.sample.jpg +0 -0
- data/test/uploads/1330781279.55913.sample.jpg +0 -0
- data/test/uploads/1330781279.92436.sample.jpg +0 -0
- data/test/uploads/1330781280.27391.sample.png +0 -0
- data/test/uploads/1330886711.00348.sample.pdf +0 -0
- data/test/uploads/1330886711.78495.sample.pdf +0 -0
- data/test/uploads/1330886712.4033.sample.pdf +0 -0
- data/test/uploads/1330886716.09532.sample.pdf +0 -0
- data/test/uploads/1330886716.7663.sample.pdf +0 -0
- data/test/uploads/1330886735.38676.sample.jpg +0 -0
- data/test/uploads/1330886736.28739.sample.jpg +0 -0
- data/test/uploads/1330886736.84868.sample.jpg +0 -0
- data/test/uploads/1330886737.64167.sample.jpg +0 -0
- data/test/uploads/1330886738.33938.sample.jpg +0 -0
- data/test/uploads/1330886738.92271.sample.png +0 -0
- data/test/uploads/1330886985.6679.sample.pdf +0 -0
- data/test/uploads/1330886986.4568.sample.pdf +0 -0
- data/test/uploads/1330886987.00302.sample.pdf +0 -0
- data/test/uploads/1330886990.4604.sample.pdf +0 -0
- data/test/uploads/1330886991.04681.sample.pdf +0 -0
- data/test/uploads/1330887008.68477.sample.jpg +0 -0
- data/test/uploads/1330887009.23077.sample.jpg +0 -0
- data/test/uploads/1330887009.82498.sample.jpg +0 -0
- data/test/uploads/1330887010.48937.sample.jpg +0 -0
- data/test/uploads/1330887011.23496.sample.jpg +0 -0
- data/test/uploads/1330887011.92032.sample.png +0 -0
- data/test/uploads/1330887633.41769.sample.pdf +0 -0
- data/test/uploads/1330887633.81961.sample.pdf +0 -0
- data/test/uploads/1330887634.25582.sample.pdf +0 -0
- data/test/uploads/1330887637.47958.sample.pdf +0 -0
- data/test/uploads/1330887638.14348.sample.pdf +0 -0
- data/test/uploads/1330887655.10619.sample.jpg +0 -0
- data/test/uploads/1330887655.80139.sample.jpg +0 -0
- data/test/uploads/1330887656.35041.sample.jpg +0 -0
- data/test/uploads/1330887656.86876.sample.jpg +0 -0
- data/test/uploads/1330887657.60467.sample.jpg +0 -0
- data/test/uploads/1330887658.23424.sample.png +0 -0
- data/test/uploads/1330888133.62299.WIN.gif +0 -0
- data/test/uploads/1330888504.16714.1.gif +0 -0
- data/test/uploads/1330888586.99975.1.gif +0 -0
- data/test/uploads/1330888607.58249.shen-logic-part1.pdf +0 -0
- data/test/uploads/1330889585.30006.shen-logic-part2.pdf +0 -0
- data/test/uploads/1330890565.79547.shen-logic-part1.pdf +0 -0
- data/test/uploads/1330890992.45693.sample.jpg +0 -0
- data/test/uploads/1330890998.10996.sample.pdf +0 -0
- data/test/uploads/1330890998.76199.sample.pdf +0 -0
- data/test/uploads/1330890999.14516.sample.pdf +0 -0
- data/test/uploads/1330891002.0989.sample.pdf +0 -0
- data/test/uploads/1330891002.49258.sample.pdf +0 -0
- data/test/uploads/1330891004.89888.sample.jpg +0 -0
- data/test/uploads/1330891007.45147.sample.jpg +0 -0
- data/test/uploads/1330891052.00842.sample.jpg +0 -0
- data/test/uploads/1330891056.46428.sample.pdf +0 -0
- data/test/uploads/1330891056.83678.sample.pdf +0 -0
- data/test/uploads/1330891057.31732.sample.pdf +0 -0
- data/test/uploads/1330891057.86036.sample.pdf +0 -0
- data/test/uploads/1330891058.49616.sample.pdf +0 -0
- data/test/uploads/1330891058.91288.sample.pdf +0 -0
- data/test/uploads/1330891138.7408.sample.pdf +0 -0
- data/test/uploads/1330891139.14067.sample.pdf +0 -0
- data/test/uploads/1330891139.46755.sample.pdf +0 -0
- data/test/uploads/1330891142.26432.sample.pdf +0 -0
- data/test/uploads/1330891142.684.sample.pdf +0 -0
- data/test/uploads/1330891158.04426.sample.jpg +0 -0
- data/test/uploads/1330891158.44159.sample.jpg +0 -0
- data/test/uploads/1330891158.85135.sample.jpg +0 -0
- data/test/uploads/1330891159.3765.sample.jpg +0 -0
- data/test/uploads/1330891159.79503.sample.jpg +0 -0
- data/test/uploads/1330891160.15479.sample.png +0 -0
- data/test/uploads/1330900466.37214.sample.pdf +0 -0
- data/test/uploads/1330900466.77443.sample.pdf +0 -0
- data/test/uploads/1330900467.32831.sample.pdf +0 -0
- data/test/uploads/1330900470.07702.sample.pdf +0 -0
- data/test/uploads/1330900470.48767.sample.pdf +0 -0
- data/test/uploads/1330900486.92727.sample.jpg +0 -0
- data/test/uploads/1330900487.4311.sample.jpg +0 -0
- data/test/uploads/1330900488.03152.sample.jpg +0 -0
- data/test/uploads/1330900488.43945.sample.jpg +0 -0
- data/test/uploads/1330900489.01433.sample.jpg +0 -0
- data/test/uploads/1330900489.43854.sample.png +0 -0
- data/vendor/assets/javascripts/simple_attachments.js +138 -0
- data/vendor/assets/stylesheets/simple_attachments.css +23 -0
- 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
|