├── .gitignore ├── CHANGELOG ├── Gemfile ├── Gemfile.lock ├── Guardfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app └── controllers │ └── attachinary │ ├── application_controller.rb │ └── cors_controller.rb ├── attachinary.gemspec ├── config └── routes.rb ├── db └── migrate │ └── 20120612112526_create_attachinary_tables.rb ├── lib ├── assets │ └── javascripts │ │ └── attachinary.js.coffee ├── attachinary.rb ├── attachinary │ ├── engine.rb │ ├── form_builder.rb │ ├── orm │ │ ├── active_record.rb │ │ ├── active_record │ │ │ ├── extension.rb │ │ │ └── file.rb │ │ ├── base_extension.rb │ │ ├── file_mixin.rb │ │ ├── mongoid.rb │ │ └── mongoid │ │ │ ├── extension.rb │ │ │ └── file.rb │ ├── simple_form.rb │ ├── utils.rb │ ├── version.rb │ └── view_helpers.rb └── tasks │ └── attachinary.rake ├── script └── rails └── spec ├── dummy ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── app │ ├── active_record │ │ └── note.rb │ ├── assets │ │ ├── javascripts │ │ │ └── application.js │ │ └── stylesheets │ │ │ └── application.css │ ├── controllers │ │ ├── application_controller.rb │ │ └── notes_controller.rb │ ├── mongoid │ │ └── note.rb │ └── views │ │ ├── layouts │ │ └── application.html.erb │ │ └── notes │ │ ├── _form_builder.html.erb │ │ ├── _form_nojs.html.erb │ │ ├── _form_raw.html.erb │ │ ├── _form_simple_form.html.erb │ │ ├── _note.html.erb │ │ ├── edit.html.erb │ │ ├── index.html.erb │ │ └── new.html.erb ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── cloudinary.yml.example │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── attachinary.rb │ │ ├── backtrace_silencers.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── secret_token.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ ├── mongoid.yml │ └── routes.rb ├── db │ ├── migrate │ │ ├── 20120608091037_create_tables.rb │ │ └── 20120608104143_create_notes.rb │ └── schema.rb ├── lib │ └── assets │ │ └── .gitkeep ├── log │ └── .gitkeep ├── public │ └── .gitkeep ├── script │ └── rails ├── spec │ ├── rails_helper.rb │ └── spec_helper.rb └── vendor │ └── assets │ └── javascripts │ ├── jquery.fileupload.js │ ├── jquery.iframe-transport.js │ └── jquery.ui.widget.js ├── dummy4 ├── .bowerrc ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.rdoc ├── Rakefile ├── app │ ├── active_record │ │ └── note.rb │ ├── assets │ │ ├── images │ │ │ └── .keep │ │ ├── javascripts │ │ │ ├── application.js │ │ │ └── notes.coffee │ │ └── stylesheets │ │ │ ├── application.scss │ │ │ ├── notes.scss │ │ │ └── scaffolds.scss │ ├── controllers │ │ ├── application_controller.rb │ │ ├── concerns │ │ │ └── .keep │ │ └── notes_controller.rb │ ├── helpers │ │ ├── application_helper.rb │ │ └── notes_helper.rb │ ├── mailers │ │ └── .keep │ ├── models │ │ ├── .keep │ │ └── concerns │ │ │ └── .keep │ ├── mongoid │ │ └── note.rb │ └── views │ │ ├── layouts │ │ └── application.html.erb │ │ └── notes │ │ ├── _form.html.erb │ │ ├── _form_builder.html.erb │ │ ├── _form_nojs.html.erb │ │ ├── _form_raw.html.erb │ │ ├── _form_simple_form.html.erb │ │ ├── _note.html.erb │ │ ├── edit.html.erb │ │ ├── index.html.erb │ │ ├── index.json.jbuilder │ │ ├── new.html.erb │ │ ├── show.html.erb │ │ └── show.json.jbuilder ├── bower.json ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── assets.rb │ │ ├── attachinary.rb │ │ ├── backtrace_silencers.rb │ │ ├── cookies_serializer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ ├── mongoid.yml │ ├── routes.rb │ └── secrets.yml ├── db │ └── seeds.rb ├── lib │ ├── assets │ │ └── .keep │ └── tasks │ │ └── .keep ├── log │ └── .keep ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── favicon.ico │ └── robots.txt ├── spec │ ├── rails_helper.rb │ └── spec_helper.rb ├── test │ ├── controllers │ │ ├── .keep │ │ └── notes_controller_test.rb │ ├── fixtures │ │ ├── .keep │ │ └── notes.yml │ ├── helpers │ │ └── .keep │ ├── integration │ │ └── .keep │ ├── mailers │ │ └── .keep │ ├── models │ │ ├── .keep │ │ └── note_test.rb │ └── test_helper.rb └── vendor │ └── assets │ ├── javascripts │ └── .keep │ └── stylesheets │ └── .keep ├── factories.rb ├── features └── notes_spec.rb ├── models ├── attachinary │ └── file_spec.rb └── note_spec.rb ├── orm ├── active_record.rb └── mongoid.rb ├── spec_helper.rb └── support ├── A.gif ├── A.txt ├── B.gif ├── C.gif └── request_helpers.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | .DS_Store 3 | log/*.log 4 | pkg/ 5 | spec/dummy/db/*.sqlite3 6 | spec/dummy/log/*.log 7 | spec/dummy/tmp/ 8 | spec/dummy/.sass-cache 9 | spec/dummy/config/cloudinary.yml 10 | bin/ 11 | 12 | .rspec 13 | config/cloudinary.yml 14 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | = Version 1.3.0 2 | * Added support for Rails 4 (thanks @rochers) 3 | * Use resource type when building cloudinary urls 4 | * Make deletion of remote resources configurable 5 | * Add some optional convenience configurations to attachinary.js 6 | 7 | = Version 1.2.7 (wip) 8 | * Implemented raw file type handling (roomthirteen) 9 | 10 | = Version 1.2.6 11 | * Added "attachinary:fileadded" and "attachinary:fileremoved" js events 12 | 13 | = Version 1.2.5 14 | * BUG FIX: Default jQuery plugin options mutation 15 | 16 | = Version 1.2.4 17 | * Ability to specify custom dropzone via config (drewmca) 18 | * BUG FIX: Bad browsers (IE) can put '[null]' into the attachinary hash (Yan Pritzker) 19 | * BUG FIX: Ensuring tags are unique (Yan Pritzker) 20 | 21 | = Version 1.2.3 22 | * Fixed bug with multiple submit buttons in one form (Benjamin Seibert) 23 | * IE content-type fix (Yan Pritzker) 24 | 25 | = Version 1.2.2 26 | * Ability to cleanup unused files: 27 | files are automatically tagged with `attachinary_tmp` during upload, and 28 | untagged when saved in local database. 29 | 30 | = Version 1.2.1 31 | * bugfix: already uploaded image gets deleted from cloudinary when updating model [#29] 32 | 33 | = Version 1.2.0 34 | * Drag and drop support (on supported browsers) 35 | * Selecting multiple files (on supported browsers) 36 | * Upload progress indicator (prepended on submit button) 37 | * Rake task for fetching assets (`rake attachinary:fetch_fileupload`) 38 | * Ability to assing image urls (e.g. `user.avatar_url = 'http://..'`) 39 | * Ability to assign IO objects (e.g. `user.avatar = File.open(...)`) 40 | * No-JS support 41 | 42 | = Version 1.1.0 43 | * BUG FIX: disabling submit key (thanks @drewmca) 44 | * BUG FIX: models attachments are now removed from cloudinary 45 | after model is destoyed [mongoid] 46 | * ability to use form builder (`f.attachinary_file_field :avatar`) 47 | * BUG FIX: proper field names and ids are generated [simple_form] 48 | 49 | = Version 1.0.1 50 | * bug fix release 51 | 52 | = Version 1.0.0 53 | * Support for Mongoid added. You need to specify which ORM you want 54 | to use by explicitly requiring it. 55 | * No backward compatibility. 56 | * Changed database schema (from N-N to 1-N). Assoc preloading made easier. 57 | 58 | = Version 0.0.8 59 | * no explicit require of cloudinary assets 60 | 61 | = Version 0.0.7 62 | * BUG FIX: removing single attachment 63 | 64 | = Version 0.0.6 65 | * attachment lazy loading 66 | * removed copies of cloudinary javascript files 67 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Declare your gem's dependencies in attachinary.gemspec. 4 | # Bundler will treat runtime dependencies like base dependencies, and 5 | # development dependencies will be added by default to the :development group. 6 | gemspec 7 | 8 | # used by the dummy application 9 | gem 'jquery-rails' 10 | gem 'cloudinary' 11 | gem 'simple_form' 12 | 13 | group :assets do 14 | gem 'coffee-rails' 15 | end 16 | 17 | group :mongoid do 18 | gem 'mongoid' 19 | end 20 | 21 | 22 | # Declare any dependencies that are still in development here instead of in 23 | # your gemspec. These might include edge Rails or gems from your path or 24 | # Git. Remember to move these dependencies to your gemspec before releasing 25 | # your gem to rubygems.org. 26 | 27 | # To use debugger 28 | # gem 'debugger' 29 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | attachinary (1.3.1) 5 | cloudinary (~> 1.1.0) 6 | rails (>= 3.2) 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actionmailer (4.2.3) 12 | actionpack (= 4.2.3) 13 | actionview (= 4.2.3) 14 | activejob (= 4.2.3) 15 | mail (~> 2.5, >= 2.5.4) 16 | rails-dom-testing (~> 1.0, >= 1.0.5) 17 | actionpack (4.2.3) 18 | actionview (= 4.2.3) 19 | activesupport (= 4.2.3) 20 | rack (~> 1.6) 21 | rack-test (~> 0.6.2) 22 | rails-dom-testing (~> 1.0, >= 1.0.5) 23 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 24 | actionview (4.2.3) 25 | activesupport (= 4.2.3) 26 | builder (~> 3.1) 27 | erubis (~> 2.7.0) 28 | rails-dom-testing (~> 1.0, >= 1.0.5) 29 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 30 | activejob (4.2.3) 31 | activesupport (= 4.2.3) 32 | globalid (>= 0.3.0) 33 | activemodel (4.2.3) 34 | activesupport (= 4.2.3) 35 | builder (~> 3.1) 36 | activerecord (4.2.3) 37 | activemodel (= 4.2.3) 38 | activesupport (= 4.2.3) 39 | arel (~> 6.0) 40 | activesupport (4.2.3) 41 | i18n (~> 0.7) 42 | json (~> 1.7, >= 1.7.7) 43 | minitest (~> 5.1) 44 | thread_safe (~> 0.3, >= 0.3.4) 45 | tzinfo (~> 1.1) 46 | addressable (2.3.8) 47 | arel (6.0.3) 48 | aws_cf_signer (0.1.3) 49 | bson (3.1.2) 50 | builder (3.2.2) 51 | capybara (2.4.4) 52 | mime-types (>= 1.16) 53 | nokogiri (>= 1.3.3) 54 | rack (>= 1.0.0) 55 | rack-test (>= 0.5.4) 56 | xpath (~> 2.0) 57 | capybara-webkit (1.6.0) 58 | capybara (>= 2.3.0, < 2.5.0) 59 | json 60 | cloudinary (1.1.0) 61 | aws_cf_signer 62 | rest-client 63 | coderay (1.1.0) 64 | coffee-rails (4.1.0) 65 | coffee-script (>= 2.2.0) 66 | railties (>= 4.0.0, < 5.0) 67 | coffee-script (2.4.1) 68 | coffee-script-source 69 | execjs 70 | coffee-script-source (1.9.1.1) 71 | connection_pool (2.2.0) 72 | database_cleaner (1.4.1) 73 | diff-lcs (1.2.5) 74 | domain_name (0.5.24) 75 | unf (>= 0.0.5, < 1.0.0) 76 | erubis (2.7.0) 77 | execjs (2.5.2) 78 | factory_girl (4.5.0) 79 | activesupport (>= 3.0.0) 80 | factory_girl_rails (4.5.0) 81 | factory_girl (~> 4.5.0) 82 | railties (>= 3.0.0) 83 | ffi (1.9.10) 84 | formatador (0.2.5) 85 | globalid (0.3.6) 86 | activesupport (>= 4.1.0) 87 | guard (2.12.8) 88 | formatador (>= 0.2.4) 89 | listen (>= 2.7, <= 4.0) 90 | lumberjack (~> 1.0) 91 | nenv (~> 0.1) 92 | notiffany (~> 0.0) 93 | pry (>= 0.9.12) 94 | shellany (~> 0.0) 95 | thor (>= 0.18.1) 96 | guard-compat (1.2.1) 97 | guard-rspec (4.6.2) 98 | guard (~> 2.1) 99 | guard-compat (~> 1.1) 100 | rspec (>= 2.99.0, < 4.0) 101 | http-cookie (1.0.2) 102 | domain_name (~> 0.5) 103 | i18n (0.7.0) 104 | jquery-rails (4.0.4) 105 | rails-dom-testing (~> 1.0) 106 | railties (>= 4.2.0) 107 | thor (>= 0.14, < 2.0) 108 | json (1.8.3) 109 | launchy (2.4.3) 110 | addressable (~> 2.3) 111 | listen (3.0.2) 112 | rb-fsevent (>= 0.9.3) 113 | rb-inotify (>= 0.9) 114 | loofah (2.0.2) 115 | nokogiri (>= 1.5.9) 116 | lumberjack (1.0.9) 117 | mail (2.6.3) 118 | mime-types (>= 1.16, < 3) 119 | method_source (0.8.2) 120 | mime-types (2.6.1) 121 | mini_portile (0.6.2) 122 | minitest (5.7.0) 123 | mongoid (4.0.2) 124 | activemodel (~> 4.0) 125 | moped (~> 2.0.0) 126 | origin (~> 2.1) 127 | tzinfo (>= 0.3.37) 128 | moped (2.0.6) 129 | bson (~> 3.0) 130 | connection_pool (~> 2.0) 131 | optionable (~> 0.2.0) 132 | nenv (0.2.0) 133 | netrc (0.10.3) 134 | nokogiri (1.6.6.2) 135 | mini_portile (~> 0.6.0) 136 | notiffany (0.0.6) 137 | nenv (~> 0.1) 138 | shellany (~> 0.0) 139 | optionable (0.2.0) 140 | origin (2.1.1) 141 | pry (0.10.1) 142 | coderay (~> 1.1.0) 143 | method_source (~> 0.8.1) 144 | slop (~> 3.4) 145 | rack (1.6.4) 146 | rack-test (0.6.3) 147 | rack (>= 1.0) 148 | rails (4.2.3) 149 | actionmailer (= 4.2.3) 150 | actionpack (= 4.2.3) 151 | actionview (= 4.2.3) 152 | activejob (= 4.2.3) 153 | activemodel (= 4.2.3) 154 | activerecord (= 4.2.3) 155 | activesupport (= 4.2.3) 156 | bundler (>= 1.3.0, < 2.0) 157 | railties (= 4.2.3) 158 | sprockets-rails 159 | rails-deprecated_sanitizer (1.0.3) 160 | activesupport (>= 4.2.0.alpha) 161 | rails-dom-testing (1.0.6) 162 | activesupport (>= 4.2.0.beta, < 5.0) 163 | nokogiri (~> 1.6.0) 164 | rails-deprecated_sanitizer (>= 1.0.1) 165 | rails-html-sanitizer (1.0.2) 166 | loofah (~> 2.0) 167 | railties (4.2.3) 168 | actionpack (= 4.2.3) 169 | activesupport (= 4.2.3) 170 | rake (>= 0.8.7) 171 | thor (>= 0.18.1, < 2.0) 172 | rake (10.4.2) 173 | rb-fsevent (0.9.5) 174 | rb-inotify (0.9.5) 175 | ffi (>= 0.5.0) 176 | rest-client (1.8.0) 177 | http-cookie (>= 1.0.2, < 2.0) 178 | mime-types (>= 1.16, < 3.0) 179 | netrc (~> 0.7) 180 | rspec (3.3.0) 181 | rspec-core (~> 3.3.0) 182 | rspec-expectations (~> 3.3.0) 183 | rspec-mocks (~> 3.3.0) 184 | rspec-core (3.3.2) 185 | rspec-support (~> 3.3.0) 186 | rspec-expectations (3.3.1) 187 | diff-lcs (>= 1.2.0, < 2.0) 188 | rspec-support (~> 3.3.0) 189 | rspec-mocks (3.3.2) 190 | diff-lcs (>= 1.2.0, < 2.0) 191 | rspec-support (~> 3.3.0) 192 | rspec-rails (3.3.3) 193 | actionpack (>= 3.0, < 4.3) 194 | activesupport (>= 3.0, < 4.3) 195 | railties (>= 3.0, < 4.3) 196 | rspec-core (~> 3.3.0) 197 | rspec-expectations (~> 3.3.0) 198 | rspec-mocks (~> 3.3.0) 199 | rspec-support (~> 3.3.0) 200 | rspec-support (3.3.0) 201 | shellany (0.0.1) 202 | simple_form (3.1.0) 203 | actionpack (~> 4.0) 204 | activemodel (~> 4.0) 205 | slop (3.6.0) 206 | sprockets (3.3.4) 207 | rack (~> 1.0) 208 | sprockets-rails (2.3.3) 209 | actionpack (>= 3.0) 210 | activesupport (>= 3.0) 211 | sprockets (>= 2.8, < 4.0) 212 | sqlite3 (1.3.10) 213 | thor (0.19.1) 214 | thread_safe (0.3.5) 215 | tzinfo (1.2.2) 216 | thread_safe (~> 0.1) 217 | unf (0.1.4) 218 | unf_ext 219 | unf_ext (0.0.7.1) 220 | valid_attribute (2.0.0) 221 | xpath (2.0.0) 222 | nokogiri (~> 1.3) 223 | 224 | PLATFORMS 225 | ruby 226 | 227 | DEPENDENCIES 228 | attachinary! 229 | capybara 230 | capybara-webkit 231 | cloudinary 232 | coffee-rails 233 | database_cleaner 234 | factory_girl_rails 235 | guard-rspec 236 | jquery-rails 237 | launchy 238 | mongoid 239 | rb-fsevent (~> 0.9.1) 240 | rspec-rails 241 | simple_form 242 | sqlite3 243 | valid_attribute 244 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | 4 | guard 'rspec' do 5 | # uses the .rspec file 6 | # --colour --fail-fast --format documentation --tag ~slow 7 | watch(%r{^spec/.+_spec\.rb$}) 8 | watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } 9 | watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } 10 | watch(%r{^app/views/(.+)/.+\.erb$}) { |m| "spec/integration/#{m[1]}_spec.rb" } 11 | watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| "spec/intagration/#{m[1]}_spec.rb" } 12 | end 13 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012 Milovan Zogovic 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. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Attachinary 2 | 3 | [![Gem Version](https://badge.fury.io/rb/attachinary.png)](http://badge.fury.io/rb/attachinary) 4 | 5 | _Note: v1 is not backward compatible. Refer to [wiki](https://github.com/assembler/attachinary/wiki/Upgrading-to-v1.0) on how to upgrade._ 6 | 7 | Need lightweight attachment (photos and raw files) handler for any of your model, in either has\_one or has\_many relation, without altering your models' schema and with zero effort? Attachinary is the tool for you! 8 | 9 | Why is Attachinary different: 10 | 11 | * Supports both **ActiveRecord** and **Mongoid** ORMs! 12 | * **No need to alter your model schema** every time you introduce new kind of attachment. 13 | * Handles **both has\_one and has\_many** use cases. 14 | * **No need for ImageMagick** (or similar) - your thumbnails are generated on the fly by Cloudinary. 15 | * Fully customizable, custom **jQuery plugin** for async file uploads with previews. 16 | * **Files are uploaded directly to Cloudinary** completely bypassing your app (without affecting its performance). 17 | * **Very easy to use**. Once set up, 1 line is enough to add attachment support to your model. **No migrations, no Uploaders**. 18 | * **Lightweight form submission**. Attachinary handles file upload asynchronously and the only thing that is passed to your server is metadata. That makes form postbacks fast and reliable. 19 | * Benefits of [jQuery File Upload](https://github.com/blueimp/jQuery-File-Upload/) (**drag'n'drop**, **selecting multiple files**, **progress indicators**.. etc) 20 | * All the [benefits of Cloudinary](http://cloudinary.com/documentation/image_transformations) (resizing, cropping, rotating, rounding corners, **face detection**...). 21 | 22 | Attachinary uses [Cloudinary](http://cloudinary.com) service. Gem is structured as mountable rails engine. 23 | 24 | 25 | ## Installation 26 | 27 | First, make sure that you have [cloudinary gem](https://github.com/cloudinary/cloudinary_gem) installed and properly configured. 28 | 29 | Add following line to your `Gemfile`: 30 | 31 | gem 'attachinary' 32 | 33 | Specify which ORM you wish to use by adding following line to your `application.rb` file (or custom initializer): 34 | 35 | require "attachinary/orm/YOUR_ORM" # active_record or mongoid 36 | 37 | If you're using `ActiveRecord` ORM, then run following lines to generate required table: 38 | 39 | rake attachinary:install:migrations 40 | rake db:migrate 41 | 42 | Next, add following line in your `routes.rb` file: 43 | 44 | mount Attachinary::Engine => "/attachinary" 45 | 46 | It will generate '/attachinary/cors' which will be used for iframe file transfers (for unsupported browsers). 47 | 48 | Finally, make sure that you have following line in head section of your application layout file: 49 | 50 | <%= cloudinary_js_config %> 51 | 52 | 53 | 54 | ## Usage 55 | 56 | Lets say that we want all of our **users** to have single **avatar** and many **photos** in their gallery. We also want *avatar* to be required. We also want to limit the number of photos user can upload to 10. We can declare it like this: 57 | 58 | ```ruby 59 | class User < ActiveRecord::Base 60 | ... 61 | has_attachment :avatar, accept: [:jpg, :png, :gif] 62 | has_attachments :photos, maximum: 10 63 | 64 | validates :avatar, presence: true 65 | # ... 66 | end 67 | ``` 68 | 69 | In our `_form.html.erb` template, we need to add only this: 70 | 71 | ```erb 72 | <%= f.attachinary_file_field :avatar %> 73 | <%= f.attachinary_file_field :photos %> 74 | ``` 75 | 76 | If you're using [SimpleForm](https://github.com/plataformatec/simple_form), you can even shorten this to: 77 | 78 | ```erb 79 | <%= f.input :avatar, as: :attachinary %> 80 | <%= f.input :photos, as: :attachinary %> 81 | ``` 82 | 83 | Finally, you have to include necessary javascript files. In your `application.js`, add following lines: 84 | 85 | ```javascript 86 | //= require jquery.ui.widget 87 | //= require jquery.iframe-transport 88 | //= require jquery.fileupload 89 | //= require cloudinary/jquery.cloudinary 90 | //= require attachinary 91 | ``` 92 | 93 | If you don't have the jQuery File Upload files, you can use following rake task to fetch (or update) them: 94 | 95 | ``` 96 | rake attachinary:fetch_fileupload 97 | ``` 98 | 99 | And, add this code on document ready: 100 | 101 | ```javascript 102 | $('.attachinary-input').attachinary() 103 | ``` 104 | 105 | Attachinary jquery plugin is based upon [jQuery File Upload plugin](https://github.com/blueimp/jQuery-File-Upload) but without any fancy UI (it leaves it up to you to decorate it). 106 | 107 | Plugin is fully customizable. It uses John Resig's micro templating in the background, but you can override it with whatever you like. Check out the source code for more configuration options you can set. 108 | 109 | 110 | ### Displaying avatar and photos 111 | 112 | Here comes the good part. There is no need to transform images on your server. Instead, you can request image transformations directly from Cloudinary. First time you request image, it is created and cached on the Cloudinary server for later use. Here is sample code that you can use in your `_user.html.erb` partial: 113 | 114 | ```erb 115 | <% if @user.avatar? %> 116 | <%= cl_image_tag(@user.avatar.path, { size: '50x50', crop: :thumb, gravity: :face }) %> 117 | <% end %> 118 | 119 | <% @user.photos.each do |photo| %> 120 | <%= cl_image_tag(photo.path, { size: '125x125', crop: :fit }) %> 121 | <% end %> 122 | ``` 123 | 124 | Avatar will be automatically cropped to 50x50px to show only user face. You read it right: **face detection** :) All other user photos are just cropped to fit within 125x125. 125 | 126 | Whenever you feel like changing image sizes, you don't need to set rake task that will take forever to re-process thousands of photos. You just change the dimension in your partial and thats it. 127 | 128 | 129 | ### Additional methods 130 | 131 | ```ruby 132 | # uploading avatar by passing url 133 | user.avatar_url = "http://path/to/avatar.jpg" 134 | 135 | # uploading photos by passing multiple urls 136 | user.photo_urls = %w[ http://path/to/photo1.jpg http://path/to/photo2.jpg] 137 | 138 | # uploading by passing IO object (e.g. direct file upload) 139 | user.avatar = File.open("/path/to/file", 'r') 140 | 141 | # if you want to provide additionals parameters from http://cloudinary.com/documentation/upload_images 142 | # you need to use diffrent syntax 143 | user.send(:avatar=, File.open("path/to/file", 'r'), :folder => Rails.env.to_s) 144 | 145 | # # uploading photos by passing multiple urls and optional parameters that will be added to every file. 146 | user.send(:photo_urls=, %w[ http://path/to/photo1.jpg http://path/to/photo2.jpg], folder: Rails.env.to_s, use_filename: true, image_metadata: true) 147 | 148 | ``` 149 | 150 | 151 | ### No-JS usage 152 | 153 | If you don't want fancy JS features, all you have to do is just switch to `:input` file field: 154 | 155 | ```erb 156 | <%= f.input :photo, as: :file %> 157 | <%= f.input :images, as: :file, input_html: { multiple: true } %> 158 | ``` 159 | 160 | ### Preventing n+1 queries when loading attachinary associations 161 | 162 | You can eager load attachinary associations. 163 | 164 | For example, I have a `user` model that has `photo` and `avatar` as attachments. 165 | 166 | ```rb 167 | # user.rb 168 | has_attachment :avatar 169 | has_attachments :photos 170 | 171 | # users_controller.rb 172 | User.includes(:avatar_files, :photo_files).all 173 | ``` 174 | 175 | ## Conventions 176 | 177 | * always use singular identifier after `has_attachment` (e.g. `has_attachment :photo`) 178 | * always use plural identifier after `has_attachments` (e.g. `has_attachments :images`) 179 | * do not use colliding identifiers (e.g. `has_attachment :photo` and `has_attachments :photos`) on same model. 180 | 181 | 182 | ## Requirements and Compatibility 183 | 184 | * Cloudinary 185 | * Ruby 1.9 186 | * Rails 3.2+ 187 | * jQuery 188 | 189 | 190 | ### Browser Compatibility 191 | 192 | Attachinary jquery plugin uses JSON2 to generate JSON data. 193 | This works for all major browsers, but if you wish to support older ones (e.g. IE7-), include [json2.js](https://github.com/douglascrockford/JSON-js/blob/master/json2.js). 194 | 195 | 196 | ## Credits and License 197 | 198 | Developed by Milovan Zogovic. 199 | 200 | This software is released under the MIT License. 201 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | begin 3 | require 'bundler/setup' 4 | rescue LoadError 5 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 6 | end 7 | begin 8 | require 'rdoc/task' 9 | rescue LoadError 10 | require 'rdoc/rdoc' 11 | require 'rake/rdoctask' 12 | RDoc::Task = Rake::RDocTask 13 | end 14 | 15 | RDoc::Task.new(:rdoc) do |rdoc| 16 | rdoc.rdoc_dir = 'rdoc' 17 | rdoc.title = 'Attachinary' 18 | rdoc.options << '--line-numbers' 19 | rdoc.rdoc_files.include('README.rdoc') 20 | rdoc.rdoc_files.include('lib/**/*.rb') 21 | end 22 | 23 | APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) 24 | load 'rails/tasks/engine.rake' 25 | 26 | 27 | 28 | Bundler::GemHelper.install_tasks 29 | 30 | #require 'rake/spectask' 31 | 32 | # Spec::Rake::SpecTask.new(:spec) do |t| 33 | # t.libs << 'lib' 34 | # t.libs << 'spec' 35 | # t.pattern = 'spec/**/*_spec.rb' 36 | # t.verbose = false 37 | # end 38 | 39 | require 'rspec/core/rake_task' 40 | RSpec::Core::RakeTask.new(:spec) 41 | 42 | 43 | desc 'Run Devise tests for all ORMs.' 44 | task :spec_all_orms do 45 | Dir[File.join(File.dirname(__FILE__), 'spec', 'orm', '*.rb')].each do |file| 46 | orm = File.basename(file).split(".").first 47 | puts "\n\n-------- ORM: #{orm}\n\n" 48 | exit 1 unless system "rake spec ATTACHINARY_ORM=#{orm}" 49 | end 50 | end 51 | 52 | task :default => :spec_all_orms 53 | -------------------------------------------------------------------------------- /app/controllers/attachinary/application_controller.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | class ApplicationController < ActionController::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/attachinary/cors_controller.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | class CorsController < Attachinary::ApplicationController 3 | 4 | def show 5 | respond_to do |format| 6 | format.json { render json: request.query_parameters, content_type: "text/plain" } 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /attachinary.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require "attachinary/version" 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |s| 8 | s.name = "attachinary" 9 | s.version = Attachinary::VERSION 10 | s.authors = ["Milovan Zogovic"] 11 | s.email = ["milovan.zogovic@gmail.com"] 12 | s.homepage = "" 13 | s.summary = "attachinary-#{s.version}" 14 | s.description = "Attachments handler for Rails that uses Cloudinary for storage." 15 | 16 | s.files = Dir["{app,config,db,lib,vendor}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.md"] 17 | s.test_files = Dir["test/**/*"] 18 | 19 | s.add_dependency 'rails', '>= 3.2' 20 | s.add_dependency 'cloudinary', '~> 1.1.0' 21 | 22 | s.add_development_dependency 'sqlite3' 23 | s.add_development_dependency 'rspec-rails' 24 | s.add_development_dependency 'valid_attribute' 25 | s.add_development_dependency 'capybara' 26 | s.add_development_dependency 'capybara-webkit' 27 | s.add_development_dependency 'factory_girl_rails' 28 | s.add_development_dependency 'launchy' 29 | s.add_development_dependency 'database_cleaner' 30 | s.add_development_dependency 'rb-fsevent', '~> 0.9.1' 31 | s.add_development_dependency 'guard-rspec' 32 | end 33 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Attachinary::Engine.routes.draw do 2 | get '/cors' => 'cors#show', format: 'json', as: 'cors' 3 | end 4 | -------------------------------------------------------------------------------- /db/migrate/20120612112526_create_attachinary_tables.rb: -------------------------------------------------------------------------------- 1 | class CreateAttachinaryTables < ActiveRecord::Migration 2 | def change 3 | create_table :attachinary_files do |t| 4 | t.references :attachinariable, polymorphic: true 5 | t.string :scope 6 | 7 | t.string :public_id 8 | t.string :version 9 | t.integer :width 10 | t.integer :height 11 | t.string :format 12 | t.string :resource_type 13 | t.timestamps 14 | end 15 | add_index :attachinary_files, [:attachinariable_type, :attachinariable_id, :scope], name: 'by_scoped_parent' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/assets/javascripts/attachinary.js.coffee: -------------------------------------------------------------------------------- 1 | (($) -> 2 | 3 | $.attachinary = 4 | index: 0 5 | config: 6 | disableWith: 'Uploading...' 7 | indicateProgress: true 8 | invalidFormatMessage: 'Invalid file format' 9 | template: """ 10 | 26 | """ 27 | render: (files) -> 28 | $.attachinary.Templating.template(@template, files: files) 29 | 30 | 31 | $.fn.attachinary = (options) -> 32 | settings = $.extend {}, $.attachinary.config, options 33 | 34 | this.each -> 35 | $this = $(this) 36 | 37 | if !$this.data('attachinary-bond') 38 | $this.data 'attachinary-bond', new $.attachinary.Attachinary($this, settings) 39 | 40 | 41 | 42 | class $.attachinary.Attachinary 43 | constructor: (@$input, @config) -> 44 | @options = @$input.data('attachinary') 45 | @files = @options.files 46 | 47 | @$form = @$input.closest('form') 48 | @$submit = @$form.find(@options.submit_selector ? 'input[type=submit]') 49 | @$wrapper = @$input.closest(@options.wrapper_container_selector) if @options.wrapper_container_selector? 50 | 51 | @initFileUpload() 52 | @addFilesContainer() 53 | @bindEventHandlers() 54 | @redraw() 55 | @checkMaximum() 56 | 57 | initFileUpload: -> 58 | @options.field_name = @$input.attr('name') 59 | 60 | options = 61 | dataType: 'json' 62 | paramName: 'file' 63 | headers: {"X-Requested-With": "XMLHttpRequest"} 64 | dropZone: @config.dropZone || @$input 65 | sequentialUploads: true 66 | 67 | if @$input.attr('accept') 68 | options.acceptFileTypes = new RegExp("^#{@$input.attr('accept').split(",").join("|")}$", "i") 69 | 70 | @$input.fileupload(options) 71 | 72 | bindEventHandlers: -> 73 | @$input.bind 'fileuploadsend', (event, data) => 74 | @$input.addClass 'uploading' 75 | @$wrapper.addClass 'uploading' if @$wrapper? 76 | @$form.addClass 'uploading' 77 | 78 | @$input.prop 'disabled', true 79 | if @config.disableWith 80 | @$submit.each (index,input) => 81 | $input = $(input) 82 | $input.data 'old-val', $input.val() unless $input.data('old-val')? 83 | @$submit.val @config.disableWith 84 | @$submit.prop 'disabled', true 85 | 86 | !@maximumReached() 87 | 88 | 89 | @$input.bind 'fileuploaddone', (event, data) => 90 | @addFile(data.result) 91 | 92 | 93 | @$input.bind 'fileuploadstart', (event) => 94 | # important! changed on every file upload 95 | @$input = $(event.target) 96 | 97 | 98 | @$input.bind 'fileuploadalways', (event) => 99 | @$input.removeClass 'uploading' 100 | @$wrapper.removeClass 'uploading' if @$wrapper? 101 | @$form.removeClass 'uploading' 102 | 103 | @checkMaximum() 104 | if @config.disableWith 105 | @$submit.each (index,input) => 106 | $input = $(input) 107 | $input.val $input.data('old-val') 108 | @$submit.prop 'disabled', false 109 | 110 | 111 | @$input.bind 'fileuploadprogressall', (e, data) => 112 | progress = parseInt(data.loaded / data.total * 100, 10) 113 | if @config.disableWith && @config.indicateProgress 114 | @$submit.val "[#{progress}%] #{@config.disableWith}" 115 | 116 | 117 | addFile: (file) -> 118 | if !@options.accept || $.inArray(file.format, @options.accept) != -1 || $.inArray(file.resource_type, @options.accept) != -1 119 | @files.push file 120 | @redraw() 121 | @checkMaximum() 122 | @$input.trigger 'attachinary:fileadded', [file] 123 | else 124 | alert @config.invalidFormatMessage 125 | 126 | removeFile: (fileIdToRemove) -> 127 | _files = [] 128 | removedFile = null 129 | for file in @files 130 | if file.public_id == fileIdToRemove 131 | removedFile = file 132 | else 133 | _files.push file 134 | @files = _files 135 | @redraw() 136 | @checkMaximum() 137 | @$input.trigger 'attachinary:fileremoved', [removedFile] 138 | 139 | checkMaximum: -> 140 | if @maximumReached() 141 | @$wrapper.addClass 'disabled' if @$wrapper? 142 | @$input.prop('disabled', true) 143 | else 144 | @$wrapper.removeClass 'disabled' if @$wrapper? 145 | @$input.prop('disabled', false) 146 | 147 | maximumReached: -> 148 | @options.maximum && @files.length >= @options.maximum 149 | 150 | 151 | 152 | addFilesContainer: -> 153 | if @options.files_container_selector? and $(@options.files_container_selector).length > 0 154 | @$filesContainer = $(@options.files_container_selector) 155 | else 156 | @$filesContainer = $('
') 157 | @$input.after @$filesContainer 158 | 159 | redraw: -> 160 | @$filesContainer.empty() 161 | 162 | if @files.length > 0 163 | @$filesContainer.append @makeHiddenField(JSON.stringify(@files)) 164 | 165 | @$filesContainer.append @config.render(@files) 166 | @$filesContainer.find('[data-remove]').on 'click', (event) => 167 | event.preventDefault() 168 | @removeFile $(event.target).data('remove') 169 | 170 | @$filesContainer.show() 171 | else 172 | @$filesContainer.append @makeHiddenField(null) 173 | @$filesContainer.hide() 174 | 175 | makeHiddenField: (value) -> 176 | $input = $('') 177 | $input.attr 'name', @options.field_name 178 | $input.val value 179 | $input 180 | 181 | 182 | 183 | 184 | # JavaScript templating by John Resig's 185 | $.attachinary.Templating = 186 | settings: 187 | start: '<%' 188 | end: '%>' 189 | interpolate: /<%=(.+?)%>/g 190 | 191 | escapeRegExp: (string) -> 192 | string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1') 193 | 194 | template: (str, data) -> 195 | c = @settings 196 | endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+@escapeRegExp(c.end)+")","g") 197 | fn = new Function 'obj', 198 | 'var p=[],print=function(){p.push.apply(p,arguments);};' + 199 | 'with(obj||{}){p.push(\'' + 200 | str.replace(/\r/g, '\\r') 201 | .replace(/\n/g, '\\n') 202 | .replace(/\t/g, '\\t') 203 | .replace(endMatch,"✄") 204 | .split("'").join("\\'") 205 | .split("✄").join("'") 206 | .replace(c.interpolate, "',$1,'") 207 | .split(c.start).join("');") 208 | .split(c.end).join("p.push('") + 209 | "');}return p.join('');" 210 | if data then fn(data) else fn 211 | 212 | )(jQuery) 213 | -------------------------------------------------------------------------------- /lib/attachinary.rb: -------------------------------------------------------------------------------- 1 | require 'attachinary/engine' 2 | 3 | module Attachinary 4 | TMPTAG = "attachinary_tmp" 5 | 6 | end 7 | -------------------------------------------------------------------------------- /lib/attachinary/engine.rb: -------------------------------------------------------------------------------- 1 | require 'attachinary/view_helpers' 2 | require 'attachinary/form_builder' 3 | 4 | module Attachinary 5 | class Engine < ::Rails::Engine 6 | isolate_namespace Attachinary 7 | 8 | initializer "attachinary.include_view_helpers" do |app| 9 | ActiveSupport.on_load :action_view do 10 | include ViewHelpers 11 | end 12 | end 13 | 14 | initializer "attachinary.include_view_helpers" do |app| 15 | ActiveSupport.on_load :action_view do 16 | ActionView::Helpers::FormBuilder.send(:include, Attachinary::FormBuilder) 17 | end 18 | end 19 | 20 | initializer "attachinary.enable_simple_form" do |app| 21 | require "attachinary/simple_form" if defined?(::SimpleForm::Inputs::Base) 22 | end 23 | 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/attachinary/form_builder.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | module FormBuilder 3 | def attachinary_file_field(method, options={}) 4 | @template.builder_attachinary_file_field_tag method, self, options 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/attachinary/orm/active_record.rb: -------------------------------------------------------------------------------- 1 | require_relative 'file_mixin' 2 | require_relative 'base_extension' 3 | require_relative 'active_record/extension' 4 | require_relative 'active_record/file' 5 | 6 | ActiveRecord::Base.extend Attachinary::Extension 7 | -------------------------------------------------------------------------------- /lib/attachinary/orm/active_record/extension.rb: -------------------------------------------------------------------------------- 1 | require 'attachinary/utils' 2 | 3 | module Attachinary 4 | module Extension 5 | include Base 6 | 7 | def attachinary_orm_definition(options) 8 | relation = "#{options[:singular]}_files" 9 | 10 | # has_many :photo_files, ... 11 | # has_many :image_files, ... 12 | if Rails::VERSION::MAJOR == 3 13 | has_many :"#{relation}", 14 | as: :attachinariable, 15 | class_name: '::Attachinary::File', 16 | conditions: { scope: options[:scope].to_s }, 17 | dependent: :destroy 18 | else 19 | has_many :"#{relation}", 20 | -> { where scope: options[:scope].to_s }, 21 | as: :attachinariable, 22 | class_name: '::Attachinary::File', 23 | dependent: :destroy 24 | end 25 | 26 | 27 | # def photo=(file) 28 | # input = Attachinary::Utils.process_input(input, upload_options) 29 | # if input.blank? 30 | # photo_files.clear 31 | # else 32 | # files = [input].flatten 33 | # self.photo_files = files 34 | # end 35 | # end 36 | define_method "#{options[:scope]}=" do |input, upload_options = {}| 37 | input = Attachinary::Utils.process_input(input, upload_options, options[:scope]) 38 | if input.nil? 39 | send("#{relation}").clear 40 | else 41 | files = [input].flatten 42 | send("#{relation}=", files) 43 | end 44 | end 45 | 46 | 47 | if options[:single] 48 | # def photo 49 | # photo_files.first 50 | # end 51 | define_method "#{options[:scope]}" do 52 | send("#{relation}").first 53 | end 54 | 55 | else # plural 56 | # def images 57 | # image_files 58 | # end 59 | define_method "#{options[:scope]}" do 60 | send("#{relation}") 61 | end 62 | end 63 | 64 | end 65 | 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/attachinary/orm/active_record/file.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | class File < ::ActiveRecord::Base 3 | belongs_to :attachinariable, polymorphic: true 4 | include FileMixin 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/attachinary/orm/base_extension.rb: -------------------------------------------------------------------------------- 1 | require 'attachinary/utils' 2 | 3 | module Attachinary 4 | module Extension 5 | module Base 6 | 7 | def has_attachment(scope, options={}) 8 | attachinary options.merge(single: true, scope: scope) 9 | end 10 | 11 | def has_attachments(scope, options={}) 12 | attachinary options.merge(single: false, scope: scope) 13 | end 14 | 15 | private 16 | def attachinary(options) 17 | options = Attachinary::Utils.process_options(options) 18 | 19 | attachinary_orm_definition(options) 20 | 21 | # attr_accessible :photo 22 | # attr_accessible :images 23 | if Rails::VERSION::MAJOR == 3 24 | attr_accessible :"#{options[:scope]}" if options[:accessible] 25 | end 26 | 27 | # def photo? 28 | # photo.present? 29 | # end 30 | # def images? 31 | # images.present? 32 | # end 33 | define_method :"#{options[:scope]}?" do 34 | send(:"#{options[:scope]}").present? 35 | end 36 | 37 | # def photo_metadata 38 | # options 39 | # end 40 | define_method :"#{options[:scope]}_metadata" do 41 | options 42 | end 43 | 44 | if options[:single] 45 | # def photo_url=(url) 46 | # ... 47 | # end 48 | define_method :"#{options[:scope]}_url=" do |url, upload_options = {}| 49 | upload_options.merge! resource_type: 'auto' 50 | send(:"#{options[:scope]}=", Cloudinary::Uploader.upload(url, upload_options)) 51 | end 52 | 53 | else 54 | # def image_urls=(urls) 55 | # ... 56 | # end 57 | define_method :"#{options[:singular]}_urls=" do |urls, upload_options = {}| 58 | upload_options.merge! resource_type: 'auto' 59 | send(:"#{options[:scope]}=", urls.map { |url| Cloudinary::Uploader.upload(url, upload_options) }) 60 | end 61 | end 62 | 63 | end 64 | 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/attachinary/orm/file_mixin.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | module FileMixin 3 | def self.included(base) 4 | base.validates :public_id, :version, :resource_type, presence: true 5 | if Rails::VERSION::MAJOR == 3 6 | base.attr_accessible :public_id, :version, :width, :height, :format, :resource_type 7 | end 8 | base.after_destroy :destroy_file 9 | base.after_create :remove_temporary_tag 10 | end 11 | 12 | def as_json(options) 13 | super(only: [:id, :public_id, :format, :version, :resource_type], methods: [:path]) 14 | end 15 | 16 | def path(custom_format=nil) 17 | p = "v#{version}/#{public_id}" 18 | if resource_type == 'image' && custom_format != false 19 | custom_format ||= format 20 | p<< ".#{custom_format}" 21 | end 22 | p 23 | end 24 | 25 | def fullpath(options={}) 26 | format = options.delete(:format) 27 | Cloudinary::Utils.cloudinary_url(path(format), options.reverse_merge(:resource_type => resource_type)) 28 | end 29 | 30 | protected 31 | def keep_remote? 32 | Cloudinary.config.attachinary_keep_remote == true 33 | end 34 | 35 | private 36 | def destroy_file 37 | Cloudinary::Uploader.destroy(public_id) if public_id && !keep_remote? 38 | end 39 | 40 | def remove_temporary_tag 41 | Cloudinary::Uploader.remove_tag(Attachinary::TMPTAG, [public_id]) if public_id 42 | end 43 | 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/attachinary/orm/mongoid.rb: -------------------------------------------------------------------------------- 1 | require_relative 'file_mixin' 2 | require_relative 'base_extension' 3 | require_relative 'mongoid/extension' 4 | require_relative 'mongoid/file' 5 | 6 | Mongoid::Document::ClassMethods.send :include, Attachinary::Extension 7 | -------------------------------------------------------------------------------- /lib/attachinary/orm/mongoid/extension.rb: -------------------------------------------------------------------------------- 1 | require 'attachinary/utils' 2 | 3 | module Attachinary 4 | module Extension 5 | include Base 6 | 7 | def attachinary_orm_definition(options) 8 | if options[:single] 9 | # embeds_on :photo, ... 10 | embeds_one :"#{options[:scope]}", 11 | as: :attachinariable, 12 | class_name: '::Attachinary::File', 13 | cascade_callbacks: true 14 | else 15 | # embeds_many :images, ... 16 | embeds_many :"#{options[:scope]}", 17 | as: :attachinariable, 18 | class_name: '::Attachinary::File', 19 | cascade_callbacks: true 20 | end 21 | 22 | # alias_method "orig_photo=", "photo=" 23 | # def photo=(input) 24 | # input = Attachinary::Utils.process_input(input, upload_options) 25 | # if input.nil? 26 | # super(nil) 27 | # else 28 | # files = [input].flatten 29 | # super(options[:single] ? files[0] : files) 30 | # end 31 | # end 32 | alias_method "orig_#{options[:scope]}=", "#{options[:scope]}=" 33 | define_method "#{options[:scope]}=" do |input, upload_options = {}| 34 | input = Attachinary::Utils.process_input(input, upload_options) 35 | if !input.nil? 36 | input = [input].flatten 37 | input = (options[:single] ? input[0] : input) 38 | end 39 | send("orig_#{options[:scope]}=", input) 40 | end 41 | end 42 | 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/attachinary/orm/mongoid/file.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | class File 3 | include ::Mongoid::Document 4 | include ::Mongoid::Timestamps 5 | include FileMixin 6 | 7 | field :public_id, type: String 8 | field :version, type: String 9 | field :width, type: Integer 10 | field :height, type: Integer 11 | field :format, type: String 12 | field :resource_type, type: String 13 | 14 | embedded_in :attachinariable, polymorphic: true 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/attachinary/simple_form.rb: -------------------------------------------------------------------------------- 1 | class AttachinaryInput < SimpleForm::Inputs::Base 2 | attr_reader :attachinary_options 3 | 4 | def input(wrapper_options={}) 5 | template.builder_attachinary_file_field_tag attribute_name, @builder, { html: input_html_options } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/attachinary/utils.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | module Utils 3 | 4 | def self.process_json(json, scope=nil) 5 | [JSON.parse(json)].flatten.compact.map do |data| 6 | process_hash(data, scope) 7 | end 8 | end 9 | 10 | def self.process_hash(hash, scope=nil) 11 | if hash['id'] 12 | Attachinary::File.find hash['id'] 13 | else 14 | file = if Rails::VERSION::MAJOR == 3 15 | Attachinary::File.new hash.slice(*Attachinary::File.attr_accessible[:default].to_a) 16 | else 17 | hash.symbolize_keys! 18 | permitted_params = ActionController::Parameters.new(hash.slice(:public_id, :version, :width, :height, :format, :resource_type)).permit! 19 | Attachinary::File.new(permitted_params) 20 | end 21 | file.scope = scope.to_s if scope && file.respond_to?(:scope=) 22 | file 23 | end 24 | end 25 | 26 | 27 | def self.process_input(input, upload_options, scope=nil) 28 | case input 29 | when :blank?.to_proc 30 | nil 31 | when lambda { |e| e.respond_to?(:read) } 32 | upload_options.merge! resource_type: 'auto' 33 | upload_info = Cloudinary::Uploader.upload(input, upload_options) 34 | process_hash upload_info, scope 35 | when String 36 | process_json(input, scope) 37 | when Hash 38 | process_hash(input, scope) 39 | when Array 40 | input = input.map{ |el| process_input(el, upload_options, scope) }.flatten.compact 41 | input = nil if input.empty? 42 | input 43 | else 44 | input 45 | end 46 | end 47 | 48 | def self.process_options(options) 49 | options = options.reverse_merge({ 50 | accessible: true 51 | }) 52 | options[:maximum] = 1 if options[:single] 53 | 54 | if options[:single] 55 | options[:singular] = options[:scope].to_s 56 | options[:plural] = options[:scope].to_s.pluralize 57 | else 58 | options[:plural] = options[:scope].to_s 59 | options[:singular] = options[:scope].to_s.singularize 60 | end 61 | 62 | options 63 | end 64 | 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /lib/attachinary/version.rb: -------------------------------------------------------------------------------- 1 | module Attachinary 2 | VERSION = "1.3.1" 3 | end 4 | -------------------------------------------------------------------------------- /lib/attachinary/view_helpers.rb: -------------------------------------------------------------------------------- 1 | require 'mime/types' 2 | 3 | module Attachinary 4 | module ViewHelpers 5 | 6 | def builder_attachinary_file_field_tag(attr_name, builder, options={}) 7 | options = attachinary_file_field_options(builder.object, attr_name, options) 8 | builder.file_field(attr_name, options[:html]) 9 | end 10 | 11 | def attachinary_file_field_tag(field_name, model, relation, options={}) 12 | options = attachinary_file_field_options(model, relation, options) 13 | file_field_tag(field_name, options[:html]) 14 | end 15 | 16 | def attachinary_file_field_options(model, relation, options={}) 17 | options[:attachinary] = model.send("#{relation}_metadata") 18 | 19 | options[:cloudinary] ||= {} 20 | options[:cloudinary][:tags] ||= [] 21 | options[:cloudinary][:tags]<< "#{Rails.env}_env" 22 | options[:cloudinary][:tags]<< Attachinary::TMPTAG 23 | options[:cloudinary][:tags].uniq! 24 | 25 | cloudinary_upload_url = Cloudinary::Utils.cloudinary_api_url("upload", 26 | {:resource_type=>:auto}.merge(options[:cloudinary])) 27 | 28 | api_key = options[:cloudinary][:api_key] || Cloudinary.config.api_key || raise("Must supply api_key") 29 | api_secret = options[:cloudinary][:api_secret] || Cloudinary.config.api_secret || raise("Must supply api_secret") 30 | 31 | cloudinary_params = Cloudinary::Uploader.build_upload_params(options[:cloudinary]) 32 | cloudinary_params[:callback] = attachinary.cors_url 33 | cloudinary_params[:signature] = Cloudinary::Utils.api_sign_request(cloudinary_params, api_secret) 34 | cloudinary_params[:api_key] = api_key 35 | 36 | 37 | options[:html] ||= {} 38 | options[:html][:class] = [options[:html][:class], 'attachinary-input'].flatten.compact 39 | 40 | if !options[:html][:accept] && accepted_types = options[:attachinary][:accept] 41 | accept = accepted_types.map do |type| 42 | MIME::Types.type_for(type.to_s)[0] 43 | end.compact 44 | options[:html][:accept] = accept.join(',') unless accept.empty? 45 | end 46 | 47 | options[:html][:multiple] = true unless options[:attachinary][:single] 48 | 49 | options[:html][:data] ||= {} 50 | options[:html][:data][:attachinary] = options[:attachinary] || {} 51 | options[:html][:data][:attachinary][:files] = [model.send(relation)].compact.flatten 52 | 53 | options[:html][:data][:form_data] = cloudinary_params.reject{ |k, v| v.blank? } 54 | options[:html][:data][:url] = cloudinary_upload_url 55 | 56 | options 57 | end 58 | 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/tasks/attachinary.rake: -------------------------------------------------------------------------------- 1 | namespace :attachinary do 2 | 3 | desc 'fetches required jQuery File Upload files from github' 4 | task :fetch_fileupload do 5 | require 'open-uri' 6 | require 'uri' 7 | 8 | urls = %w[ 9 | https://raw.github.com/blueimp/jQuery-File-Upload/master/js/vendor/jquery.ui.widget.js 10 | https://raw.github.com/blueimp/jQuery-File-Upload/master/js/jquery.iframe-transport.js 11 | https://raw.github.com/blueimp/jQuery-File-Upload/master/js/jquery.fileupload.js 12 | ] 13 | 14 | dir = Rails.root.join("vendor/assets/javascripts") 15 | FileUtils.mkdir_p dir.to_s 16 | 17 | urls.each do |url| 18 | uri = URI.parse(url) 19 | filename = uri.path.split('/').last 20 | puts "Getting #{filename}" 21 | 22 | dest = File.open(dir.join(filename), "w") 23 | dest.puts open(url).read 24 | dest.close 25 | end 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | ENGINE_ROOT = File.expand_path('../..', __FILE__) 5 | ENGINE_PATH = File.expand_path('../../lib/attachinary/engine', __FILE__) 6 | 7 | require 'rails/all' 8 | require 'rails/engine/commands' 9 | -------------------------------------------------------------------------------- /spec/dummy/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 4 | gem 'rails', '~> 3.2' 5 | # Use sqlite3 as the database for Active Record 6 | gem 'sqlite3' 7 | # Use Uglifier as compressor for JavaScript assets 8 | gem 'uglifier', '>= 1.3.0' 9 | # Use CoffeeScript for .coffee assets and views 10 | gem 'coffee-rails' 11 | # Use jquery as the JavaScript library 12 | gem 'jquery-rails' 13 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 14 | gem 'jbuilder', '~> 2.0' 15 | 16 | # Use ActiveModel has_secure_password 17 | # gem 'bcrypt', '~> 3.1.7' 18 | 19 | # Use Unicorn as the app server 20 | # gem 'unicorn' 21 | 22 | # Use Capistrano for deployment 23 | # gem 'capistrano-rails', group: :development 24 | 25 | group :development, :test do 26 | 27 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 28 | gem 'spring' 29 | gem 'rspec-rails' 30 | gem 'ruby-debug-ide' 31 | gem 'valid_attribute' 32 | gem 'capybara' 33 | gem 'capybara-webkit' 34 | gem 'selenium-webdriver' 35 | gem 'factory_girl_rails' 36 | gem 'launchy' 37 | gem 'database_cleaner' 38 | gem 'rb-fsevent', '~> 0.9.1' 39 | gem 'guard-rspec' 40 | end 41 | 42 | gem 'mongoid' 43 | gem 'cloudinary', '~> 1.1' 44 | gem 'attachinary', :path => '../..' 45 | gem 'simple_form' 46 | 47 | -------------------------------------------------------------------------------- /spec/dummy/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../.. 3 | specs: 4 | attachinary (1.3.1) 5 | cloudinary (~> 1.1.0) 6 | rails (>= 3.2) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionmailer (3.2.22) 12 | actionpack (= 3.2.22) 13 | mail (~> 2.5.4) 14 | actionpack (3.2.22) 15 | activemodel (= 3.2.22) 16 | activesupport (= 3.2.22) 17 | builder (~> 3.0.0) 18 | erubis (~> 2.7.0) 19 | journey (~> 1.0.4) 20 | rack (~> 1.4.5) 21 | rack-cache (~> 1.2) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.2.1) 24 | activemodel (3.2.22) 25 | activesupport (= 3.2.22) 26 | builder (~> 3.0.0) 27 | activerecord (3.2.22) 28 | activemodel (= 3.2.22) 29 | activesupport (= 3.2.22) 30 | arel (~> 3.0.2) 31 | tzinfo (~> 0.3.29) 32 | activeresource (3.2.22) 33 | activemodel (= 3.2.22) 34 | activesupport (= 3.2.22) 35 | activesupport (3.2.22) 36 | i18n (~> 0.6, >= 0.6.4) 37 | multi_json (~> 1.0) 38 | addressable (2.3.8) 39 | arel (3.0.3) 40 | aws_cf_signer (0.1.3) 41 | builder (3.0.4) 42 | capybara (2.4.4) 43 | mime-types (>= 1.16) 44 | nokogiri (>= 1.3.3) 45 | rack (>= 1.0.0) 46 | rack-test (>= 0.5.4) 47 | xpath (~> 2.0) 48 | capybara-webkit (1.6.0) 49 | capybara (>= 2.3.0, < 2.5.0) 50 | json 51 | childprocess (0.5.6) 52 | ffi (~> 1.0, >= 1.0.11) 53 | cloudinary (1.1.0) 54 | aws_cf_signer 55 | rest-client 56 | coderay (1.1.0) 57 | coffee-rails (3.2.2) 58 | coffee-script (>= 2.2.0) 59 | railties (~> 3.2.0) 60 | coffee-script (2.4.1) 61 | coffee-script-source 62 | execjs 63 | coffee-script-source (1.9.1.1) 64 | database_cleaner (1.4.1) 65 | diff-lcs (1.2.5) 66 | domain_name (0.5.24) 67 | unf (>= 0.0.5, < 1.0.0) 68 | erubis (2.7.0) 69 | execjs (2.5.2) 70 | factory_girl (4.5.0) 71 | activesupport (>= 3.0.0) 72 | factory_girl_rails (4.5.0) 73 | factory_girl (~> 4.5.0) 74 | railties (>= 3.0.0) 75 | ffi (1.9.10) 76 | formatador (0.2.5) 77 | guard (2.12.9) 78 | formatador (>= 0.2.4) 79 | listen (>= 2.7, <= 4.0) 80 | lumberjack (~> 1.0) 81 | nenv (~> 0.1) 82 | notiffany (~> 0.0) 83 | pry (>= 0.9.12) 84 | shellany (~> 0.0) 85 | thor (>= 0.18.1) 86 | guard-compat (1.2.1) 87 | guard-rspec (4.6.3) 88 | guard (~> 2.1) 89 | guard-compat (~> 1.1) 90 | rspec (>= 2.99.0, < 4.0) 91 | hike (1.2.3) 92 | http-cookie (1.0.2) 93 | domain_name (~> 0.5) 94 | i18n (0.7.0) 95 | jbuilder (2.3.1) 96 | activesupport (>= 3.0.0, < 5) 97 | multi_json (~> 1.2) 98 | journey (1.0.4) 99 | jquery-rails (3.1.3) 100 | railties (>= 3.0, < 5.0) 101 | thor (>= 0.14, < 2.0) 102 | json (1.8.3) 103 | launchy (2.4.3) 104 | addressable (~> 2.3) 105 | listen (3.0.3) 106 | rb-fsevent (>= 0.9.3) 107 | rb-inotify (>= 0.9) 108 | lumberjack (1.0.9) 109 | mail (2.5.4) 110 | mime-types (~> 1.16) 111 | treetop (~> 1.4.8) 112 | method_source (0.8.2) 113 | mime-types (1.25.1) 114 | mini_portile (0.6.2) 115 | mongoid (3.1.7) 116 | activemodel (~> 3.2) 117 | moped (~> 1.4) 118 | origin (~> 1.0) 119 | tzinfo (~> 0.3.29) 120 | moped (1.5.2) 121 | multi_json (1.11.2) 122 | nenv (0.2.0) 123 | netrc (0.10.3) 124 | nokogiri (1.6.6.2) 125 | mini_portile (~> 0.6.0) 126 | notiffany (0.0.6) 127 | nenv (~> 0.1) 128 | shellany (~> 0.0) 129 | origin (1.1.0) 130 | polyglot (0.3.5) 131 | pry (0.10.1) 132 | coderay (~> 1.1.0) 133 | method_source (~> 0.8.1) 134 | slop (~> 3.4) 135 | rack (1.4.7) 136 | rack-cache (1.2) 137 | rack (>= 0.4) 138 | rack-ssl (1.3.4) 139 | rack 140 | rack-test (0.6.3) 141 | rack (>= 1.0) 142 | rails (3.2.22) 143 | actionmailer (= 3.2.22) 144 | actionpack (= 3.2.22) 145 | activerecord (= 3.2.22) 146 | activeresource (= 3.2.22) 147 | activesupport (= 3.2.22) 148 | bundler (~> 1.0) 149 | railties (= 3.2.22) 150 | railties (3.2.22) 151 | actionpack (= 3.2.22) 152 | activesupport (= 3.2.22) 153 | rack-ssl (~> 1.3.2) 154 | rake (>= 0.8.7) 155 | rdoc (~> 3.4) 156 | thor (>= 0.14.6, < 2.0) 157 | rake (10.4.2) 158 | rb-fsevent (0.9.5) 159 | rb-inotify (0.9.5) 160 | ffi (>= 0.5.0) 161 | rdoc (3.12.2) 162 | json (~> 1.4) 163 | rest-client (1.8.0) 164 | http-cookie (>= 1.0.2, < 2.0) 165 | mime-types (>= 1.16, < 3.0) 166 | netrc (~> 0.7) 167 | rspec (3.3.0) 168 | rspec-core (~> 3.3.0) 169 | rspec-expectations (~> 3.3.0) 170 | rspec-mocks (~> 3.3.0) 171 | rspec-core (3.3.2) 172 | rspec-support (~> 3.3.0) 173 | rspec-expectations (3.3.1) 174 | diff-lcs (>= 1.2.0, < 2.0) 175 | rspec-support (~> 3.3.0) 176 | rspec-mocks (3.3.2) 177 | diff-lcs (>= 1.2.0, < 2.0) 178 | rspec-support (~> 3.3.0) 179 | rspec-rails (3.3.3) 180 | actionpack (>= 3.0, < 4.3) 181 | activesupport (>= 3.0, < 4.3) 182 | railties (>= 3.0, < 4.3) 183 | rspec-core (~> 3.3.0) 184 | rspec-expectations (~> 3.3.0) 185 | rspec-mocks (~> 3.3.0) 186 | rspec-support (~> 3.3.0) 187 | rspec-support (3.3.0) 188 | ruby-debug-ide (0.4.32) 189 | rake (>= 0.8.1) 190 | rubyzip (1.1.7) 191 | selenium-webdriver (2.47.1) 192 | childprocess (~> 0.5) 193 | multi_json (~> 1.0) 194 | rubyzip (~> 1.0) 195 | websocket (~> 1.0) 196 | shellany (0.0.1) 197 | simple_form (2.1.2) 198 | actionpack (~> 3.0) 199 | activemodel (~> 3.0) 200 | slop (3.6.0) 201 | spring (1.3.6) 202 | sprockets (2.2.3) 203 | hike (~> 1.2) 204 | multi_json (~> 1.0) 205 | rack (~> 1.0) 206 | tilt (~> 1.1, != 1.3.0) 207 | sqlite3 (1.3.10) 208 | thor (0.19.1) 209 | tilt (1.4.1) 210 | treetop (1.4.15) 211 | polyglot 212 | polyglot (>= 0.3.1) 213 | tzinfo (0.3.44) 214 | uglifier (2.7.1) 215 | execjs (>= 0.3.0) 216 | json (>= 1.8.0) 217 | unf (0.1.4) 218 | unf_ext 219 | unf_ext (0.0.7.1) 220 | valid_attribute (2.0.0) 221 | websocket (1.2.2) 222 | xpath (2.0.0) 223 | nokogiri (~> 1.3) 224 | 225 | PLATFORMS 226 | ruby 227 | 228 | DEPENDENCIES 229 | attachinary! 230 | capybara 231 | capybara-webkit 232 | cloudinary (~> 1.1) 233 | coffee-rails 234 | database_cleaner 235 | factory_girl_rails 236 | guard-rspec 237 | jbuilder (~> 2.0) 238 | jquery-rails 239 | launchy 240 | mongoid 241 | rails (~> 3.2) 242 | rb-fsevent (~> 0.9.1) 243 | rspec-rails 244 | ruby-debug-ide 245 | selenium-webdriver 246 | simple_form 247 | spring 248 | sqlite3 249 | uglifier (>= 1.3.0) 250 | valid_attribute 251 | -------------------------------------------------------------------------------- /spec/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Dummy::Application.load_tasks 8 | -------------------------------------------------------------------------------- /spec/dummy/app/active_record/note.rb: -------------------------------------------------------------------------------- 1 | class Note < ActiveRecord::Base 2 | 3 | has_attachment :photo, accept: [:jpg, :png, :gif] 4 | has_attachments :images, accept: [:jpg, :png, :gif], maximum: 3 5 | 6 | validates :body, presence: true, length: { minimum: 4, maximum: 128 } 7 | validates :photo, presence: true 8 | 9 | attr_accessible :body if Rails::VERSION::MAJOR == 3 10 | 11 | 12 | end 13 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= 16 | //= require jquery.ui.widget 17 | //= require jquery.iframe-transport 18 | //= require jquery.fileupload 19 | //= require cloudinary/jquery.cloudinary 20 | //= require attachinary 21 | //= 22 | //= require_tree . 23 | 24 | jQuery(function() { 25 | 26 | $('.attachinary-input').attachinary(); 27 | 28 | }) 29 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | 15 | form.uploading { 16 | background-color: #ccc; 17 | } 18 | 19 | input.uploading { 20 | background-color: #999; 21 | } 22 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/notes_controller.rb: -------------------------------------------------------------------------------- 1 | class NotesController < ApplicationController 2 | 3 | def index 4 | if Rails::VERSION::MAJOR == 3 5 | @notes = Note.all 6 | else 7 | @notes = Note.all.to_a 8 | end 9 | end 10 | 11 | def new 12 | @note = Note.new 13 | end 14 | 15 | def create 16 | @note = Note.new note_params 17 | if @note.save 18 | redirect_to notes_url 19 | else 20 | render 'new' 21 | end 22 | end 23 | 24 | def edit 25 | @note = Note.find params[:id] 26 | end 27 | 28 | def update 29 | @note = Note.find params[:id] 30 | if @note.update_attributes(note_params) 31 | redirect_to notes_url 32 | else 33 | render 'edit' 34 | end 35 | end 36 | 37 | def destroy 38 | @note = Note.find params[:id] 39 | @note.destroy 40 | redirect_to :back 41 | end 42 | 43 | private 44 | 45 | def note_params 46 | if Rails::VERSION::MAJOR == 3 47 | params[:note].slice(:body, :photo) 48 | else 49 | params.require(:note).permit( 50 | :body, 51 | :photo, 52 | ) 53 | end 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /spec/dummy/app/mongoid/note.rb: -------------------------------------------------------------------------------- 1 | class Note 2 | include Mongoid::Document 3 | include Mongoid::Timestamps 4 | field :body, type: String 5 | 6 | has_attachment :photo, accept: [:jpg, :png, :gif] 7 | has_attachments :images, accept: [:jpg, :png, :gif], maximum: 3 8 | 9 | validates :body, presence: true, length: { minimum: 5, maximum: 128 } 10 | validates :photo, presence: true 11 | 12 | attr_accessible :body 13 | end 14 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= stylesheet_link_tag "application", :media => "all" %> 6 | <%= javascript_include_tag "application" %> 7 | <%= cloudinary_js_config %> 8 | <%= csrf_meta_tags %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/_form_builder.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for note, html: { multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.label 'Body' %> 6 |
7 | 8 | <%= f.text_field :body %> 9 |
<%= note.errors[:body].first %>
10 |
11 | 12 |
13 | <%= f.attachinary_file_field :photo %> 14 |
<%= note.errors[:photo].first %>
15 |
16 | 17 |
18 | 19 |
20 | <%= f.attachinary_file_field :images %> 21 |
<%= note.errors[:image].first %>
22 |
23 | 24 |
25 |
26 | 27 | <%= f.submit %> 28 | <% end %> 29 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/_form_nojs.html.erb: -------------------------------------------------------------------------------- 1 | <%= simple_form_for note, html: { novalidate: true, multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.input :body, as: :string %> 6 | 7 |
8 | <%= f.input :photo, as: :file %> 9 |
10 | 11 |
12 | <%= f.input :images, as: :file, input_html: { multiple: true } %> 13 |
14 | 15 | <%= f.submit %> 16 | 17 | <% end %> 18 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/_form_raw.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for note, html: { multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.label 'Body' %> 6 |
7 | 8 | <%= f.text_field :body %> 9 |
<%= note.errors[:body].first %>
10 |
11 | 12 |
13 | <%= attachinary_file_field_tag 'note[photo]', note, :photo %> 14 |
<%= note.errors[:photo].first %>
15 |
16 | 17 |
18 | 19 |
20 | <%= attachinary_file_field_tag 'note[images][]', note, :images %> 21 |
<%= note.errors[:image].first %>
22 |
23 | 24 |
25 |
26 | 27 | <%= f.submit %> 28 | <% end %> 29 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/_form_simple_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= simple_form_for note, html: { novalidate: true, multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.input :body, as: :string %> 6 | 7 |
8 | <%= f.input :photo, as: :attachinary %> 9 |
10 | 11 |
12 | <%= f.input :images, as: :attachinary %> 13 |
14 | 15 | <%= f.submit %> 16 | 17 | <% end %> 18 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/_note.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <% if note.photo? %> 3 | <%= cl_image_tag note.photo.path, 4 | size: '120x120', crop: :fill, html_width: nil, html_height: nil %>
5 | 6 | <% note.images.each do |image| %> 7 | <%= cl_image_tag image.path, size: '37x37', crop: :fill, html_width: nil, html_height: nil %> 8 | <% end %> 9 | <% end %>
10 | <%= note.body %>
11 | <%= link_to 'edit (raw)', edit_note_path(note, kind: 'raw') %>
12 | <%= link_to 'edit (builder)', edit_note_path(note, kind: 'builder') %>
13 | <%= link_to 'edit (simple form)', edit_note_path(note, kind: 'simple_form') %>
14 | <%= link_to 'delete', note_path(note), method: :delete %> 15 |
16 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= render "form_#{params[:kind]}", note: @note %> 2 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/index.html.erb: -------------------------------------------------------------------------------- 1 |

Notes

2 |

<%= ATTACHINARY_ORM %>

3 | 4 |
5 | <%= render @notes %> 6 |
7 | 8 |
9 |
10 | <%= link_to 'create (raw)', new_note_path(kind: 'raw') %>
11 | <%= link_to 'create (builder)', new_note_path(kind: 'builder') %>
12 | <%= link_to 'create (simple form)', new_note_path(kind: 'simple_form') %>
13 | <%= link_to 'create (no javascript)', new_note_path(kind: 'nojs') %>
14 | -------------------------------------------------------------------------------- /spec/dummy/app/views/notes/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= render "form_#{params[:kind]}", note: @note %> 2 | -------------------------------------------------------------------------------- /spec/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Dummy::Application 5 | -------------------------------------------------------------------------------- /spec/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require :default, ATTACHINARY_ORM 6 | 7 | begin 8 | require "#{ATTACHINARY_ORM}/railtie" 9 | rescue LoadError 10 | end 11 | 12 | require "attachinary" 13 | 14 | module Dummy 15 | class Application < Rails::Application 16 | # Settings in config/environments/* take precedence over those specified here. 17 | # Application configuration should go into files in config/initializers 18 | # -- all .rb files in that directory are automatically loaded. 19 | 20 | # Custom directories with classes and modules you want to be autoloadable. 21 | # config.autoload_paths += %W(#{config.root}/extras) 22 | config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers views).include?($1) } 23 | config.autoload_paths += [ "#{config.root}/app/#{ATTACHINARY_ORM}" ] 24 | 25 | # Only load the plugins named here, in the order given (default is alphabetical). 26 | # :all can be used as a placeholder for all plugins not explicitly named. 27 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 28 | 29 | # Activate observers that should always be running. 30 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 31 | 32 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 33 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 34 | # config.time_zone = 'Central Time (US & Canada)' 35 | 36 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 37 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 38 | # config.i18n.default_locale = :de 39 | 40 | # Configure the default encoding used in templates for Ruby 1.9. 41 | config.encoding = "utf-8" 42 | 43 | config.eager_load = true 44 | 45 | # Configure sensitive parameters which will be filtered from the log file. 46 | config.filter_parameters += [:password] 47 | 48 | # Enable escaping HTML in JSON. 49 | config.active_support.escape_html_entities_in_json = true 50 | 51 | # Use SQL instead of Active Record's schema dumper when creating the database. 52 | # This is necessary if your schema can't be completely dumped by the schema dumper, 53 | # like if you have constraints or database-specific column types 54 | # config.active_record.schema_format = :sql 55 | 56 | if Rails::VERSION::MAJOR == 3 57 | config.active_record.whitelist_attributes = true 58 | end 59 | 60 | # Enable the asset pipeline 61 | config.assets.enabled = true 62 | 63 | # Version of your assets, change this if you want to expire all your assets 64 | config.assets.version = '1.0' 65 | 66 | config.secret_key_base = 'xxx' 67 | 68 | I18n.enforce_available_locales = false 69 | end 70 | end 71 | 72 | -------------------------------------------------------------------------------- /spec/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | unless defined?(ATTACHINARY_ORM) 2 | ATTACHINARY_ORM = (ENV["ATTACHINARY_ORM"] || :active_record).to_sym 3 | end 4 | 5 | require 'rubygems' 6 | # Set up gems listed in the Gemfile. 7 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 8 | 9 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 10 | -------------------------------------------------------------------------------- /spec/dummy/config/cloudinary.yml.example: -------------------------------------------------------------------------------- 1 | default: &default 2 | enhance_image_tag: true 3 | static_image_support: true 4 | cdn_subdomain: true 5 | secure_distribution: false 6 | private_cdn: false 7 | cloud_name: zogash 8 | api_key: 'xxx' 9 | api_secret: xxx 10 | 11 | development: 12 | <<: *default 13 | 14 | test: 15 | <<: *default 16 | -------------------------------------------------------------------------------- /spec/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: sqlite3 17 | database: db/test.sqlite3 18 | pool: 5 19 | timeout: 5000 20 | 21 | production: 22 | adapter: sqlite3 23 | database: db/production.sqlite3 24 | pool: 5 25 | timeout: 5000 26 | -------------------------------------------------------------------------------- /spec/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Dummy::Application.initialize! 6 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Show full error reports and disable caching 10 | config.consider_all_requests_local = true 11 | config.action_controller.perform_caching = false 12 | 13 | # Don't care if the mailer can't send 14 | config.action_mailer.raise_delivery_errors = false 15 | 16 | # Print deprecation notices to the Rails logger 17 | config.active_support.deprecation = :log 18 | 19 | # Only use best-standards-support built into browsers 20 | config.action_dispatch.best_standards_support = :builtin 21 | 22 | if Rails::VERSION::MAJOR == 3 23 | config.active_record.mass_assignment_sanitizer = :strict 24 | end 25 | 26 | # Do not compress assets 27 | config.assets.compress = false 28 | 29 | # Expands the lines which load the assets 30 | config.assets.debug = true 31 | 32 | config.eager_load = false 33 | end 34 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | 51 | # Disable delivery errors, bad email addresses will be ignored 52 | # config.action_mailer.raise_delivery_errors = false 53 | 54 | # Enable threaded mode 55 | # config.threadsafe! 56 | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 58 | # the I18n.default_locale when a translation can not be found) 59 | config.i18n.fallbacks = true 60 | 61 | # Send deprecation notices to registered listeners 62 | config.active_support.deprecation = :notify 63 | end 64 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Show full error reports and disable caching 15 | config.consider_all_requests_local = true 16 | config.action_controller.perform_caching = false 17 | 18 | # Raise exceptions instead of rendering exception templates 19 | config.action_dispatch.show_exceptions = false 20 | 21 | # Disable request forgery protection in test environment 22 | config.action_controller.allow_forgery_protection = false 23 | 24 | # Tell Action Mailer not to deliver emails to the real world. 25 | # The :test delivery method accumulates sent emails in the 26 | # ActionMailer::Base.deliveries array. 27 | config.action_mailer.delivery_method = :test 28 | 29 | if Rails::VERSION::MAJOR == 3 30 | config.active_record.mass_assignment_sanitizer = :strict 31 | end 32 | 33 | # Print deprecation notices to the stderr 34 | config.active_support.deprecation = :stderr 35 | 36 | config.eager_load = false 37 | end 38 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/attachinary.rb: -------------------------------------------------------------------------------- 1 | require "attachinary/orm/#{ATTACHINARY_ORM}" 2 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | Dummy::Application.config.secret_token = 'f183aecf8ec1f4324366308b34353d5e40beaca43b38dd65b122cdced57debe3e611d14aa40d6c654ce9c5311f31aee580d5b1f39debaad9430e09aafb1ec8c5' 8 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # Dummy::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /spec/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /spec/dummy/config/mongoid.yml: -------------------------------------------------------------------------------- 1 | development: 2 | # Configure available database sessions. (required) 3 | sessions: 4 | # Defines the default session. (required) 5 | default: 6 | # Defines the name of the default database that Mongoid can connect to. 7 | # (required). 8 | database: attachinary_development 9 | # Provides the hosts the default session can connect to. Must be an array 10 | # of host:port pairs. (required) 11 | hosts: 12 | - localhost:27017 13 | options: 14 | # Change whether the session persists in safe mode by default. 15 | # (default: false) 16 | # safe: false 17 | 18 | # Change the default consistency model to :eventual or :strong. 19 | # :eventual will send reads to secondaries, :strong sends everything 20 | # to master. (default: :eventual) 21 | consistency: :strong 22 | # Configure Mongoid specific options. (optional) 23 | options: 24 | # Configuration for whether or not to allow access to fields that do 25 | # not have a field definition on the model. (default: true) 26 | # allow_dynamic_fields: true 27 | 28 | # Enable the identity map, needed for eager loading. (default: false) 29 | # identity_map_enabled: false 30 | 31 | # Includes the root model name in json serialization. (default: false) 32 | # include_root_in_json: false 33 | 34 | # Include the _type field in serializaion. (default: false) 35 | # include_type_for_serialization: false 36 | 37 | # Preload all models in development, needed when models use 38 | # inheritance. (default: false) 39 | # preload_models: false 40 | 41 | # Protect id and type from mass assignment. (default: true) 42 | # protect_sensitive_fields: true 43 | 44 | # Raise an error when performing a #find and the document is not found. 45 | # (default: true) 46 | # raise_not_found_error: true 47 | 48 | # Raise an error when defining a scope with the same name as an 49 | # existing method. (default: false) 50 | # scope_overwrite_exception: false 51 | 52 | # Skip the database version check, used when connecting to a db without 53 | # admin access. (default: false) 54 | # skip_version_check: false 55 | 56 | # User Active Support's time zone in conversions. (default: true) 57 | # use_activesupport_time_zone: true 58 | 59 | # Ensure all times are UTC in the app side. (default: false) 60 | # use_utc: false 61 | test: 62 | sessions: 63 | default: 64 | database: attachinary_test 65 | hosts: 66 | - localhost:27017 67 | options: 68 | consistency: :strong 69 | -------------------------------------------------------------------------------- /spec/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | mount Attachinary::Engine => "/attachinary" 3 | resources :notes 4 | root to: 'notes#index' 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20120608091037_create_tables.rb: -------------------------------------------------------------------------------- 1 | class CreateTables < ActiveRecord::Migration 2 | def change 3 | create_table :attachinary_files do |t| 4 | t.references :attachinariable, polymorphic: true 5 | t.string :scope 6 | 7 | t.string :public_id 8 | t.string :version 9 | t.integer :width 10 | t.integer :height 11 | t.string :format 12 | t.string :resource_type 13 | t.timestamps 14 | end 15 | add_index :attachinary_files, [:attachinariable_type, :attachinariable_id, :scope], name: 'by_scoped_parent' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20120608104143_create_notes.rb: -------------------------------------------------------------------------------- 1 | class CreateNotes < ActiveRecord::Migration 2 | def change 3 | create_table :notes do |t| 4 | t.text :body 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20120608104143) do 15 | 16 | create_table "attachinary_files", :force => true do |t| 17 | t.integer "attachinariable_id" 18 | t.string "attachinariable_type" 19 | t.string "scope" 20 | t.string "public_id" 21 | t.string "version" 22 | t.integer "width" 23 | t.integer "height" 24 | t.string "format" 25 | t.string "resource_type" 26 | t.datetime "created_at", :null => false 27 | t.datetime "updated_at", :null => false 28 | end 29 | 30 | add_index "attachinary_files", ["attachinariable_type", "attachinariable_id", "scope"], :name => "by_scoped_parent" 31 | 32 | create_table "notes", :force => true do |t| 33 | t.text "body" 34 | t.datetime "created_at", :null => false 35 | t.datetime "updated_at", :null => false 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /spec/dummy/lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy/lib/assets/.gitkeep -------------------------------------------------------------------------------- /spec/dummy/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy/log/.gitkeep -------------------------------------------------------------------------------- /spec/dummy/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy/public/.gitkeep -------------------------------------------------------------------------------- /spec/dummy/script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /spec/dummy/spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV['RAILS_ENV'] ||= 'test' 3 | require File.expand_path("../../config/environment", __FILE__) 4 | # Prevent database truncation if the environment is production 5 | abort("The Rails environment is running in production mode!") if Rails.env.production? 6 | require 'spec_helper' 7 | require 'rspec/rails' 8 | # Add additional requires below this line. Rails is not loaded until this point! 9 | require '../spec_helper.rb' 10 | # Requires supporting ruby files with custom matchers and macros, etc, in 11 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 12 | # run as spec files by default. This means that files in spec/support that end 13 | # in _spec.rb will both be required and run as specs, causing the specs to be 14 | # run twice. It is recommended that you do not name files matching this glob to 15 | # end with _spec.rb. You can configure this pattern with the --pattern 16 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 17 | # 18 | # The following line is provided for convenience purposes. It has the downside 19 | # of increasing the boot-up time by auto-requiring all files in the support 20 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 21 | # require only the support files necessary. 22 | # 23 | # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 24 | 25 | RSpec.configure do |config| 26 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 27 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 28 | 29 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 30 | # examples within a transaction, remove the following line or assign false 31 | # instead of true. 32 | config.use_transactional_fixtures = true 33 | 34 | # RSpec Rails can automatically mix in different behaviours to your tests 35 | # based on their file location, for example enabling you to call `get` and 36 | # `post` in specs under `spec/controllers`. 37 | # 38 | # You can disable this behaviour by removing the line below, and instead 39 | # explicitly tag your specs with their type, e.g.: 40 | # 41 | # RSpec.describe UsersController, :type => :controller do 42 | # # ... 43 | # end 44 | # 45 | # The different available types are documented in the features, such as in 46 | # https://relishapp.com/rspec/rspec-rails/docs 47 | config.infer_spec_type_from_file_location! 48 | end 49 | -------------------------------------------------------------------------------- /spec/dummy/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # The `.rspec` file also contains a few flags that are not defaults but that 16 | # users commonly want. 17 | # 18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 19 | RSpec.configure do |config| 20 | # rspec-expectations config goes here. You can use an alternate 21 | # assertion/expectation library such as wrong or the stdlib/minitest 22 | # assertions if you prefer. 23 | config.expect_with :rspec do |expectations| 24 | # This option will default to `true` in RSpec 4. It makes the `description` 25 | # and `failure_message` of custom matchers include text for helper methods 26 | # defined using `chain`, e.g.: 27 | # be_bigger_than(2).and_smaller_than(4).description 28 | # # => "be bigger than 2 and smaller than 4" 29 | # ...rather than: 30 | # # => "be bigger than 2" 31 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 32 | end 33 | 34 | # rspec-mocks config goes here. You can use an alternate test double 35 | # library (such as bogus or mocha) by changing the `mock_with` option here. 36 | config.mock_with :rspec do |mocks| 37 | # Prevents you from mocking or stubbing a method that does not exist on 38 | # a real object. This is generally recommended, and will default to 39 | # `true` in RSpec 4. 40 | mocks.verify_partial_doubles = true 41 | end 42 | 43 | # The settings below are suggested to provide a good initial experience 44 | # with RSpec, but feel free to customize to your heart's content. 45 | =begin 46 | # These two settings work together to allow you to limit a spec run 47 | # to individual examples or groups you care about by tagging them with 48 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 49 | # get run. 50 | config.filter_run :focus 51 | config.run_all_when_everything_filtered = true 52 | 53 | # Allows RSpec to persist some state between runs in order to support 54 | # the `--only-failures` and `--next-failure` CLI options. We recommend 55 | # you configure your source control system to ignore this file. 56 | config.example_status_persistence_file_path = "spec/examples.txt" 57 | 58 | # Limits the available syntax to the non-monkey patched syntax that is 59 | # recommended. For more details, see: 60 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 61 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 62 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 63 | config.disable_monkey_patching! 64 | 65 | # Many RSpec users commonly either run the entire suite or an individual 66 | # file, and it's useful to allow more verbose output when running an 67 | # individual spec file. 68 | if config.files_to_run.one? 69 | # Use the documentation formatter for detailed output, 70 | # unless a formatter has already been configured 71 | # (e.g. via a command-line flag). 72 | config.default_formatter = 'doc' 73 | end 74 | 75 | # Print the 10 slowest examples and example groups at the 76 | # end of the spec run, to help surface which specs are running 77 | # particularly slow. 78 | config.profile_examples = 10 79 | 80 | # Run specs in random order to surface order dependencies. If you find an 81 | # order dependency and want to debug it, you can fix the order by providing 82 | # the seed, which is printed after each run. 83 | # --seed 1234 84 | config.order = :random 85 | 86 | # Seed global randomization in this process using the `--seed` CLI option. 87 | # Setting this allows you to use `--seed` to deterministically reproduce 88 | # test failures related to randomization by passing the same `--seed` value 89 | # as the one that triggered the failure. 90 | Kernel.srand config.seed 91 | =end 92 | end 93 | -------------------------------------------------------------------------------- /spec/dummy/vendor/assets/javascripts/jquery.iframe-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Iframe Transport Plugin 1.5 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * http://www.opensource.org/licenses/MIT 10 | */ 11 | 12 | /*jslint unparam: true, nomen: true */ 13 | /*global define, window, document */ 14 | 15 | (function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define(['jquery'], factory); 20 | } else { 21 | // Browser globals: 22 | factory(window.jQuery); 23 | } 24 | }(function ($) { 25 | 'use strict'; 26 | 27 | // Helper variable to create unique names for the transport iframes: 28 | var counter = 0; 29 | 30 | // The iframe transport accepts three additional options: 31 | // options.fileInput: a jQuery collection of file input fields 32 | // options.paramName: the parameter name for the file form data, 33 | // overrides the name property of the file input field(s), 34 | // can be a string or an array of strings. 35 | // options.formData: an array of objects with name and value properties, 36 | // equivalent to the return data of .serializeArray(), e.g.: 37 | // [{name: 'a', value: 1}, {name: 'b', value: 2}] 38 | $.ajaxTransport('iframe', function (options) { 39 | if (options.async && (options.type === 'POST' || options.type === 'GET')) { 40 | var form, 41 | iframe; 42 | return { 43 | send: function (_, completeCallback) { 44 | form = $('
'); 45 | form.attr('accept-charset', options.formAcceptCharset); 46 | // javascript:false as initial iframe src 47 | // prevents warning popups on HTTPS in IE6. 48 | // IE versions below IE8 cannot set the name property of 49 | // elements that have already been added to the DOM, 50 | // so we set the name along with the iframe HTML markup: 51 | iframe = $( 52 | '' 54 | ).bind('load', function () { 55 | var fileInputClones, 56 | paramNames = $.isArray(options.paramName) ? 57 | options.paramName : [options.paramName]; 58 | iframe 59 | .unbind('load') 60 | .bind('load', function () { 61 | var response; 62 | // Wrap in a try/catch block to catch exceptions thrown 63 | // when trying to access cross-domain iframe contents: 64 | try { 65 | response = iframe.contents(); 66 | // Google Chrome and Firefox do not throw an 67 | // exception when calling iframe.contents() on 68 | // cross-domain requests, so we unify the response: 69 | if (!response.length || !response[0].firstChild) { 70 | throw new Error(); 71 | } 72 | } catch (e) { 73 | response = undefined; 74 | } 75 | // The complete callback returns the 76 | // iframe content document as response object: 77 | completeCallback( 78 | 200, 79 | 'success', 80 | {'iframe': response} 81 | ); 82 | // Fix for IE endless progress bar activity bug 83 | // (happens on form submits to iframe targets): 84 | $('') 85 | .appendTo(form); 86 | form.remove(); 87 | }); 88 | form 89 | .prop('target', iframe.prop('name')) 90 | .prop('action', options.url) 91 | .prop('method', options.type); 92 | if (options.formData) { 93 | $.each(options.formData, function (index, field) { 94 | $('') 95 | .prop('name', field.name) 96 | .val(field.value) 97 | .appendTo(form); 98 | }); 99 | } 100 | if (options.fileInput && options.fileInput.length && 101 | options.type === 'POST') { 102 | fileInputClones = options.fileInput.clone(); 103 | // Insert a clone for each file input field: 104 | options.fileInput.after(function (index) { 105 | return fileInputClones[index]; 106 | }); 107 | if (options.paramName) { 108 | options.fileInput.each(function (index) { 109 | $(this).prop( 110 | 'name', 111 | paramNames[index] || options.paramName 112 | ); 113 | }); 114 | } 115 | // Appending the file input fields to the hidden form 116 | // removes them from their original location: 117 | form 118 | .append(options.fileInput) 119 | .prop('enctype', 'multipart/form-data') 120 | // enctype must be set as encoding for IE: 121 | .prop('encoding', 'multipart/form-data'); 122 | } 123 | form.submit(); 124 | // Insert the file input fields at their original location 125 | // by replacing the clones with the originals: 126 | if (fileInputClones && fileInputClones.length) { 127 | options.fileInput.each(function (index, input) { 128 | var clone = $(fileInputClones[index]); 129 | $(input).prop('name', clone.prop('name')); 130 | clone.replaceWith(input); 131 | }); 132 | } 133 | }); 134 | form.append(iframe).appendTo(document.body); 135 | }, 136 | abort: function () { 137 | if (iframe) { 138 | // javascript:false as iframe src aborts the request 139 | // and prevents warning popups on HTTPS in IE6. 140 | // concat is used to avoid the "Script URL" JSLint error: 141 | iframe 142 | .unbind('load') 143 | .prop('src', 'javascript'.concat(':false;')); 144 | } 145 | if (form) { 146 | form.remove(); 147 | } 148 | } 149 | }; 150 | } 151 | }); 152 | 153 | // The iframe transport returns the iframe content document as response. 154 | // The following adds converters from iframe to text, json, html, and script: 155 | $.ajaxSetup({ 156 | converters: { 157 | 'iframe text': function (iframe) { 158 | return $(iframe[0].body).text(); 159 | }, 160 | 'iframe json': function (iframe) { 161 | return $.parseJSON($(iframe[0].body).text()); 162 | }, 163 | 'iframe html': function (iframe) { 164 | return $(iframe[0].body).html(); 165 | }, 166 | 'iframe script': function (iframe) { 167 | return $.globalEval($(iframe[0].body).text()); 168 | } 169 | } 170 | }); 171 | 172 | })); 173 | -------------------------------------------------------------------------------- /spec/dummy/vendor/assets/javascripts/jquery.ui.widget.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Widget 1.9.1+amd 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2012 jQuery Foundation and other contributors 6 | * Released under the MIT license. 7 | * http://jquery.org/license 8 | * 9 | * http://api.jqueryui.com/jQuery.widget/ 10 | */ 11 | 12 | (function (factory) { 13 | if (typeof define === "function" && define.amd) { 14 | // Register as an anonymous AMD module: 15 | define(["jquery"], factory); 16 | } else { 17 | // Browser globals: 18 | factory(jQuery); 19 | } 20 | }(function( $, undefined ) { 21 | 22 | var uuid = 0, 23 | slice = Array.prototype.slice, 24 | _cleanData = $.cleanData; 25 | $.cleanData = function( elems ) { 26 | for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { 27 | try { 28 | $( elem ).triggerHandler( "remove" ); 29 | // http://bugs.jquery.com/ticket/8235 30 | } catch( e ) {} 31 | } 32 | _cleanData( elems ); 33 | }; 34 | 35 | $.widget = function( name, base, prototype ) { 36 | var fullName, existingConstructor, constructor, basePrototype, 37 | namespace = name.split( "." )[ 0 ]; 38 | 39 | name = name.split( "." )[ 1 ]; 40 | fullName = namespace + "-" + name; 41 | 42 | if ( !prototype ) { 43 | prototype = base; 44 | base = $.Widget; 45 | } 46 | 47 | // create selector for plugin 48 | $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 49 | return !!$.data( elem, fullName ); 50 | }; 51 | 52 | $[ namespace ] = $[ namespace ] || {}; 53 | existingConstructor = $[ namespace ][ name ]; 54 | constructor = $[ namespace ][ name ] = function( options, element ) { 55 | // allow instantiation without "new" keyword 56 | if ( !this._createWidget ) { 57 | return new constructor( options, element ); 58 | } 59 | 60 | // allow instantiation without initializing for simple inheritance 61 | // must use "new" keyword (the code above always passes args) 62 | if ( arguments.length ) { 63 | this._createWidget( options, element ); 64 | } 65 | }; 66 | // extend with the existing constructor to carry over any static properties 67 | $.extend( constructor, existingConstructor, { 68 | version: prototype.version, 69 | // copy the object used to create the prototype in case we need to 70 | // redefine the widget later 71 | _proto: $.extend( {}, prototype ), 72 | // track widgets that inherit from this widget in case this widget is 73 | // redefined after a widget inherits from it 74 | _childConstructors: [] 75 | }); 76 | 77 | basePrototype = new base(); 78 | // we need to make the options hash a property directly on the new instance 79 | // otherwise we'll modify the options hash on the prototype that we're 80 | // inheriting from 81 | basePrototype.options = $.widget.extend( {}, basePrototype.options ); 82 | $.each( prototype, function( prop, value ) { 83 | if ( $.isFunction( value ) ) { 84 | prototype[ prop ] = (function() { 85 | var _super = function() { 86 | return base.prototype[ prop ].apply( this, arguments ); 87 | }, 88 | _superApply = function( args ) { 89 | return base.prototype[ prop ].apply( this, args ); 90 | }; 91 | return function() { 92 | var __super = this._super, 93 | __superApply = this._superApply, 94 | returnValue; 95 | 96 | this._super = _super; 97 | this._superApply = _superApply; 98 | 99 | returnValue = value.apply( this, arguments ); 100 | 101 | this._super = __super; 102 | this._superApply = __superApply; 103 | 104 | return returnValue; 105 | }; 106 | })(); 107 | } 108 | }); 109 | constructor.prototype = $.widget.extend( basePrototype, { 110 | // TODO: remove support for widgetEventPrefix 111 | // always use the name + a colon as the prefix, e.g., draggable:start 112 | // don't prefix for widgets that aren't DOM-based 113 | widgetEventPrefix: basePrototype.widgetEventPrefix || name 114 | }, prototype, { 115 | constructor: constructor, 116 | namespace: namespace, 117 | widgetName: name, 118 | // TODO remove widgetBaseClass, see #8155 119 | widgetBaseClass: fullName, 120 | widgetFullName: fullName 121 | }); 122 | 123 | // If this widget is being redefined then we need to find all widgets that 124 | // are inheriting from it and redefine all of them so that they inherit from 125 | // the new version of this widget. We're essentially trying to replace one 126 | // level in the prototype chain. 127 | if ( existingConstructor ) { 128 | $.each( existingConstructor._childConstructors, function( i, child ) { 129 | var childPrototype = child.prototype; 130 | 131 | // redefine the child widget using the same prototype that was 132 | // originally used, but inherit from the new version of the base 133 | $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); 134 | }); 135 | // remove the list of existing child constructors from the old constructor 136 | // so the old child constructors can be garbage collected 137 | delete existingConstructor._childConstructors; 138 | } else { 139 | base._childConstructors.push( constructor ); 140 | } 141 | 142 | $.widget.bridge( name, constructor ); 143 | }; 144 | 145 | $.widget.extend = function( target ) { 146 | var input = slice.call( arguments, 1 ), 147 | inputIndex = 0, 148 | inputLength = input.length, 149 | key, 150 | value; 151 | for ( ; inputIndex < inputLength; inputIndex++ ) { 152 | for ( key in input[ inputIndex ] ) { 153 | value = input[ inputIndex ][ key ]; 154 | if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 155 | // Clone objects 156 | if ( $.isPlainObject( value ) ) { 157 | target[ key ] = $.isPlainObject( target[ key ] ) ? 158 | $.widget.extend( {}, target[ key ], value ) : 159 | // Don't extend strings, arrays, etc. with objects 160 | $.widget.extend( {}, value ); 161 | // Copy everything else by reference 162 | } else { 163 | target[ key ] = value; 164 | } 165 | } 166 | } 167 | } 168 | return target; 169 | }; 170 | 171 | $.widget.bridge = function( name, object ) { 172 | var fullName = object.prototype.widgetFullName; 173 | $.fn[ name ] = function( options ) { 174 | var isMethodCall = typeof options === "string", 175 | args = slice.call( arguments, 1 ), 176 | returnValue = this; 177 | 178 | // allow multiple hashes to be passed on init 179 | options = !isMethodCall && args.length ? 180 | $.widget.extend.apply( null, [ options ].concat(args) ) : 181 | options; 182 | 183 | if ( isMethodCall ) { 184 | this.each(function() { 185 | var methodValue, 186 | instance = $.data( this, fullName ); 187 | if ( !instance ) { 188 | return $.error( "cannot call methods on " + name + " prior to initialization; " + 189 | "attempted to call method '" + options + "'" ); 190 | } 191 | if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { 192 | return $.error( "no such method '" + options + "' for " + name + " widget instance" ); 193 | } 194 | methodValue = instance[ options ].apply( instance, args ); 195 | if ( methodValue !== instance && methodValue !== undefined ) { 196 | returnValue = methodValue && methodValue.jquery ? 197 | returnValue.pushStack( methodValue.get() ) : 198 | methodValue; 199 | return false; 200 | } 201 | }); 202 | } else { 203 | this.each(function() { 204 | var instance = $.data( this, fullName ); 205 | if ( instance ) { 206 | instance.option( options || {} )._init(); 207 | } else { 208 | new object( options, this ); 209 | } 210 | }); 211 | } 212 | 213 | return returnValue; 214 | }; 215 | }; 216 | 217 | $.Widget = function( /* options, element */ ) {}; 218 | $.Widget._childConstructors = []; 219 | 220 | $.Widget.prototype = { 221 | widgetName: "widget", 222 | widgetEventPrefix: "", 223 | defaultElement: "
", 224 | options: { 225 | disabled: false, 226 | 227 | // callbacks 228 | create: null 229 | }, 230 | _createWidget: function( options, element ) { 231 | element = $( element || this.defaultElement || this )[ 0 ]; 232 | this.element = $( element ); 233 | this.uuid = uuid++; 234 | this.eventNamespace = "." + this.widgetName + this.uuid; 235 | this.options = $.widget.extend( {}, 236 | this.options, 237 | this._getCreateOptions(), 238 | options ); 239 | 240 | this.bindings = $(); 241 | this.hoverable = $(); 242 | this.focusable = $(); 243 | 244 | if ( element !== this ) { 245 | // 1.9 BC for #7810 246 | // TODO remove dual storage 247 | $.data( element, this.widgetName, this ); 248 | $.data( element, this.widgetFullName, this ); 249 | this._on( this.element, { 250 | remove: function( event ) { 251 | if ( event.target === element ) { 252 | this.destroy(); 253 | } 254 | } 255 | }); 256 | this.document = $( element.style ? 257 | // element within the document 258 | element.ownerDocument : 259 | // element is window or document 260 | element.document || element ); 261 | this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); 262 | } 263 | 264 | this._create(); 265 | this._trigger( "create", null, this._getCreateEventData() ); 266 | this._init(); 267 | }, 268 | _getCreateOptions: $.noop, 269 | _getCreateEventData: $.noop, 270 | _create: $.noop, 271 | _init: $.noop, 272 | 273 | destroy: function() { 274 | this._destroy(); 275 | // we can probably remove the unbind calls in 2.0 276 | // all event bindings should go through this._on() 277 | this.element 278 | .unbind( this.eventNamespace ) 279 | // 1.9 BC for #7810 280 | // TODO remove dual storage 281 | .removeData( this.widgetName ) 282 | .removeData( this.widgetFullName ) 283 | // support: jquery <1.6.3 284 | // http://bugs.jquery.com/ticket/9413 285 | .removeData( $.camelCase( this.widgetFullName ) ); 286 | this.widget() 287 | .unbind( this.eventNamespace ) 288 | .removeAttr( "aria-disabled" ) 289 | .removeClass( 290 | this.widgetFullName + "-disabled " + 291 | "ui-state-disabled" ); 292 | 293 | // clean up events and states 294 | this.bindings.unbind( this.eventNamespace ); 295 | this.hoverable.removeClass( "ui-state-hover" ); 296 | this.focusable.removeClass( "ui-state-focus" ); 297 | }, 298 | _destroy: $.noop, 299 | 300 | widget: function() { 301 | return this.element; 302 | }, 303 | 304 | option: function( key, value ) { 305 | var options = key, 306 | parts, 307 | curOption, 308 | i; 309 | 310 | if ( arguments.length === 0 ) { 311 | // don't return a reference to the internal hash 312 | return $.widget.extend( {}, this.options ); 313 | } 314 | 315 | if ( typeof key === "string" ) { 316 | // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 317 | options = {}; 318 | parts = key.split( "." ); 319 | key = parts.shift(); 320 | if ( parts.length ) { 321 | curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 322 | for ( i = 0; i < parts.length - 1; i++ ) { 323 | curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 324 | curOption = curOption[ parts[ i ] ]; 325 | } 326 | key = parts.pop(); 327 | if ( value === undefined ) { 328 | return curOption[ key ] === undefined ? null : curOption[ key ]; 329 | } 330 | curOption[ key ] = value; 331 | } else { 332 | if ( value === undefined ) { 333 | return this.options[ key ] === undefined ? null : this.options[ key ]; 334 | } 335 | options[ key ] = value; 336 | } 337 | } 338 | 339 | this._setOptions( options ); 340 | 341 | return this; 342 | }, 343 | _setOptions: function( options ) { 344 | var key; 345 | 346 | for ( key in options ) { 347 | this._setOption( key, options[ key ] ); 348 | } 349 | 350 | return this; 351 | }, 352 | _setOption: function( key, value ) { 353 | this.options[ key ] = value; 354 | 355 | if ( key === "disabled" ) { 356 | this.widget() 357 | .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) 358 | .attr( "aria-disabled", value ); 359 | this.hoverable.removeClass( "ui-state-hover" ); 360 | this.focusable.removeClass( "ui-state-focus" ); 361 | } 362 | 363 | return this; 364 | }, 365 | 366 | enable: function() { 367 | return this._setOption( "disabled", false ); 368 | }, 369 | disable: function() { 370 | return this._setOption( "disabled", true ); 371 | }, 372 | 373 | _on: function( element, handlers ) { 374 | var delegateElement, 375 | instance = this; 376 | // no element argument, shuffle and use this.element 377 | if ( !handlers ) { 378 | handlers = element; 379 | element = this.element; 380 | delegateElement = this.widget(); 381 | } else { 382 | // accept selectors, DOM elements 383 | element = delegateElement = $( element ); 384 | this.bindings = this.bindings.add( element ); 385 | } 386 | 387 | $.each( handlers, function( event, handler ) { 388 | function handlerProxy() { 389 | // allow widgets to customize the disabled handling 390 | // - disabled as an array instead of boolean 391 | // - disabled class as method for disabling individual parts 392 | if ( instance.options.disabled === true || 393 | $( this ).hasClass( "ui-state-disabled" ) ) { 394 | return; 395 | } 396 | return ( typeof handler === "string" ? instance[ handler ] : handler ) 397 | .apply( instance, arguments ); 398 | } 399 | 400 | // copy the guid so direct unbinding works 401 | if ( typeof handler !== "string" ) { 402 | handlerProxy.guid = handler.guid = 403 | handler.guid || handlerProxy.guid || $.guid++; 404 | } 405 | 406 | var match = event.match( /^(\w+)\s*(.*)$/ ), 407 | eventName = match[1] + instance.eventNamespace, 408 | selector = match[2]; 409 | if ( selector ) { 410 | delegateElement.delegate( selector, eventName, handlerProxy ); 411 | } else { 412 | element.bind( eventName, handlerProxy ); 413 | } 414 | }); 415 | }, 416 | 417 | _off: function( element, eventName ) { 418 | eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; 419 | element.unbind( eventName ).undelegate( eventName ); 420 | }, 421 | 422 | _delay: function( handler, delay ) { 423 | function handlerProxy() { 424 | return ( typeof handler === "string" ? instance[ handler ] : handler ) 425 | .apply( instance, arguments ); 426 | } 427 | var instance = this; 428 | return setTimeout( handlerProxy, delay || 0 ); 429 | }, 430 | 431 | _hoverable: function( element ) { 432 | this.hoverable = this.hoverable.add( element ); 433 | this._on( element, { 434 | mouseenter: function( event ) { 435 | $( event.currentTarget ).addClass( "ui-state-hover" ); 436 | }, 437 | mouseleave: function( event ) { 438 | $( event.currentTarget ).removeClass( "ui-state-hover" ); 439 | } 440 | }); 441 | }, 442 | 443 | _focusable: function( element ) { 444 | this.focusable = this.focusable.add( element ); 445 | this._on( element, { 446 | focusin: function( event ) { 447 | $( event.currentTarget ).addClass( "ui-state-focus" ); 448 | }, 449 | focusout: function( event ) { 450 | $( event.currentTarget ).removeClass( "ui-state-focus" ); 451 | } 452 | }); 453 | }, 454 | 455 | _trigger: function( type, event, data ) { 456 | var prop, orig, 457 | callback = this.options[ type ]; 458 | 459 | data = data || {}; 460 | event = $.Event( event ); 461 | event.type = ( type === this.widgetEventPrefix ? 462 | type : 463 | this.widgetEventPrefix + type ).toLowerCase(); 464 | // the original event may come from any element 465 | // so we need to reset the target on the new event 466 | event.target = this.element[ 0 ]; 467 | 468 | // copy original event properties over to the new event 469 | orig = event.originalEvent; 470 | if ( orig ) { 471 | for ( prop in orig ) { 472 | if ( !( prop in event ) ) { 473 | event[ prop ] = orig[ prop ]; 474 | } 475 | } 476 | } 477 | 478 | this.element.trigger( event, data ); 479 | return !( $.isFunction( callback ) && 480 | callback.apply( this.element[0], [ event ].concat( data ) ) === false || 481 | event.isDefaultPrevented() ); 482 | } 483 | }; 484 | 485 | $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 486 | $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 487 | if ( typeof options === "string" ) { 488 | options = { effect: options }; 489 | } 490 | var hasOptions, 491 | effectName = !options ? 492 | method : 493 | options === true || typeof options === "number" ? 494 | defaultEffect : 495 | options.effect || defaultEffect; 496 | options = options || {}; 497 | if ( typeof options === "number" ) { 498 | options = { duration: options }; 499 | } 500 | hasOptions = !$.isEmptyObject( options ); 501 | options.complete = callback; 502 | if ( options.delay ) { 503 | element.delay( options.delay ); 504 | } 505 | if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) { 506 | element[ method ]( options ); 507 | } else if ( effectName !== method && element[ effectName ] ) { 508 | element[ effectName ]( options.duration, options.easing, callback ); 509 | } else { 510 | element.queue(function( next ) { 511 | $( this )[ method ](); 512 | if ( callback ) { 513 | callback.call( element[ 0 ] ); 514 | } 515 | next(); 516 | }); 517 | } 518 | }; 519 | }); 520 | 521 | // DEPRECATED 522 | if ( $.uiBackCompat !== false ) { 523 | $.Widget.prototype._getCreateOptions = function() { 524 | return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; 525 | }; 526 | } 527 | 528 | })); 529 | -------------------------------------------------------------------------------- /spec/dummy4/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "vendor/assets/components" 3 | } 4 | -------------------------------------------------------------------------------- /spec/dummy4/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | !/log/.keep 17 | /tmp 18 | */cloudinary.yml 19 | vendor/assets/ 20 | db/ 21 | -------------------------------------------------------------------------------- /spec/dummy4/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '4.2.3' 6 | # Use sqlite3 as the database for Active Record 7 | gem 'sqlite3' 8 | # Use SCSS for stylesheets 9 | gem 'sass-rails', '~> 5.0' 10 | # Use Uglifier as compressor for JavaScript assets 11 | gem 'uglifier', '>= 1.3.0' 12 | # Use CoffeeScript for .coffee assets and views 13 | gem 'coffee-rails', '~> 4.1.0' 14 | # See https://github.com/rails/execjs#readme for more supported runtimes 15 | # gem 'therubyracer', platforms: :ruby 16 | 17 | # Use jquery as the JavaScript library 18 | gem 'jquery-rails' 19 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 20 | gem 'turbolinks' 21 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 22 | gem 'jbuilder', '~> 2.0' 23 | # bundle exec rake doc:rails generates the API under doc/api. 24 | gem 'sdoc', '~> 0.4.0', group: :doc 25 | 26 | # Use ActiveModel has_secure_password 27 | # gem 'bcrypt', '~> 3.1.7' 28 | 29 | # Use Unicorn as the app server 30 | # gem 'unicorn' 31 | 32 | # Use Capistrano for deployment 33 | # gem 'capistrano-rails', group: :development 34 | 35 | group :development, :test do 36 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 37 | gem 'byebug' 38 | 39 | # Access an IRB console on exception pages or by using <%= console %> in views 40 | gem 'web-console', '~> 2.0' 41 | 42 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 43 | gem 'spring' 44 | gem 'rspec-rails' 45 | gem 'ruby-debug-ide' 46 | gem 'debase' 47 | gem 'valid_attribute' 48 | gem 'capybara' 49 | gem 'capybara-webkit' 50 | gem 'selenium-webdriver' 51 | gem 'factory_girl_rails' 52 | gem 'launchy' 53 | gem 'database_cleaner' 54 | gem 'rb-fsevent', '~> 0.9.1' 55 | gem 'guard-rspec' 56 | end 57 | 58 | gem 'mongoid' 59 | gem 'cloudinary', '~> 1.1' 60 | gem 'attachinary', :path => '../..' 61 | gem 'bootstrap-sass', '~> 3.3.5' 62 | gem 'simple_form' -------------------------------------------------------------------------------- /spec/dummy4/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../.. 3 | specs: 4 | attachinary (1.3.1) 5 | cloudinary (~> 1.1.0) 6 | rails (>= 3.2) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionmailer (4.2.3) 12 | actionpack (= 4.2.3) 13 | actionview (= 4.2.3) 14 | activejob (= 4.2.3) 15 | mail (~> 2.5, >= 2.5.4) 16 | rails-dom-testing (~> 1.0, >= 1.0.5) 17 | actionpack (4.2.3) 18 | actionview (= 4.2.3) 19 | activesupport (= 4.2.3) 20 | rack (~> 1.6) 21 | rack-test (~> 0.6.2) 22 | rails-dom-testing (~> 1.0, >= 1.0.5) 23 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 24 | actionview (4.2.3) 25 | activesupport (= 4.2.3) 26 | builder (~> 3.1) 27 | erubis (~> 2.7.0) 28 | rails-dom-testing (~> 1.0, >= 1.0.5) 29 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 30 | activejob (4.2.3) 31 | activesupport (= 4.2.3) 32 | globalid (>= 0.3.0) 33 | activemodel (4.2.3) 34 | activesupport (= 4.2.3) 35 | builder (~> 3.1) 36 | activerecord (4.2.3) 37 | activemodel (= 4.2.3) 38 | activesupport (= 4.2.3) 39 | arel (~> 6.0) 40 | activesupport (4.2.3) 41 | i18n (~> 0.7) 42 | json (~> 1.7, >= 1.7.7) 43 | minitest (~> 5.1) 44 | thread_safe (~> 0.3, >= 0.3.4) 45 | tzinfo (~> 1.1) 46 | addressable (2.3.8) 47 | arel (6.0.2) 48 | autoprefixer-rails (5.2.1.1) 49 | execjs 50 | json 51 | aws_cf_signer (0.1.3) 52 | binding_of_caller (0.7.2) 53 | debug_inspector (>= 0.0.1) 54 | bootstrap-sass (3.3.5.1) 55 | autoprefixer-rails (>= 5.0.0.1) 56 | sass (>= 3.3.0) 57 | bson (3.2.4) 58 | builder (3.2.2) 59 | byebug (5.0.0) 60 | columnize (= 0.9.0) 61 | capybara (2.5.0) 62 | mime-types (>= 1.16) 63 | nokogiri (>= 1.3.3) 64 | rack (>= 1.0.0) 65 | rack-test (>= 0.5.4) 66 | xpath (~> 2.0) 67 | capybara-webkit (1.7.1) 68 | capybara (>= 2.3.0, < 2.6.0) 69 | json 70 | childprocess (0.5.6) 71 | ffi (~> 1.0, >= 1.0.11) 72 | cloudinary (1.1.0) 73 | aws_cf_signer 74 | rest-client 75 | coderay (1.1.0) 76 | coffee-rails (4.1.0) 77 | coffee-script (>= 2.2.0) 78 | railties (>= 4.0.0, < 5.0) 79 | coffee-script (2.4.1) 80 | coffee-script-source 81 | execjs 82 | coffee-script-source (1.9.1.1) 83 | columnize (0.9.0) 84 | database_cleaner (1.5.0) 85 | debase (0.2.1) 86 | debase-ruby_core_source 87 | debase-ruby_core_source (0.7.10) 88 | debug_inspector (0.0.2) 89 | diff-lcs (1.2.5) 90 | domain_name (0.5.24) 91 | unf (>= 0.0.5, < 1.0.0) 92 | erubis (2.7.0) 93 | execjs (2.5.2) 94 | factory_girl (4.5.0) 95 | activesupport (>= 3.0.0) 96 | factory_girl_rails (4.5.0) 97 | factory_girl (~> 4.5.0) 98 | railties (>= 3.0.0) 99 | ffi (1.9.10) 100 | formatador (0.2.5) 101 | globalid (0.3.5) 102 | activesupport (>= 4.1.0) 103 | guard (2.13.0) 104 | formatador (>= 0.2.4) 105 | listen (>= 2.7, <= 4.0) 106 | lumberjack (~> 1.0) 107 | nenv (~> 0.1) 108 | notiffany (~> 0.0) 109 | pry (>= 0.9.12) 110 | shellany (~> 0.0) 111 | thor (>= 0.18.1) 112 | guard-compat (1.2.1) 113 | guard-rspec (4.6.4) 114 | guard (~> 2.1) 115 | guard-compat (~> 1.1) 116 | rspec (>= 2.99.0, < 4.0) 117 | http-cookie (1.0.2) 118 | domain_name (~> 0.5) 119 | i18n (0.7.0) 120 | jbuilder (2.3.1) 121 | activesupport (>= 3.0.0, < 5) 122 | multi_json (~> 1.2) 123 | jquery-rails (4.0.4) 124 | rails-dom-testing (~> 1.0) 125 | railties (>= 4.2.0) 126 | thor (>= 0.14, < 2.0) 127 | json (1.8.3) 128 | launchy (2.4.3) 129 | addressable (~> 2.3) 130 | listen (3.0.3) 131 | rb-fsevent (>= 0.9.3) 132 | rb-inotify (>= 0.9) 133 | loofah (2.0.2) 134 | nokogiri (>= 1.5.9) 135 | lumberjack (1.0.9) 136 | mail (2.6.3) 137 | mime-types (>= 1.16, < 3) 138 | method_source (0.8.2) 139 | mime-types (2.6.1) 140 | mini_portile (0.6.2) 141 | minitest (5.7.0) 142 | mongo (2.1.1) 143 | bson (~> 3.0) 144 | mongoid (5.0.0) 145 | activemodel (~> 4.0) 146 | mongo (~> 2.1) 147 | origin (~> 2.1) 148 | tzinfo (>= 0.3.37) 149 | multi_json (1.11.2) 150 | nenv (0.2.0) 151 | netrc (0.10.3) 152 | nokogiri (1.6.6.2) 153 | mini_portile (~> 0.6.0) 154 | notiffany (0.0.8) 155 | nenv (~> 0.1) 156 | shellany (~> 0.0) 157 | origin (2.1.1) 158 | pry (0.10.2) 159 | coderay (~> 1.1.0) 160 | method_source (~> 0.8.1) 161 | slop (~> 3.4) 162 | rack (1.6.4) 163 | rack-test (0.6.3) 164 | rack (>= 1.0) 165 | rails (4.2.3) 166 | actionmailer (= 4.2.3) 167 | actionpack (= 4.2.3) 168 | actionview (= 4.2.3) 169 | activejob (= 4.2.3) 170 | activemodel (= 4.2.3) 171 | activerecord (= 4.2.3) 172 | activesupport (= 4.2.3) 173 | bundler (>= 1.3.0, < 2.0) 174 | railties (= 4.2.3) 175 | sprockets-rails 176 | rails-deprecated_sanitizer (1.0.3) 177 | activesupport (>= 4.2.0.alpha) 178 | rails-dom-testing (1.0.6) 179 | activesupport (>= 4.2.0.beta, < 5.0) 180 | nokogiri (~> 1.6.0) 181 | rails-deprecated_sanitizer (>= 1.0.1) 182 | rails-html-sanitizer (1.0.2) 183 | loofah (~> 2.0) 184 | railties (4.2.3) 185 | actionpack (= 4.2.3) 186 | activesupport (= 4.2.3) 187 | rake (>= 0.8.7) 188 | thor (>= 0.18.1, < 2.0) 189 | rake (10.4.2) 190 | rb-fsevent (0.9.6) 191 | rb-inotify (0.9.5) 192 | ffi (>= 0.5.0) 193 | rdoc (4.2.0) 194 | json (~> 1.4) 195 | rest-client (1.8.0) 196 | http-cookie (>= 1.0.2, < 2.0) 197 | mime-types (>= 1.16, < 3.0) 198 | netrc (~> 0.7) 199 | rspec (3.3.0) 200 | rspec-core (~> 3.3.0) 201 | rspec-expectations (~> 3.3.0) 202 | rspec-mocks (~> 3.3.0) 203 | rspec-core (3.3.2) 204 | rspec-support (~> 3.3.0) 205 | rspec-expectations (3.3.1) 206 | diff-lcs (>= 1.2.0, < 2.0) 207 | rspec-support (~> 3.3.0) 208 | rspec-mocks (3.3.2) 209 | diff-lcs (>= 1.2.0, < 2.0) 210 | rspec-support (~> 3.3.0) 211 | rspec-rails (3.3.3) 212 | actionpack (>= 3.0, < 4.3) 213 | activesupport (>= 3.0, < 4.3) 214 | railties (>= 3.0, < 4.3) 215 | rspec-core (~> 3.3.0) 216 | rspec-expectations (~> 3.3.0) 217 | rspec-mocks (~> 3.3.0) 218 | rspec-support (~> 3.3.0) 219 | rspec-support (3.3.0) 220 | ruby-debug-ide (0.6.0) 221 | rake (>= 0.8.1) 222 | rubyzip (1.1.7) 223 | sass (3.4.16) 224 | sass-rails (5.0.3) 225 | railties (>= 4.0.0, < 5.0) 226 | sass (~> 3.1) 227 | sprockets (>= 2.8, < 4.0) 228 | sprockets-rails (>= 2.0, < 4.0) 229 | tilt (~> 1.1) 230 | sdoc (0.4.1) 231 | json (~> 1.7, >= 1.7.7) 232 | rdoc (~> 4.0) 233 | selenium-webdriver (2.47.1) 234 | childprocess (~> 0.5) 235 | multi_json (~> 1.0) 236 | rubyzip (~> 1.0) 237 | websocket (~> 1.0) 238 | shellany (0.0.1) 239 | simple_form (3.2.0) 240 | actionpack (~> 4.0) 241 | activemodel (~> 4.0) 242 | slop (3.6.0) 243 | spring (1.3.6) 244 | sprockets (3.2.0) 245 | rack (~> 1.0) 246 | sprockets-rails (2.3.2) 247 | actionpack (>= 3.0) 248 | activesupport (>= 3.0) 249 | sprockets (>= 2.8, < 4.0) 250 | sqlite3 (1.3.10) 251 | thor (0.19.1) 252 | thread_safe (0.3.5) 253 | tilt (1.4.1) 254 | turbolinks (2.5.3) 255 | coffee-rails 256 | tzinfo (1.2.2) 257 | thread_safe (~> 0.1) 258 | uglifier (2.7.1) 259 | execjs (>= 0.3.0) 260 | json (>= 1.8.0) 261 | unf (0.1.4) 262 | unf_ext 263 | unf_ext (0.0.7.1) 264 | valid_attribute (2.0.0) 265 | web-console (2.2.1) 266 | activemodel (>= 4.0) 267 | binding_of_caller (>= 0.7.2) 268 | railties (>= 4.0) 269 | sprockets-rails (>= 2.0, < 4.0) 270 | websocket (1.2.2) 271 | xpath (2.0.0) 272 | nokogiri (~> 1.3) 273 | 274 | PLATFORMS 275 | ruby 276 | 277 | DEPENDENCIES 278 | attachinary! 279 | bootstrap-sass (~> 3.3.5) 280 | byebug 281 | capybara 282 | capybara-webkit 283 | cloudinary (~> 1.1) 284 | coffee-rails (~> 4.1.0) 285 | database_cleaner 286 | debase 287 | factory_girl_rails 288 | guard-rspec 289 | jbuilder (~> 2.0) 290 | jquery-rails 291 | launchy 292 | mongoid 293 | rails (= 4.2.3) 294 | rb-fsevent (~> 0.9.1) 295 | rspec-rails 296 | ruby-debug-ide 297 | sass-rails (~> 5.0) 298 | sdoc (~> 0.4.0) 299 | selenium-webdriver 300 | simple_form 301 | spring 302 | sqlite3 303 | turbolinks 304 | uglifier (>= 1.3.0) 305 | valid_attribute 306 | web-console (~> 2.0) 307 | -------------------------------------------------------------------------------- /spec/dummy4/README.rdoc: -------------------------------------------------------------------------------- 1 | == README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | 26 | 27 | Please feel free to use a different markup language if you do not plan to run 28 | rake doc:app. 29 | -------------------------------------------------------------------------------- /spec/dummy4/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/dummy4/app/active_record/note.rb: -------------------------------------------------------------------------------- 1 | class Note < ActiveRecord::Base 2 | 3 | has_attachment :photo, accept: [:jpg, :png, :gif] 4 | has_attachments :images, accept: [:jpg, :png, :gif], maximum: 3 5 | 6 | validates :body, presence: true, length: { minimum: 4, maximum: 128 } 7 | validates :photo, presence: true 8 | 9 | end 10 | -------------------------------------------------------------------------------- /spec/dummy4/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/app/assets/images/.keep -------------------------------------------------------------------------------- /spec/dummy4/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require turbolinks 16 | //= require bootstrap-sprockets 17 | //= require blueimp-file-upload/js/vendor/jquery.ui.widget 18 | //= require blueimp-file-upload/js/jquery.iframe-transport 19 | //= require blueimp-file-upload/js/jquery.fileupload 20 | //= require cloudinary/jquery.cloudinary 21 | //= require attachinary 22 | 23 | //= require_tree . 24 | 25 | 26 | //jQuery(function() { 27 | $(document).on('ready page:chagne page:load', function(e){ 28 | $('.attachinary-input').attachinary(); 29 | }); 30 | 31 | //}); 32 | -------------------------------------------------------------------------------- /spec/dummy4/app/assets/javascripts/notes.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /spec/dummy4/app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | */ 14 | 15 | // "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables" 16 | @import "bootstrap-sprockets"; 17 | @import "bootstrap"; 18 | @import "notes"; 19 | -------------------------------------------------------------------------------- /spec/dummy4/app/assets/stylesheets/notes.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the notes controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /spec/dummy4/app/assets/stylesheets/scaffolds.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #333; 4 | font-family: verdana, arial, helvetica, sans-serif; 5 | font-size: 13px; 6 | line-height: 18px; 7 | } 8 | 9 | p, ol, ul, td { 10 | font-family: verdana, arial, helvetica, sans-serif; 11 | font-size: 13px; 12 | line-height: 18px; 13 | } 14 | 15 | pre { 16 | background-color: #eee; 17 | padding: 10px; 18 | font-size: 11px; 19 | } 20 | 21 | a { 22 | color: #000; 23 | 24 | &:visited { 25 | color: #666; 26 | } 27 | 28 | &:hover { 29 | color: #fff; 30 | background-color: #000; 31 | } 32 | } 33 | 34 | div { 35 | &.field, &.actions { 36 | margin-bottom: 10px; 37 | } 38 | } 39 | 40 | #notice { 41 | color: green; 42 | } 43 | 44 | .field_with_errors { 45 | padding: 2px; 46 | background-color: red; 47 | display: table; 48 | } 49 | 50 | #error_explanation { 51 | width: 450px; 52 | border: 2px solid red; 53 | padding: 7px; 54 | padding-bottom: 0; 55 | margin-bottom: 20px; 56 | background-color: #f0f0f0; 57 | 58 | h2 { 59 | text-align: left; 60 | font-weight: bold; 61 | padding: 5px 5px 5px 15px; 62 | font-size: 12px; 63 | margin: -7px; 64 | margin-bottom: 0px; 65 | background-color: #c00; 66 | color: #fff; 67 | } 68 | 69 | ul li { 70 | font-size: 12px; 71 | list-style: square; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /spec/dummy4/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy4/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy4/app/controllers/notes_controller.rb: -------------------------------------------------------------------------------- 1 | class NotesController < ApplicationController 2 | before_action :set_note, only: [:show, :edit, :update, :destroy] 3 | 4 | # GET /notes 5 | # GET /notes.json 6 | def index 7 | @notes = Note.all 8 | end 9 | 10 | # GET /notes/1 11 | # GET /notes/1.json 12 | def show 13 | end 14 | 15 | # GET /notes/new 16 | def new 17 | @note = Note.new 18 | end 19 | 20 | # GET /notes/1/edit 21 | def edit 22 | end 23 | 24 | # POST /notes 25 | # POST /notes.json 26 | def create 27 | @note = Note.new(note_params) 28 | 29 | respond_to do |format| 30 | if @note.save 31 | format.html { redirect_to notes_url, notice: 'Note was successfully created.' } 32 | format.json { render :show, status: :created, location: @note } 33 | else 34 | format.html { render :new } 35 | format.json { render json: @note.errors, status: :unprocessable_entity } 36 | end 37 | end 38 | end 39 | 40 | # PATCH/PUT /notes/1 41 | # PATCH/PUT /notes/1.json 42 | def update 43 | respond_to do |format| 44 | if @note.update(note_params) 45 | format.html { redirect_to notes_url, notice: 'Note was successfully updated.' } 46 | format.json { render :show, status: :ok, location: @note } 47 | else 48 | format.html { render :edit } 49 | format.json { render json: @note.errors, status: :unprocessable_entity } 50 | end 51 | end 52 | end 53 | 54 | # DELETE /notes/1 55 | # DELETE /notes/1.json 56 | def destroy 57 | @note.destroy 58 | respond_to do |format| 59 | format.html { redirect_to notes_url, notice: 'Note was successfully destroyed.' } 60 | format.json { head :no_content } 61 | end 62 | end 63 | 64 | private 65 | # Use callbacks to share common setup or constraints between actions. 66 | def set_note 67 | @note = Note.find(params[:id]) 68 | end 69 | 70 | # Never trust parameters from the scary internet, only allow the white list through. 71 | def note_params 72 | params.require(:note).permit(:body, :photo, :images => []) 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/dummy4/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy4/app/helpers/notes_helper.rb: -------------------------------------------------------------------------------- 1 | module NotesHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy4/app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/app/mailers/.keep -------------------------------------------------------------------------------- /spec/dummy4/app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/app/models/.keep -------------------------------------------------------------------------------- /spec/dummy4/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/app/models/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy4/app/mongoid/note.rb: -------------------------------------------------------------------------------- 1 | class Note 2 | include Mongoid::Document 3 | include Mongoid::Timestamps 4 | field :body, type: String 5 | 6 | has_attachment :photo, accept: [:jpg, :png, :gif] 7 | has_attachments :images, accept: [:jpg, :png, :gif], maximum: 3 8 | 9 | validates :body, presence: true, length: { minimum: 5, maximum: 128 } 10 | validates :photo, presence: true 11 | end 12 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy4 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= cloudinary_js_config %> 8 | <%= csrf_meta_tags %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(@note) do |f| %> 2 | <% if @note.errors.any? %> 3 |
4 |

<%= pluralize(@note.errors.count, "error") %> prohibited this note from being saved:

5 | 6 |
    7 | <% @note.errors.full_messages.each do |message| %> 8 |
  • <%= message %>
  • 9 | <% end %> 10 |
11 |
12 | <% end %> 13 | 14 |
15 | <%= f.label :body %>
16 | <%= f.text_field :body %> 17 |
18 |
19 | <%= f.submit %> 20 |
21 | <% end %> 22 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/_form_builder.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for note, html: { multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.label 'Body' %> 6 |
7 | 8 | <%= f.text_field :body %> 9 |
<%= note.errors[:body].first %>
10 |
11 | 12 |
13 | <%= f.attachinary_file_field :photo %> 14 |
<%= note.errors[:photo].first %>
15 |
16 | 17 |
18 | 19 |
20 | <%= f.attachinary_file_field :images %> 21 |
<%= note.errors[:image].first %>
22 |
23 | 24 |
25 |
26 | 27 | <%= f.submit %> 28 | <% end %> 29 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/_form_nojs.html.erb: -------------------------------------------------------------------------------- 1 | <%= simple_form_for note, html: { novalidate: true, multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.input :body, as: :string %> 6 | 7 |
8 | <%= f.input :photo, as: :file %> 9 |
10 | 11 |
12 | <%= f.input :images, as: :file, input_html: { multiple: true } %> 13 |
14 | 15 | <%= f.submit %> 16 | 17 | <% end %> 18 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/_form_raw.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for note, html: { multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.label 'Body' %> 6 |
7 | 8 | <%= f.text_field :body %> 9 |
<%= note.errors[:body].first %>
10 |
11 | 12 |
13 | <%= attachinary_file_field_tag 'note[photo]', note, :photo %> 14 |
<%= note.errors[:photo].first %>
15 |
16 | 17 |
18 | 19 |
20 | <%= attachinary_file_field_tag 'note[images][]', note, :images %> 21 |
<%= note.errors[:image].first %>
22 |
23 | 24 |
25 |
26 | 27 | <%= f.submit %> 28 | <% end %> 29 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/_form_simple_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= simple_form_for note, html: { novalidate: true, multipart: true } do |f| %> 2 | 3 | <%= hidden_field_tag 'kind', params[:kind] %> 4 | 5 | <%= f.input :body, as: :string %> 6 | 7 |
8 | <%= f.input :photo, as: :attachinary %> 9 |
10 | 11 |
12 | <%= f.input :images, as: :attachinary %> 13 |
14 | 15 | <%= f.submit %> 16 | 17 | <% end %> 18 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/_note.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <% if note.photo? %> 3 | <%= cl_image_tag note.photo.path, 4 | size: '120x120', crop: :fill, html_width: nil, html_height: nil %>
5 | 6 | <% note.images.each do |image| %> 7 | <%= cl_image_tag image.path, size: '37x37', crop: :fill, html_width: nil, html_height: nil %> 8 | <% end %> 9 | <% end %>
10 | <%= note.body %>
11 | <%= link_to 'edit (raw)', edit_note_path(note, kind: 'raw') %>
12 | <%= link_to 'edit (builder)', edit_note_path(note, kind: 'builder') %>
13 | <%= link_to 'edit (simple form)', edit_note_path(note, kind: 'simple_form') %>
14 | <%= link_to 'delete', note_path(note), method: :delete %> 15 |
16 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= render "form_#{params[:kind]}", note: @note %> 2 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/index.html.erb: -------------------------------------------------------------------------------- 1 |

Notes

2 |

<%= ATTACHINARY_ORM %>

3 | 4 |
5 | <%= render @notes %> 6 |
7 | 8 |
9 |
10 | <%= link_to 'create (raw)', new_note_path(kind: 'raw') %>
11 | <%= link_to 'create (builder)', new_note_path(kind: 'builder') %>
12 | <%= link_to 'create (simple form)', new_note_path(kind: 'simple_form') %>
13 | <%= link_to 'create (no javascript)', new_note_path(kind: 'nojs') %>
14 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array!(@notes) do |note| 2 | json.extract! note, :id, :body 3 | json.url note_url(note, format: :json) 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= render "form_#{params[:kind]}", note: @note %> 2 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

4 | Body: 5 | <%= @note.body %> 6 |

7 | 8 | <%= link_to 'Edit', edit_note_path(@note) %> | 9 | <%= link_to 'Back', notes_path %> 10 | -------------------------------------------------------------------------------- /spec/dummy4/app/views/notes/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.extract! @note, :id, :body, :created_at, :updated_at 2 | -------------------------------------------------------------------------------- /spec/dummy4/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dummy4", 3 | "version": "1.2.6", 4 | "homepage": "https://github.com/assembler/attachinary", 5 | "authors": [ 6 | "Amir Tocker " 7 | ], 8 | "license": "MIT", 9 | "ignore": [ 10 | "**/.*", 11 | "node_modules", 12 | "bower_components", 13 | "test", 14 | "tests" 15 | ], 16 | "dependencies": { 17 | "jquery": ">=1.6", 18 | "blueimp-file-upload": ">=7.2.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /spec/dummy4/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /spec/dummy4/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups, ATTACHINARY_ORM) 8 | begin 9 | require "#{ATTACHINARY_ORM}/railtie" 10 | rescue LoadError 11 | end 12 | 13 | require "attachinary" 14 | 15 | module Dummy4 16 | class Application < Rails::Application 17 | # Settings in config/environments/* take precedence over those specified here. 18 | # Application configuration should go into files in config/initializers 19 | # -- all .rb files in that directory are automatically loaded. 20 | 21 | # Custom directories with classes and modules you want to be autoloadable. 22 | # config.autoload_paths += %W(#{config.root}/extras) 23 | config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers views).include?($1) } 24 | config.autoload_paths += [ "#{config.root}/app/#{ATTACHINARY_ORM}" ] 25 | 26 | # Only load the plugins named here, in the order given (default is alphabetical). 27 | # :all can be used as a placeholder for all plugins not explicitly named. 28 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 29 | 30 | # Activate observers that should always be running. 31 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 32 | 33 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 34 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 35 | # config.time_zone = 'Central Time (US & Canada)' 36 | 37 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 38 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 39 | # config.i18n.default_locale = :de 40 | 41 | # Do not swallow errors in after_commit/after_rollback callbacks. 42 | config.active_record.raise_in_transactional_callbacks = true 43 | 44 | config.assets.paths << Rails.root.join('vendor', 'assets', 'components') 45 | if ATTACHINARY_ORM == 'mongoid' 46 | config.generators do |g| 47 | g.orm :mongoid 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/dummy4/config/boot.rb: -------------------------------------------------------------------------------- 1 | unless defined?(ATTACHINARY_ORM) 2 | ATTACHINARY_ORM = (ENV["ATTACHINARY_ORM"] || :active_record).to_sym 3 | end 4 | 5 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 6 | 7 | require 'bundler/setup' # Set up gems listed in the Gemfile. 8 | -------------------------------------------------------------------------------- /spec/dummy4/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /spec/dummy4/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /spec/dummy4/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 31 | # yet still be able to expire them through the digest params. 32 | config.assets.digest = true 33 | 34 | # Adds additional error checking when serving assets at runtime. 35 | # Checks for improperly declared sprockets dependencies. 36 | # Raises helpful error messages. 37 | config.assets.raise_runtime_errors = true 38 | 39 | # Raises error for missing translations 40 | # config.action_view.raise_on_missing_translations = true 41 | end 42 | -------------------------------------------------------------------------------- /spec/dummy4/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like 20 | # NGINX, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress JavaScripts and CSS. 28 | config.assets.js_compressor = :uglifier 29 | # config.assets.css_compressor = :sass 30 | 31 | # Do not fallback to assets pipeline if a precompiled asset is missed. 32 | config.assets.compile = false 33 | 34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 35 | # yet still be able to expire them through the digest params. 36 | config.assets.digest = true 37 | 38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 39 | 40 | # Specifies the header that your server uses for sending files. 41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 43 | 44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 45 | # config.force_ssl = true 46 | 47 | # Use the lowest log level to ensure availability of diagnostic information 48 | # when problems arise. 49 | config.log_level = :debug 50 | 51 | # Prepend all log lines with the following tags. 52 | # config.log_tags = [ :subdomain, :uuid ] 53 | 54 | # Use a different logger for distributed setups. 55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 61 | # config.action_controller.asset_host = 'http://assets.example.com' 62 | 63 | # Ignore bad email addresses and do not raise email delivery errors. 64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 65 | # config.action_mailer.raise_delivery_errors = false 66 | 67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 68 | # the I18n.default_locale when a translation cannot be found). 69 | config.i18n.fallbacks = true 70 | 71 | # Send deprecation notices to registered listeners. 72 | config.active_support.deprecation = :notify 73 | 74 | # Use default logging formatter so that PID and timestamp are not suppressed. 75 | config.log_formatter = ::Logger::Formatter.new 76 | 77 | # Do not dump schema after migrations. 78 | config.active_record.dump_schema_after_migration = false 79 | end 80 | -------------------------------------------------------------------------------- /spec/dummy4/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static file server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Randomize the order test cases are executed. 35 | config.active_support.test_order = :random 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/attachinary.rb: -------------------------------------------------------------------------------- 1 | require "attachinary/orm/#{ATTACHINARY_ORM}" 2 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_dummy4_session' 4 | -------------------------------------------------------------------------------- /spec/dummy4/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /spec/dummy4/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /spec/dummy4/config/mongoid.yml: -------------------------------------------------------------------------------- 1 | development: 2 | # Configure available database clients. (required) 3 | clients: 4 | # Defines the default client. (required) 5 | default: 6 | # Defines the name of the default database that Mongoid can connect to. 7 | # (required). 8 | database: dummy4_development 9 | # Provides the hosts the default client can connect to. Must be an array 10 | # of host:port pairs. (required) 11 | hosts: 12 | - localhost:27017 13 | options: 14 | # Change the default write concern. (default = { w: 1 }) 15 | # write: 16 | # w: 1 17 | 18 | # Change the default read preference. Valid options for mode are: :secondary, 19 | # :secondary_preferred, :primary, :primary_preferred, :nearest 20 | # (default: primary) 21 | # read: 22 | # mode: :secondary_preferred 23 | 24 | # The name of the user for authentication. 25 | # user: 'user' 26 | 27 | # The password of the user for authentication. 28 | # password: 'password' 29 | 30 | # The user's database roles. 31 | # roles: 32 | # - 'dbOwner' 33 | 34 | # Change the default authentication mechanism. Valid options are: :scram, 35 | # :mongodb_cr, :mongodb_x509, and :plain. (default on 3.0 is :scram, default 36 | # on 2.4 and 2.6 is :plain) 37 | # auth_mech: :scram 38 | 39 | # The database or source to authenticate the user against. (default: admin) 40 | # auth_source: admin 41 | 42 | # Force a the driver cluster to behave in a certain manner instead of auto- 43 | # discovering. Can be one of: :direct, :replica_set, :sharded. Set to :direct 44 | # when connecting to hidden members of a replica set. 45 | # connect: :direct 46 | 47 | # Changes the default time in seconds the server monitors refresh their status 48 | # via ismaster commands. (default: 10) 49 | # heartbeat_frequency: 10 50 | 51 | # The time in seconds for selecting servers for a near read preference. (default: 5) 52 | # local_threshold: 5 53 | 54 | # The timeout in seconds for selecting a server for an operation. (default: 30) 55 | # server_selection_timeout: 30 56 | 57 | # The maximum number of connections in the connection pool. (default: 5) 58 | # max_pool_size: 5 59 | 60 | # The minimum number of connections in the connection pool. (default: 1) 61 | # min_pool_size: 1 62 | 63 | # The time to wait, in seconds, in the connection pool for a connection 64 | # to be checked in before timing out. (default: 5) 65 | # wait_queue_timeout: 5 66 | 67 | # The time to wait to establish a connection before timing out, in seconds. 68 | # (default: 5) 69 | # connect_timeout: 5 70 | 71 | # The timeout to wait to execute operations on a socket before raising an error. 72 | # (default: 5) 73 | # socket_timeout: 5 74 | 75 | # The name of the replica set to connect to. Servers provided as seeds that do 76 | # not belong to this replica set will be ignored. 77 | # replica_set: name 78 | 79 | # Whether to connect to the servers via ssl. (default: false) 80 | # ssl: true 81 | 82 | # The certificate file used to identify the connection against MongoDB. 83 | # ssl_cert: /path/to/my.cert 84 | 85 | # The private keyfile used to identify the connection against MongoDB. 86 | # Note that even if the key is stored in the same file as the certificate, 87 | # both need to be explicitly specified. 88 | # ssl_key: /path/to/my.key 89 | 90 | # A passphrase for the private key. 91 | # ssl_key_pass_phrase: password 92 | 93 | # Whether or not to do peer certification validation. (default: false) 94 | # ssl_verify: true 95 | 96 | # The file containing a set of concatenated certification authority certifications 97 | # used to validate certs passed from the other end of the connection. 98 | # ssl_ca_cert: /path/to/ca.cert 99 | 100 | 101 | # Configure Mongoid specific options. (optional) 102 | options: 103 | # Includes the root model name in json serialization. (default: false) 104 | # include_root_in_json: false 105 | 106 | # Include the _type field in serialization. (default: false) 107 | # include_type_for_serialization: false 108 | 109 | # Preload all models in development, needed when models use 110 | # inheritance. (default: false) 111 | # preload_models: false 112 | 113 | # Raise an error when performing a #find and the document is not found. 114 | # (default: true) 115 | # raise_not_found_error: true 116 | 117 | # Raise an error when defining a scope with the same name as an 118 | # existing method. (default: false) 119 | # scope_overwrite_exception: false 120 | 121 | # Use Active Support's time zone in conversions. (default: true) 122 | # use_activesupport_time_zone: true 123 | 124 | # Ensure all times are UTC in the app side. (default: false) 125 | # use_utc: false 126 | test: 127 | clients: 128 | default: 129 | database: dummy4_test 130 | hosts: 131 | - localhost:27017 132 | options: 133 | # read: 134 | # mode: primary 135 | max_pool_size: 1 136 | -------------------------------------------------------------------------------- /spec/dummy4/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | mount Attachinary::Engine => "/attachinary" 3 | resources :notes 4 | root to: 'notes#index' 5 | 6 | # The priority is based upon order of creation: first created -> highest priority. 7 | # See how all your routes lay out with "rake routes". 8 | 9 | # You can have the root of your site routed with "root" 10 | # root 'welcome#index' 11 | 12 | # Example of regular route: 13 | # get 'products/:id' => 'catalog#view' 14 | 15 | # Example of named route that can be invoked with purchase_url(id: product.id) 16 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 17 | 18 | # Example resource route (maps HTTP verbs to controller actions automatically): 19 | # resources :products 20 | 21 | # Example resource route with options: 22 | # resources :products do 23 | # member do 24 | # get 'short' 25 | # post 'toggle' 26 | # end 27 | # 28 | # collection do 29 | # get 'sold' 30 | # end 31 | # end 32 | 33 | # Example resource route with sub-resources: 34 | # resources :products do 35 | # resources :comments, :sales 36 | # resource :seller 37 | # end 38 | 39 | # Example resource route with more complex sub-resources: 40 | # resources :products do 41 | # resources :comments 42 | # resources :sales do 43 | # get 'recent', on: :collection 44 | # end 45 | # end 46 | 47 | # Example resource route with concerns: 48 | # concern :toggleable do 49 | # post 'toggle' 50 | # end 51 | # resources :posts, concerns: :toggleable 52 | # resources :photos, concerns: :toggleable 53 | 54 | # Example resource route within a namespace: 55 | # namespace :admin do 56 | # # Directs /admin/products/* to Admin::ProductsController 57 | # # (app/controllers/admin/products_controller.rb) 58 | # resources :products 59 | # end 60 | end 61 | -------------------------------------------------------------------------------- /spec/dummy4/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: b9534cf1d6b32c759212373d798dde4714e4c97d262bace0935c14607666195cf1f0e5ae10307db809cbebec9cffd9ac15125d4cb265032c48cc9731385319a9 15 | 16 | test: 17 | secret_key_base: d0c21d62451e9aed42658bbaa07bbac349ea37eab8fc5903490fcdffc141d1dac7941827baefde403481920c6b4f01d040d67b30b7f208c501a80fa22fb459d5 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /spec/dummy4/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /spec/dummy4/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/lib/assets/.keep -------------------------------------------------------------------------------- /spec/dummy4/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/lib/tasks/.keep -------------------------------------------------------------------------------- /spec/dummy4/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/log/.keep -------------------------------------------------------------------------------- /spec/dummy4/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/dummy4/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/dummy4/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /spec/dummy4/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/public/favicon.ico -------------------------------------------------------------------------------- /spec/dummy4/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /spec/dummy4/spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV['RAILS_ENV'] ||= 'test' 3 | require File.expand_path('../../config/environment', __FILE__) 4 | # Prevent database truncation if the environment is production 5 | abort("The Rails environment is running in production mode!") if Rails.env.production? 6 | require 'spec_helper' 7 | require 'rspec/rails' 8 | # Add additional requires below this line. Rails is not loaded until this point! 9 | 10 | # Requires supporting ruby files with custom matchers and macros, etc, in 11 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 12 | # run as spec files by default. This means that files in spec/support that end 13 | # in _spec.rb will both be required and run as specs, causing the specs to be 14 | # run twice. It is recommended that you do not name files matching this glob to 15 | # end with _spec.rb. You can configure this pattern with the --pattern 16 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 17 | # 18 | # The following line is provided for convenience purposes. It has the downside 19 | # of increasing the boot-up time by auto-requiring all files in the support 20 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 21 | # require only the support files necessary. 22 | # 23 | # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 24 | 25 | # Checks for pending migrations before tests are run. 26 | # If you are not using ActiveRecord, you can remove this line. 27 | ActiveRecord::Migration.maintain_test_schema! 28 | 29 | RSpec.configure do |config| 30 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 31 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 32 | 33 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 34 | # examples within a transaction, remove the following line or assign false 35 | # instead of true. 36 | config.use_transactional_fixtures = true 37 | 38 | # RSpec Rails can automatically mix in different behaviours to your tests 39 | # based on their file location, for example enabling you to call `get` and 40 | # `post` in specs under `spec/controllers`. 41 | # 42 | # You can disable this behaviour by removing the line below, and instead 43 | # explicitly tag your specs with their type, e.g.: 44 | # 45 | # RSpec.describe UsersController, :type => :controller do 46 | # # ... 47 | # end 48 | # 49 | # The different available types are documented in the features, such as in 50 | # https://relishapp.com/rspec/rspec-rails/docs 51 | config.infer_spec_type_from_file_location! 52 | end 53 | require '../spec_helper.rb' -------------------------------------------------------------------------------- /spec/dummy4/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # The `.rspec` file also contains a few flags that are not defaults but that 16 | # users commonly want. 17 | # 18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 19 | RSpec.configure do |config| 20 | # rspec-expectations config goes here. You can use an alternate 21 | # assertion/expectation library such as wrong or the stdlib/minitest 22 | # assertions if you prefer. 23 | config.expect_with :rspec do |expectations| 24 | # This option will default to `true` in RSpec 4. It makes the `description` 25 | # and `failure_message` of custom matchers include text for helper methods 26 | # defined using `chain`, e.g.: 27 | # be_bigger_than(2).and_smaller_than(4).description 28 | # # => "be bigger than 2 and smaller than 4" 29 | # ...rather than: 30 | # # => "be bigger than 2" 31 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 32 | end 33 | 34 | # rspec-mocks config goes here. You can use an alternate test double 35 | # library (such as bogus or mocha) by changing the `mock_with` option here. 36 | config.mock_with :rspec do |mocks| 37 | # Prevents you from mocking or stubbing a method that does not exist on 38 | # a real object. This is generally recommended, and will default to 39 | # `true` in RSpec 4. 40 | mocks.verify_partial_doubles = true 41 | end 42 | 43 | # The settings below are suggested to provide a good initial experience 44 | # with RSpec, but feel free to customize to your heart's content. 45 | =begin 46 | # These two settings work together to allow you to limit a spec run 47 | # to individual examples or groups you care about by tagging them with 48 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 49 | # get run. 50 | config.filter_run :focus 51 | config.run_all_when_everything_filtered = true 52 | 53 | # Allows RSpec to persist some state between runs in order to support 54 | # the `--only-failures` and `--next-failure` CLI options. We recommend 55 | # you configure your source control system to ignore this file. 56 | config.example_status_persistence_file_path = "spec/examples.txt" 57 | 58 | # Limits the available syntax to the non-monkey patched syntax that is 59 | # recommended. For more details, see: 60 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 61 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 62 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 63 | config.disable_monkey_patching! 64 | 65 | # Many RSpec users commonly either run the entire suite or an individual 66 | # file, and it's useful to allow more verbose output when running an 67 | # individual spec file. 68 | if config.files_to_run.one? 69 | # Use the documentation formatter for detailed output, 70 | # unless a formatter has already been configured 71 | # (e.g. via a command-line flag). 72 | config.default_formatter = 'doc' 73 | end 74 | 75 | # Print the 10 slowest examples and example groups at the 76 | # end of the spec run, to help surface which specs are running 77 | # particularly slow. 78 | config.profile_examples = 10 79 | 80 | # Run specs in random order to surface order dependencies. If you find an 81 | # order dependency and want to debug it, you can fix the order by providing 82 | # the seed, which is printed after each run. 83 | # --seed 1234 84 | config.order = :random 85 | 86 | # Seed global randomization in this process using the `--seed` CLI option. 87 | # Setting this allows you to use `--seed` to deterministically reproduce 88 | # test failures related to randomization by passing the same `--seed` value 89 | # as the one that triggered the failure. 90 | Kernel.srand config.seed 91 | =end 92 | end 93 | -------------------------------------------------------------------------------- /spec/dummy4/test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/test/controllers/.keep -------------------------------------------------------------------------------- /spec/dummy4/test/controllers/notes_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class NotesControllerTest < ActionController::TestCase 4 | setup do 5 | @note = notes(:one) 6 | end 7 | 8 | test "should get index" do 9 | get :index 10 | assert_response :success 11 | assert_not_nil assigns(:notes) 12 | end 13 | 14 | test "should get new" do 15 | get :new 16 | assert_response :success 17 | end 18 | 19 | test "should create note" do 20 | assert_difference('Note.count') do 21 | post :create, note: { body: @note.body } 22 | end 23 | 24 | assert_redirected_to note_path(assigns(:note)) 25 | end 26 | 27 | test "should show note" do 28 | get :show, id: @note 29 | assert_response :success 30 | end 31 | 32 | test "should get edit" do 33 | get :edit, id: @note 34 | assert_response :success 35 | end 36 | 37 | test "should update note" do 38 | patch :update, id: @note, note: { body: @note.body } 39 | assert_redirected_to note_path(assigns(:note)) 40 | end 41 | 42 | test "should destroy note" do 43 | assert_difference('Note.count', -1) do 44 | delete :destroy, id: @note 45 | end 46 | 47 | assert_redirected_to notes_path 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/dummy4/test/fixtures/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/test/fixtures/.keep -------------------------------------------------------------------------------- /spec/dummy4/test/fixtures/notes.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | one: 4 | body: MyString 5 | 6 | two: 7 | body: MyString 8 | -------------------------------------------------------------------------------- /spec/dummy4/test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/test/helpers/.keep -------------------------------------------------------------------------------- /spec/dummy4/test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/test/integration/.keep -------------------------------------------------------------------------------- /spec/dummy4/test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/test/mailers/.keep -------------------------------------------------------------------------------- /spec/dummy4/test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/test/models/.keep -------------------------------------------------------------------------------- /spec/dummy4/test/models/note_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class NoteTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /spec/dummy4/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 7 | fixtures :all 8 | 9 | # Add more helper methods to be used by all tests here... 10 | end 11 | -------------------------------------------------------------------------------- /spec/dummy4/vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /spec/dummy4/vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/dummy4/vendor/assets/stylesheets/.keep -------------------------------------------------------------------------------- /spec/factories.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | 3 | factory :note do 4 | sequence(:body) { |n| "Note ##{n}"} 5 | after(:build) do |note| 6 | note.photo ||= FactoryGirl.build(:file) 7 | end 8 | end 9 | 10 | factory :file, class: Attachinary::File do 11 | sequence(:public_id) { |n| "id#{n}"} 12 | sequence(:version) { |n| "#{n}"} 13 | width 800 14 | height 600 15 | format 'jpg' 16 | resource_type 'image' 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /spec/features/notes_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe 'Notes' do 4 | Capybara.default_wait_time = 15 5 | 6 | describe 'Creating new note' do 7 | 8 | shared_examples_for "any form" do 9 | before do 10 | visit path 11 | end 12 | 13 | it 'display an alert if invalid file format is uploaded', :js => true do 14 | within 'div.photo' do 15 | accept_alert 'Invalid file format' do 16 | attach_file 'note[photo]', "#{SPEC_ROOT}/support/A.txt" 17 | end 18 | end 19 | end 20 | 21 | it 'disables input when first photo is uploaded', :js => true do 22 | within 'div.photo' do 23 | attach_file "note[photo]", "#{SPEC_ROOT}/support/A.gif" 24 | page.should have_css 'input[disabled]' 25 | end 26 | end 27 | 28 | it 'allows multiple images to be uploaded', :js => true do 29 | within 'div.images' do 30 | attach_file "note[images][]", "#{SPEC_ROOT}/support/A.gif" 31 | value = find(:xpath, './/input[@name="note[images][]" and @type="hidden" and contains(@value, \'"A"\')]', :visible => false).value 32 | images = ActiveSupport::JSON.decode( value) 33 | images.length.should be 1 34 | images.map{|i| i["original_filename"]}.should eq ["A"] 35 | 36 | attach_file "note[images][]", "#{SPEC_ROOT}/support/B.gif" 37 | value = find(:xpath, './/input[@name="note[images][]" and @type="hidden" and contains(@value, \'"B"\')]', :visible => false).value 38 | images = ActiveSupport::JSON.decode( value) 39 | images.length.should be 2 40 | images.map{|i| i["original_filename"]}.sort.should eq ["A", "B"] 41 | end 42 | end 43 | 44 | it 'preserves uploaded photo across postbacks', :js => true do 45 | within 'div.photo' do 46 | attach_file "note[photo]", "#{SPEC_ROOT}/support/A.gif" 47 | page.should have_css 'img' 48 | end 49 | 50 | page.should have_button 'Create Note' # wait for it to appear 51 | click_button 'Create Note' 52 | 53 | within 'div.photo' do 54 | page.should have_css 'img' 55 | end 56 | end 57 | 58 | it 'validates presence of photo', :js => true do 59 | click_button 'Create Note' 60 | within 'div.photo' do 61 | page.should have_content "can't be blank" 62 | end 63 | end 64 | 65 | it 'saves the record', :js => true do 66 | fill_in 'note[body]', with: 'My Note' 67 | within 'div.photo' do 68 | attach_file "note[photo]", "#{SPEC_ROOT}/support/A.gif" 69 | end 70 | click_button 'Create Note' 71 | 72 | current_path.should == notes_path 73 | page.should have_content 'My Note' 74 | page.should have_css 'img' 75 | end 76 | 77 | end 78 | 79 | 80 | context 'raw form', :js do 81 | let(:path) { new_note_path(kind: 'raw') } 82 | it_behaves_like "any form" 83 | end 84 | 85 | context 'builder form', :js do 86 | let(:path) { new_note_path(kind: 'builder') } 87 | it_behaves_like "any form" 88 | end 89 | 90 | 91 | context 'simple_form', :js do 92 | let(:path) { new_note_path(kind: 'simple_form') } 93 | it_behaves_like "any form" 94 | end 95 | 96 | end 97 | 98 | end 99 | -------------------------------------------------------------------------------- /spec/models/attachinary/file_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Attachinary::File do 4 | subject { build(:file) } 5 | 6 | describe 'validations' do 7 | it { should be_valid } 8 | it { should_not have_valid(:public_id).when(nil) } 9 | it { should_not have_valid(:version).when(nil) } 10 | it { should_not have_valid(:resource_type).when(nil) } 11 | end 12 | 13 | describe '#path(custom_format=nil)' do 14 | context "image resource_type" do 15 | subject { build(:file, public_id: 'id', version: '1', format: 'jpg', resource_type: 'image') } 16 | 17 | it 'allows you to pick format' do 18 | subject.path.should == 'v1/id.jpg' 19 | subject.path('png').should == 'v1/id.png' 20 | subject.path(false).should == 'v1/id' 21 | end 22 | end 23 | 24 | context "raw resource_type" do 25 | subject { build(:file, public_id: 'id.txt', version: '1', format: '', resource_type: 'raw') } 26 | 27 | it 'ignores the format' do 28 | subject.path.should == 'v1/id.txt' 29 | subject.path('png').should == 'v1/id.txt' 30 | subject.path(false).should == 'v1/id.txt' 31 | end 32 | end 33 | end 34 | 35 | describe '#fullpath(options={})' do 36 | it 'delegates to Cloudinary' do 37 | Cloudinary::Utils.stub(:cloudinary_url).with('v1/id1.png', {resource_type: "image"}).and_return('http_png') 38 | subject.public_id = 'id1' 39 | subject.version = '1' 40 | subject.fullpath(format: 'png').should == 'http_png' 41 | end 42 | end 43 | 44 | end 45 | -------------------------------------------------------------------------------- /spec/models/note_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Note do 4 | subject { build(:note) } 5 | 6 | describe 'validations' do 7 | it { should be_valid } 8 | it { should_not have_valid(:photo).when(nil) } 9 | end 10 | 11 | 12 | describe "callbacks" do 13 | let(:photo) { build(:file) } 14 | 15 | describe "after_destroy" do 16 | after(:each) do 17 | Cloudinary.config.delete_field(:attachinary_keep_remote) if Cloudinary.config.respond_to?(:attachinary_keep_remote) 18 | end 19 | 20 | it "destroys attached files" do 21 | note = create(:note, photo: photo) 22 | Cloudinary::Uploader.should_receive(:destroy).with(photo.public_id) 23 | note.destroy 24 | end 25 | 26 | it "keeps attached files if Cloudinary.config.attachinary_keep_remote == true" do 27 | Cloudinary.config.attachinary_keep_remote = true 28 | note = create(:note, photo: photo) 29 | Cloudinary::Uploader.should_not_receive(:destroy).with(photo.public_id) 30 | note.destroy 31 | end 32 | end 33 | 34 | describe "after_create" do 35 | it "removes attachinary_tmp tag from files" do 36 | Cloudinary::Uploader.should_receive(:remove_tag).with(Attachinary::TMPTAG, [photo.public_id]) 37 | create(:note, photo: photo) 38 | end 39 | end 40 | end 41 | 42 | describe 'photo attachment' do 43 | describe '#photo' do 44 | it 'manages photo' do 45 | photo1 = build(:file) 46 | subject.photo = photo1 47 | subject.photo.should == photo1 48 | 49 | photo2 = build(:file) 50 | subject.photo = photo2 51 | subject.photo.should == photo2 52 | 53 | subject.photo = nil 54 | subject.photo.should be_nil 55 | end 56 | 57 | it 'accepts stringified JSON' do 58 | file = build(:file) 59 | subject.photo = file.to_json 60 | subject.photo.public_id.should == file.public_id 61 | end 62 | 63 | it 'handles invalid JSON from bad browsers (IE)' do 64 | file = build(:file) 65 | subject.photo = "[null]" 66 | subject.photo.should be_nil 67 | end 68 | 69 | it 'accepts IO objects' do 70 | image = StringIO.new("") 71 | file = build(:file) 72 | expected_id = file.public_id 73 | Cloudinary::Uploader.should_receive(:upload).with(image, resource_type: 'auto').and_return(file.attributes) 74 | 75 | subject.photo = image 76 | subject.photo.public_id.should == expected_id 77 | end 78 | end 79 | 80 | describe '#photo_url=(url)' do 81 | let(:url) { "http://placehold.it/100x100" } 82 | let(:file) { build(:file) } 83 | let(:json) { file.attributes.to_json } 84 | 85 | before do 86 | Cloudinary::Uploader.should_receive(:upload).with(url, resource_type: 'auto').and_return(json) 87 | end 88 | 89 | it 'uploads photo via url' do 90 | subject.photo_url = url 91 | subject.photo.public_id.should == file.public_id 92 | end 93 | end 94 | 95 | describe '#photo?' do 96 | it 'checks whether photo is present' do 97 | subject.photo?.should be_truthy 98 | subject.photo = nil 99 | subject.photo?.should be_falsey 100 | end 101 | end 102 | 103 | describe '#photo_metadata' do 104 | it 'returns association metadata' do 105 | subject.photo_metadata[:maximum].should == 1 106 | subject.photo_metadata[:single].should == true 107 | end 108 | end 109 | end 110 | 111 | describe 'image attachments' do 112 | describe '#images' do 113 | it 'manages images' do 114 | subject.images?.should be_falsey 115 | 116 | image1 = build(:file) 117 | subject.images << image1 118 | subject.images.should == [image1] 119 | 120 | image2 = build(:file) 121 | subject.images << image2 122 | subject.images.should == [image1, image2] 123 | 124 | subject.images = nil 125 | subject.images.should be_blank 126 | end 127 | 128 | it 'accepts stringified JSON' do 129 | file = build(:file) 130 | 131 | subject.images = file.to_json 132 | subject.images.first.public_id.should == file.public_id 133 | end 134 | 135 | it 'accepts IO objects' do 136 | images = [1,2].map { StringIO.new("") } 137 | files = build_list(:file, images.length) 138 | files_ids = files.map(&:public_id) 139 | 140 | files.each.with_index do |file, index| 141 | Cloudinary::Uploader.should_receive(:upload).with(images[index], resource_type: 'auto').and_return(file.attributes) 142 | end 143 | 144 | subject.images = images 145 | subject.images.map(&:public_id).should =~ files_ids 146 | end 147 | end 148 | 149 | describe '#image_urls=(urls)' do 150 | let(:urls) { %w[ 1 2 3 ] } 151 | let(:files) { build_list(:file, urls.length) } 152 | let(:files_ids) { files.map(&:public_id)} 153 | 154 | before do 155 | files_ids 156 | files.each.with_index do |file, index| 157 | Cloudinary::Uploader.should_receive(:upload).with(urls[index], resource_type: 'auto').and_return(file.attributes) 158 | end 159 | end 160 | 161 | it 'upload photos via urls' do 162 | subject.image_urls = urls 163 | subject.images.map(&:public_id).should =~ files_ids 164 | end 165 | end 166 | 167 | describe '#images_metadata' do 168 | it 'returns association metadata' do 169 | subject.images_metadata[:single].should == false 170 | end 171 | end 172 | end 173 | end 174 | -------------------------------------------------------------------------------- /spec/orm/active_record.rb: -------------------------------------------------------------------------------- 1 | ActiveRecord::Migration.verbose = false 2 | ActiveRecord::Base.logger = Logger.new(nil) 3 | 4 | ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/") 5 | -------------------------------------------------------------------------------- /spec/orm/mongoid.rb: -------------------------------------------------------------------------------- 1 | Mongoid.logger = Logger.new(nil) 2 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Envinronment 2 | ENV["RAILS_ENV"] = "test" 3 | ATTACHINARY_ORM ||= (ENV["ATTACHINARY_ORM"] || :active_record).to_sym 4 | 5 | # $:.unshift File.dirname(__FILE__) 6 | # require 'rspec/rails' 7 | # require "dummy/config/environment.rb" 8 | SPEC_ROOT = "#{::Rails.root}/.." 9 | require "#{SPEC_ROOT}/orm/#{ATTACHINARY_ORM}" 10 | 11 | require 'valid_attribute' 12 | require 'capybara/rspec' 13 | 14 | require 'factory_girl' 15 | require "#{SPEC_ROOT}/factories" 16 | 17 | require 'database_cleaner' 18 | 19 | require "capybara/webkit" 20 | Capybara.javascript_driver = :webkit 21 | 22 | Capybara::Webkit.configure do |config| 23 | config.allow_url("api.cloudinary.com") 24 | config.allow_url("res.cloudinary.com") 25 | end 26 | 27 | # ENGINE_RAILS_ROOT = File.join(File.dirname(__FILE__), '../') 28 | 29 | # Requires supporting ruby files with custom matchers and macros, etc, 30 | # in spec/support/ and its subdirectories. 31 | # Uncomment next line to load all support files, if you have more than one 32 | # Uncomment next line to load all support files, if you have more than one 33 | # Dir[File.join(ENGINE_RAILS_ROOT, "../../spec/support/**/*.rb")].each {|f| require f } 34 | require "#{SPEC_ROOT}/support/request_helpers" 35 | 36 | RSpec.configure do |config| 37 | config.color = true 38 | config.treat_symbols_as_metadata_keys_with_true_values = true 39 | config.filter_run focus: true 40 | config.run_all_when_everything_filtered = true 41 | 42 | config.use_transactional_fixtures = false 43 | config.include FactoryGirl::Syntax::Methods 44 | config.include RequestHelpers, type: :feature 45 | 46 | config.before(:suite) do 47 | DatabaseCleaner.strategy = :truncation 48 | end 49 | 50 | config.before(:each) do |example| 51 | DatabaseCleaner.start 52 | end 53 | 54 | config.after(:each) do 55 | DatabaseCleaner.clean 56 | end 57 | 58 | config.after(:suite) do 59 | print "\n\n Cleaning up uploaded files" 60 | 61 | begin 62 | Cloudinary::Api.delete_resources_by_tag('test_env') 63 | print " (done)" 64 | rescue Cloudinary::Api::RateLimited => e 65 | print " (#{e.message})" 66 | end 67 | 68 | print "\n\n" 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/support/A.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/support/A.gif -------------------------------------------------------------------------------- /spec/support/A.txt: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /spec/support/B.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/support/B.gif -------------------------------------------------------------------------------- /spec/support/C.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assembler/attachinary/98a895be22edc74b1928ffa3ae116d24bd9818fd/spec/support/C.gif -------------------------------------------------------------------------------- /spec/support/request_helpers.rb: -------------------------------------------------------------------------------- 1 | module RequestHelpers 2 | 3 | def handle_alert 4 | page.execute_script "window.original_alert_function = window.alert" 5 | page.execute_script "window.alert_message = null" 6 | page.execute_script "window.alert = function(msg) { window.alert_message = msg; }" 7 | yield 8 | ensure 9 | page.execute_script "window.alert = window.original_alert_function" 10 | end 11 | 12 | def alert_message 13 | page.evaluate_script "window.alert_message" 14 | end 15 | 16 | end 17 | --------------------------------------------------------------------------------