attachinary 0.0.8 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -15
- data/Rakefile +10 -1
- data/app/controllers/attachinary/files_controller.rb +1 -1
- data/db/migrate/20120612112526_create_attachinary_tables.rb +3 -7
- data/lib/attachinary.rb +0 -3
- data/lib/attachinary/orm/active_record.rb +5 -0
- data/lib/attachinary/orm/active_record/extension.rb +116 -0
- data/lib/attachinary/orm/active_record/file.rb +6 -0
- data/lib/attachinary/orm/extension.rb +121 -0
- data/{app/models/attachinary/file.rb → lib/attachinary/orm/file_mixin.rb} +6 -13
- data/lib/attachinary/orm/mongoid.rb +5 -0
- data/lib/attachinary/orm/mongoid/extension.rb +90 -0
- data/lib/attachinary/orm/mongoid/file.rb +16 -0
- data/lib/attachinary/simple_form.rb +2 -11
- data/lib/attachinary/version.rb +1 -1
- data/lib/attachinary/view_helpers.rb +6 -6
- data/vendor/assets/javascripts/attachinary.js.coffee +7 -25
- metadata +45 -29
- data/app/models/attachinary/attachment.rb +0 -10
- data/lib/attachinary/active_record_extension.rb +0 -189
data/README.md
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
# Attachinary
|
1
|
+
# Attachinary v1
|
2
|
+
|
3
|
+
_Note: v1 is not backward compatible._
|
2
4
|
|
3
5
|
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!
|
4
6
|
|
5
7
|
Why is Attachinary different:
|
6
8
|
|
7
|
-
*
|
9
|
+
* Supports both **ActiveRecord** and **Mongoid** ORMs!
|
10
|
+
* **No need to alter your model schema** every time you introduce new kind of attachment.
|
8
11
|
* Handles **both has\_one and has\_many** use cases.
|
9
12
|
* **No need for ImageMagick** (or similar) - your thumbnails are generated on the fly by Cloudinary.
|
10
|
-
* Fully customizable,
|
13
|
+
* Fully customizable, custom **jQuery plugin** for async file uploads with previews.
|
11
14
|
* **Files are uploaded directly to Cloudinary** completely bypassing your app (without affecting its performance).
|
12
15
|
* **Very easy to use**. Once set up, 1 line is enough to add attachment support to your model. **No migrations, no Uploaders**.
|
13
|
-
* **Lightweight form submission**. Attachinary handles file upload asynchronously and the only thing that is passed to your server
|
16
|
+
* **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.
|
14
17
|
* All the [benefits of Cloudinary](http://cloudinary.com/documentation/image_transformations) (resizing, cropping, rotating, rounding corners, **face detection**...).
|
15
18
|
|
16
19
|
Attachinary uses [Cloudinary](http://cloudinary.com) service. Gem is structured as mountable rails engine.
|
@@ -18,23 +21,30 @@ Attachinary uses [Cloudinary](http://cloudinary.com) service. Gem is structured
|
|
18
21
|
|
19
22
|
## Installation
|
20
23
|
|
21
|
-
First, make sure that you have [cloudinary gem](https://github.com/cloudinary/cloudinary_gem) installed and properly configured.
|
22
|
-
|
23
|
-
<%= cloudinary_js_config %>
|
24
|
+
First, make sure that you have [cloudinary gem](https://github.com/cloudinary/cloudinary_gem) installed and properly configured.
|
24
25
|
|
25
|
-
|
26
|
+
Add following line to your `Gemfile`:
|
26
27
|
|
27
28
|
gem 'attachinary'
|
28
29
|
|
29
|
-
|
30
|
+
Specify which ORM you wish to use by adding following line to your `application.rb` file (or custom initializer):
|
31
|
+
|
32
|
+
require "attachinary/orm/YOUR_ORM" # active_record or mongoid
|
33
|
+
|
34
|
+
If you're using `ActiveRecord` ORM, then run following lines to generate required table:
|
30
35
|
|
31
36
|
rake attachinary:install:migrations
|
32
37
|
rake db:migrate
|
33
38
|
|
34
|
-
|
39
|
+
Next, add following line in your `routes.rb` file:
|
35
40
|
|
36
41
|
mount Attachinary::Engine => "/attachinary"
|
37
42
|
|
43
|
+
It will generate '/attachinary/cors' which will be used for iframe file transfers (for unsupported browsers).
|
44
|
+
|
45
|
+
Finally, make sure that you have following line in head section of your application layout file:
|
46
|
+
|
47
|
+
<%= cloudinary_js_config %>
|
38
48
|
|
39
49
|
|
40
50
|
|
@@ -44,17 +54,17 @@ Lets say that we want all of our **users** to have single **avatar** and many **
|
|
44
54
|
|
45
55
|
class User < ActiveRecord::Base
|
46
56
|
...
|
47
|
-
has_attachment :avatar, accept: [
|
57
|
+
has_attachment :avatar, accept: [:jpg, :png, :gif]
|
48
58
|
has_attachments :photos, maximum: 10
|
49
59
|
|
50
|
-
validates :
|
60
|
+
validates :avatar, presence: true
|
51
61
|
...
|
52
62
|
end
|
53
63
|
|
54
64
|
In our `_form.html.erb` template, we need to add only this:
|
55
65
|
|
56
|
-
<%= attachinary_file_field_tag 'user[
|
57
|
-
<%= attachinary_file_field_tag 'user[
|
66
|
+
<%= attachinary_file_field_tag 'user[avatar]', user, :avatar %>
|
67
|
+
<%= attachinary_file_field_tag 'user[photos]', user, :photos %>
|
58
68
|
|
59
69
|
If you're using [SimpleForm](https://github.com/plataformatec/simple_form), you can even shorten this to:
|
60
70
|
|
@@ -76,6 +86,7 @@ Attachinary jquery plugin is based upon [jQuery File Upload plugin](https://gith
|
|
76
86
|
|
77
87
|
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.
|
78
88
|
|
89
|
+
|
79
90
|
### Displaying avatar and photos
|
80
91
|
|
81
92
|
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:
|
@@ -96,7 +107,8 @@ Whenever you feel like changing image sizes, you don't need to set rake task tha
|
|
96
107
|
## Conventions
|
97
108
|
|
98
109
|
* always use singular identifier after `has_attachment` (e.g. `has_attachment :photo`)
|
99
|
-
* always use plural identifier after `has_attachments` (e.g. `has_attachments :
|
110
|
+
* always use plural identifier after `has_attachments` (e.g. `has_attachments :images`)
|
111
|
+
* you can't use colliding identifiers (e.g. `has_attachment :photo` and `has_attachments :photos`) on same model.
|
100
112
|
|
101
113
|
|
102
114
|
## Requirements and Compatibility
|
@@ -107,6 +119,12 @@ Whenever you feel like changing image sizes, you don't need to set rake task tha
|
|
107
119
|
* jQuery
|
108
120
|
|
109
121
|
|
122
|
+
### Browser Compatibility
|
123
|
+
|
124
|
+
Attachinary jquery plugin uses JSON2 to generate JSON data.
|
125
|
+
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).
|
126
|
+
|
127
|
+
|
110
128
|
## Credits and License
|
111
129
|
|
112
130
|
Developed by Milovan Zogovic.
|
data/Rakefile
CHANGED
@@ -38,6 +38,15 @@ Bundler::GemHelper.install_tasks
|
|
38
38
|
|
39
39
|
require 'rspec/core/rake_task'
|
40
40
|
RSpec::Core::RakeTask.new(:spec)
|
41
|
-
task :default => :spec
|
42
41
|
|
43
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
|
@@ -14,7 +14,7 @@ module Attachinary
|
|
14
14
|
|
15
15
|
private
|
16
16
|
def file_params
|
17
|
-
request.query_parameters.slice(:public_id, :version, :width, :height, :format, :resource_type)
|
17
|
+
request.query_parameters.slice(:public_id, :version, :width, :height, :format, :resource_type, :scope)
|
18
18
|
end
|
19
19
|
|
20
20
|
end
|
@@ -1,14 +1,9 @@
|
|
1
1
|
class CreateAttachinaryTables < ActiveRecord::Migration
|
2
2
|
def change
|
3
|
-
create_table :
|
4
|
-
t.
|
5
|
-
t.belongs_to :file
|
3
|
+
create_table :attachinary_files do |t|
|
4
|
+
t.references :attachinariable, polymorphic: true
|
6
5
|
t.string :scope
|
7
|
-
t.timestamps
|
8
|
-
end
|
9
|
-
add_index :attachinary_attachments, [:parent_type, :parent_id, :scope], name: 'by_scoped_parent'
|
10
6
|
|
11
|
-
create_table :attachinary_files do |t|
|
12
7
|
t.string :public_id
|
13
8
|
t.string :version
|
14
9
|
t.integer :width
|
@@ -17,5 +12,6 @@ class CreateAttachinaryTables < ActiveRecord::Migration
|
|
17
12
|
t.string :resource_type
|
18
13
|
t.timestamps
|
19
14
|
end
|
15
|
+
add_index :attachinary_files, [:attachinariable_type, :attachinariable_id, :scope], name: 'by_scoped_parent'
|
20
16
|
end
|
21
17
|
end
|
data/lib/attachinary.rb
CHANGED
@@ -0,0 +1,116 @@
|
|
1
|
+
module Attachinary
|
2
|
+
module Extension
|
3
|
+
|
4
|
+
def has_attachment(scope, options={})
|
5
|
+
options[:single] = true
|
6
|
+
attachinary scope, options
|
7
|
+
end
|
8
|
+
|
9
|
+
def has_attachments(scope, options={})
|
10
|
+
options[:single] = false
|
11
|
+
attachinary scope, options
|
12
|
+
end
|
13
|
+
|
14
|
+
def attachinary(scope, options)
|
15
|
+
options.reverse_merge!({
|
16
|
+
accessible: true
|
17
|
+
})
|
18
|
+
|
19
|
+
if options[:single]
|
20
|
+
singular = scope.to_s
|
21
|
+
plural = scope.to_s.pluralize
|
22
|
+
else
|
23
|
+
plural = scope.to_s
|
24
|
+
singular = scope.to_s.singularize
|
25
|
+
end
|
26
|
+
|
27
|
+
relation = "#{singular}_files"
|
28
|
+
|
29
|
+
# has_many :photo_files, ...
|
30
|
+
# has_many :image_files, ...
|
31
|
+
has_many :"#{relation}",
|
32
|
+
as: :attachinariable,
|
33
|
+
class_name: '::Attachinary::File',
|
34
|
+
conditions: { scope: scope.to_s },
|
35
|
+
dependent: :destroy
|
36
|
+
|
37
|
+
# attr_accessible :photo
|
38
|
+
# attr_accessible :images
|
39
|
+
attr_accessible :"#{scope}" if options[:accessible]
|
40
|
+
|
41
|
+
|
42
|
+
# def photo?
|
43
|
+
# photo.present?
|
44
|
+
# end
|
45
|
+
# def images?
|
46
|
+
# images.present?
|
47
|
+
# end
|
48
|
+
define_method :"#{scope}?" do
|
49
|
+
send(:"#{scope}").present?
|
50
|
+
end
|
51
|
+
|
52
|
+
# def photo_metadata
|
53
|
+
# options[:scope] = 'photo'
|
54
|
+
# options[:maximum] = 1 if options[:single]
|
55
|
+
# options
|
56
|
+
# end
|
57
|
+
define_method :"#{scope}_metadata" do
|
58
|
+
options[:scope] = scope
|
59
|
+
options[:maximum] = 1 if options[:single]
|
60
|
+
options
|
61
|
+
end
|
62
|
+
|
63
|
+
# def photo=(file)
|
64
|
+
# if file.blank?
|
65
|
+
# self.photo_files.clear
|
66
|
+
# else
|
67
|
+
# case file
|
68
|
+
# when String
|
69
|
+
# files = ... parse JSON and MAP to array of Attachinary::File ..
|
70
|
+
# self.photo_files = files
|
71
|
+
# else
|
72
|
+
# self.photo_files = [file].flatten
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
define_method "#{scope}=" do |file|
|
77
|
+
if file.blank?
|
78
|
+
send("#{relation}").clear
|
79
|
+
else
|
80
|
+
case file
|
81
|
+
when String
|
82
|
+
files = [JSON.parse(file)].flatten.map do |data|
|
83
|
+
data = data.slice(*Attachinary::File.attr_accessible[:default].to_a)
|
84
|
+
Attachinary::File.new(data) do |f|
|
85
|
+
f.scope = scope.to_s
|
86
|
+
end
|
87
|
+
end
|
88
|
+
send("#{relation}=", files)
|
89
|
+
else
|
90
|
+
send("#{relation}=", [file].flatten)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
if options[:single]
|
97
|
+
# def photo
|
98
|
+
# photo_files.first
|
99
|
+
# end
|
100
|
+
define_method "#{scope}" do
|
101
|
+
send("#{relation}").first
|
102
|
+
end
|
103
|
+
|
104
|
+
else # plural
|
105
|
+
# def images
|
106
|
+
# image_files
|
107
|
+
# end
|
108
|
+
define_method "#{scope}" do
|
109
|
+
send("#{relation}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Attachinary
|
2
|
+
module Extension
|
3
|
+
|
4
|
+
def has_attachment(scope, options={})
|
5
|
+
options[:single] = true
|
6
|
+
attachinary scope, options
|
7
|
+
end
|
8
|
+
|
9
|
+
def has_attachments(scope, options={})
|
10
|
+
options[:single] = false
|
11
|
+
attachinary scope, options
|
12
|
+
end
|
13
|
+
|
14
|
+
def attachinary(scope, options)
|
15
|
+
options.reverse_merge!({
|
16
|
+
accessible: true
|
17
|
+
})
|
18
|
+
|
19
|
+
if options[:single]
|
20
|
+
singular = scope.to_s
|
21
|
+
plural = scope.to_s.pluralize
|
22
|
+
else
|
23
|
+
plural = scope.to_s
|
24
|
+
singular = scope.to_s.singularize
|
25
|
+
end
|
26
|
+
|
27
|
+
relation = "#{singular}_files"
|
28
|
+
|
29
|
+
# # has_many :photo_files, ...
|
30
|
+
# # has_many :image_files, ...
|
31
|
+
# has_many :"#{relation}",
|
32
|
+
# as: :attachinariable,
|
33
|
+
# class_name: '::Attachinary::File',
|
34
|
+
# conditions: { scope: scope.to_s },
|
35
|
+
# dependent: :destroy
|
36
|
+
|
37
|
+
embeds_many :"#{relation}",
|
38
|
+
as: :attachinariable,
|
39
|
+
class_name: '::Attachinary::File',
|
40
|
+
validate: false
|
41
|
+
|
42
|
+
# attr_accessible :photo
|
43
|
+
# attr_accessible :images
|
44
|
+
attr_accessible :"#{scope}" if options[:accessible]
|
45
|
+
|
46
|
+
|
47
|
+
# def photo?
|
48
|
+
# photo.present?
|
49
|
+
# end
|
50
|
+
# def images?
|
51
|
+
# images.present?
|
52
|
+
# end
|
53
|
+
define_method :"#{scope}?" do
|
54
|
+
send(:"#{scope}").present?
|
55
|
+
end
|
56
|
+
|
57
|
+
# def photo_metadata
|
58
|
+
# options[:scope] = 'photo'
|
59
|
+
# options[:maximum] = 1 if options[:single]
|
60
|
+
# options
|
61
|
+
# end
|
62
|
+
define_method :"#{scope}_metadata" do
|
63
|
+
options[:scope] = scope
|
64
|
+
options[:maximum] = 1 if options[:single]
|
65
|
+
options
|
66
|
+
end
|
67
|
+
|
68
|
+
# def photo=(file)
|
69
|
+
# if file.blank?
|
70
|
+
# self.photo_files.clear
|
71
|
+
# else
|
72
|
+
# case file
|
73
|
+
# when String
|
74
|
+
# files = ... parse JSON and MAP to array of Attachinary::File ..
|
75
|
+
# self.photo_files = files
|
76
|
+
# else
|
77
|
+
# self.photo_files = [file].flatten
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
define_method "#{scope}=" do |file|
|
82
|
+
if file.blank?
|
83
|
+
send("#{relation}").clear
|
84
|
+
else
|
85
|
+
case file
|
86
|
+
when String
|
87
|
+
files = [JSON.parse(file)].flatten.map do |data|
|
88
|
+
data = data.slice(*Attachinary::File.attr_accessible[:default].to_a)
|
89
|
+
Attachinary::File.new(data) do |f|
|
90
|
+
f.scope = scope.to_s if f.respond_to?(:scope)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
send("#{relation}=", files)
|
94
|
+
else
|
95
|
+
send("#{relation}=", [file].flatten)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
if options[:single]
|
102
|
+
# def photo
|
103
|
+
# photo_files.first
|
104
|
+
# end
|
105
|
+
define_method "#{scope}" do
|
106
|
+
send("#{relation}").first
|
107
|
+
end
|
108
|
+
|
109
|
+
else # plural
|
110
|
+
# def images
|
111
|
+
# image_files
|
112
|
+
# end
|
113
|
+
define_method "#{scope}" do
|
114
|
+
send("#{relation}")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Attachinary
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
module FileMixin
|
3
|
+
def self.included(base)
|
4
|
+
base.validates :public_id, :version, :resource_type, presence: true
|
5
|
+
base.attr_accessible :public_id, :version, :width, :height, :format, :resource_type
|
6
|
+
base.after_destroy :destroy_file
|
7
|
+
end
|
8
8
|
|
9
9
|
def as_json(options)
|
10
10
|
super(only: [:id, :public_id, :format, :version, :resource_type], methods: [:path])
|
@@ -24,13 +24,6 @@ module Attachinary
|
|
24
24
|
Cloudinary::Utils.cloudinary_url(path(format), options)
|
25
25
|
end
|
26
26
|
|
27
|
-
def self.upload!(file)
|
28
|
-
if file.respond_to?(:read)
|
29
|
-
response = Cloudinary::Uploader.upload(file, tags: "env_#{Rails.env}")
|
30
|
-
create! response.slice('public_id', 'version', 'width', 'height', 'format', 'resource_type')
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
27
|
private
|
35
28
|
def destroy_file
|
36
29
|
Cloudinary::Uploader.destroy(public_id) if public_id
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Attachinary
|
2
|
+
module Extension
|
3
|
+
|
4
|
+
def has_attachment(scope, options={})
|
5
|
+
options[:single] = true
|
6
|
+
attachinary scope, options
|
7
|
+
end
|
8
|
+
|
9
|
+
def has_attachments(scope, options={})
|
10
|
+
options[:single] = false
|
11
|
+
attachinary scope, options
|
12
|
+
end
|
13
|
+
|
14
|
+
def attachinary(scope, options)
|
15
|
+
options.reverse_merge!({
|
16
|
+
accessible: true
|
17
|
+
})
|
18
|
+
|
19
|
+
if options[:single]
|
20
|
+
singular = scope.to_s
|
21
|
+
plural = scope.to_s.pluralize
|
22
|
+
else
|
23
|
+
plural = scope.to_s
|
24
|
+
singular = scope.to_s.singularize
|
25
|
+
end
|
26
|
+
|
27
|
+
if options[:single]
|
28
|
+
# embeds_on :photo, ...
|
29
|
+
embeds_one :"#{scope}", as: :attachinariable, class_name: '::Attachinary::File'
|
30
|
+
else
|
31
|
+
# embeds_many :images, ...
|
32
|
+
embeds_many :"#{scope}", as: :attachinariable, class_name: '::Attachinary::File'
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# attr_accessible :photo
|
37
|
+
# attr_accessible :images
|
38
|
+
attr_accessible :"#{scope}" if options[:accessible]
|
39
|
+
|
40
|
+
# def photo?
|
41
|
+
# photo.present?
|
42
|
+
# end
|
43
|
+
# def images?
|
44
|
+
# images.present?
|
45
|
+
# end
|
46
|
+
define_method :"#{scope}?" do
|
47
|
+
send(:"#{scope}").present?
|
48
|
+
end
|
49
|
+
|
50
|
+
# def photo_metadata
|
51
|
+
# options[:scope] = 'photo'
|
52
|
+
# options[:maximum] = 1 if options[:single]
|
53
|
+
# options
|
54
|
+
# end
|
55
|
+
define_method :"#{scope}_metadata" do
|
56
|
+
options[:scope] = scope
|
57
|
+
options[:maximum] = 1 if options[:single]
|
58
|
+
options
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# alias_method :orig_photo=, :photo=
|
63
|
+
# def photo=(arg)
|
64
|
+
# arg = nil if arg.empty?
|
65
|
+
# if arg.is_a?(String)
|
66
|
+
# files = ... parse JSON and MAP to array of Attachinary::File ..
|
67
|
+
# files = files[0] if options[:singular]
|
68
|
+
# super files
|
69
|
+
# else
|
70
|
+
# super
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
alias_method "orig_#{scope}=", "#{scope}="
|
74
|
+
define_method "#{scope}=" do |arg|
|
75
|
+
arg = nil if arg.respond_to?(:empty?) && arg.empty?
|
76
|
+
|
77
|
+
if arg.is_a?(String)
|
78
|
+
files = [JSON.parse(arg)].flatten.map do |data|
|
79
|
+
data = data.slice(*Attachinary::File.attr_accessible[:default].to_a)
|
80
|
+
Attachinary::File.new(data)
|
81
|
+
end
|
82
|
+
send("orig_#{scope}=", options[:single] ? files[0] : files)
|
83
|
+
else
|
84
|
+
send("orig_#{scope}=", arg)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
@@ -1,18 +1,9 @@
|
|
1
1
|
class AttachinaryInput < SimpleForm::Inputs::Base
|
2
2
|
attr_reader :attachinary_options
|
3
3
|
|
4
|
-
def initialize(builder, attribute_name, column, input_type, options = {})
|
5
|
-
@attachinary_options = builder.object.send("#{attribute_name.to_s.singularize}_options")
|
6
|
-
attribute_name = @attachinary_options[:field_name]
|
7
|
-
|
8
|
-
super builder, attribute_name, column, input_type, options
|
9
|
-
end
|
10
|
-
|
11
4
|
def input
|
12
5
|
name = "#{@builder.object_name}[#{attribute_name}]"
|
13
|
-
|
14
|
-
|
15
|
-
template.attachinary_file_field_tag name, value,
|
16
|
-
{ html: input_html_options, attachinary: attachinary_options }
|
6
|
+
template.attachinary_file_field_tag name, @builder.object, attribute_name,
|
7
|
+
{ html: input_html_options }
|
17
8
|
end
|
18
9
|
end
|
data/lib/attachinary/version.rb
CHANGED
@@ -3,7 +3,9 @@ require 'mime/types'
|
|
3
3
|
module Attachinary
|
4
4
|
module ViewHelpers
|
5
5
|
|
6
|
-
def attachinary_file_field_tag(
|
6
|
+
def attachinary_file_field_tag(field_name, model, relation, options={})
|
7
|
+
options[:attachinary] = model.send("#{relation}_metadata")
|
8
|
+
|
7
9
|
options[:cloudinary] ||= {}
|
8
10
|
options[:cloudinary][:tags] ||= []
|
9
11
|
options[:cloudinary][:tags]<< "#{Rails.env}_env"
|
@@ -33,15 +35,13 @@ module Attachinary
|
|
33
35
|
|
34
36
|
options[:html][:data] ||= {}
|
35
37
|
options[:html][:data][:attachinary] = options[:attachinary] || {}
|
36
|
-
options[:html][:data][:attachinary][:
|
37
|
-
options[:html][:data][:attachinary][:
|
38
|
-
options[:html][:data][:attachinary][:file_field_name] = name.gsub(options[:attachinary][:field_name], options[:attachinary][:file_field_name])
|
39
|
-
options[:html][:data][:attachinary][:field_name] = name
|
38
|
+
options[:html][:data][:attachinary][:files] = [model.send(relation)].compact.flatten
|
39
|
+
options[:html][:data][:attachinary][:field_name] = field_name
|
40
40
|
|
41
41
|
options[:html][:data][:form_data] = cloudinary_params.reject{ |k, v| v.blank? }
|
42
42
|
options[:html][:data][:url] = cloudinary_upload_url
|
43
43
|
|
44
|
-
file_field_tag(
|
44
|
+
file_field_tag('file', options[:html])
|
45
45
|
end
|
46
46
|
|
47
47
|
end
|
@@ -15,7 +15,7 @@
|
|
15
15
|
<img
|
16
16
|
src="<%= $.cloudinary.url(files[i].public_id, { "version": files[i].version, "format": 'jpg', "crop": 'fill', "width": 75, "height": 75 }) %>"
|
17
17
|
alt="" width="75" height="75" />
|
18
|
-
<a href="#" data-remove="<%= files[i].
|
18
|
+
<a href="#" data-remove="<%= files[i].public_id %>">Remove</a>
|
19
19
|
</li>
|
20
20
|
<% } %>
|
21
21
|
</ul>
|
@@ -55,13 +55,12 @@
|
|
55
55
|
if @$input.attr('accept')
|
56
56
|
options.acceptFileTypes = new RegExp("^#{@$input.attr('accept').split(",").join("|")}$", "i")
|
57
57
|
|
58
|
-
@$input.attr('name', 'file')
|
59
58
|
@$input.fileupload(options)
|
60
59
|
|
61
60
|
|
62
61
|
bindEventHandlers: ->
|
63
62
|
@$input.bind 'fileuploaddone', (event, data) =>
|
64
|
-
@
|
63
|
+
setTimeout (=> @addFile(data.result)), 0 # let 'fileuploadalways' finish
|
65
64
|
|
66
65
|
@$input.bind 'fileuploadstart', (event) =>
|
67
66
|
@$input = $(event.target) # important! changed on every file upload
|
@@ -72,9 +71,7 @@
|
|
72
71
|
$form.addClass 'uploading'
|
73
72
|
|
74
73
|
@$input.prop 'disabled', true
|
75
|
-
|
76
74
|
if @config.disableWith
|
77
|
-
$submit.prop 'disabled', true
|
78
75
|
$submit.data 'old-val', $submit.val()
|
79
76
|
$submit.val @config.disableWith
|
80
77
|
|
@@ -86,21 +83,11 @@
|
|
86
83
|
$form.removeClass 'uploading'
|
87
84
|
|
88
85
|
@$input.prop 'disabled', false
|
89
|
-
|
90
86
|
if @config.disableWith
|
91
|
-
$submit.prop 'disabled', false
|
92
87
|
$submit.val $submit.data('old-val')
|
93
88
|
|
94
|
-
|
95
|
-
issueCallback: (data) ->
|
96
|
-
$.ajax
|
97
|
-
url: @options.callback,
|
98
|
-
data: data,
|
99
|
-
success: (file) => @addFile(file)
|
100
|
-
|
101
89
|
addFile: (file) ->
|
102
|
-
|
103
|
-
if !@options.accept || $.inArray(extension, @options.accept) != -1
|
90
|
+
if !@options.accept || $.inArray(file.format, @options.accept) != -1
|
104
91
|
@files.push file
|
105
92
|
@redraw()
|
106
93
|
@checkMaximum()
|
@@ -108,7 +95,7 @@
|
|
108
95
|
alert @config.invalidFormatMessage
|
109
96
|
|
110
97
|
removeFile: (fileIdToRemove) ->
|
111
|
-
@files = (file for file in @files when file.
|
98
|
+
@files = (file for file in @files when file.public_id != fileIdToRemove)
|
112
99
|
@redraw()
|
113
100
|
@checkMaximum()
|
114
101
|
|
@@ -124,11 +111,9 @@
|
|
124
111
|
|
125
112
|
redraw: ->
|
126
113
|
@$filesContainer.empty()
|
127
|
-
@$filesContainer.append @makeHiddenField(null)
|
128
114
|
|
129
115
|
if @files.length > 0
|
130
|
-
|
131
|
-
@$filesContainer.append @makeHiddenField(file.id)
|
116
|
+
@$filesContainer.append @makeHiddenField(JSON.stringify(@files))
|
132
117
|
|
133
118
|
@$filesContainer.append @config.render(@files)
|
134
119
|
@$filesContainer.find('[data-remove]').on 'click', (event) =>
|
@@ -137,15 +122,12 @@
|
|
137
122
|
|
138
123
|
@$filesContainer.show()
|
139
124
|
else
|
125
|
+
@$filesContainer.append @makeHiddenField(null)
|
140
126
|
@$filesContainer.hide()
|
141
127
|
|
142
128
|
makeHiddenField: (value) ->
|
143
129
|
$input = $('<input type="hidden">')
|
144
|
-
|
145
|
-
name = @options.field_name
|
146
|
-
name+= "[]" unless @options.single
|
147
|
-
|
148
|
-
$input.attr 'name', name
|
130
|
+
$input.attr 'name', @options.field_name
|
149
131
|
$input.val value
|
150
132
|
$input
|
151
133
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attachinary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &70213729979420 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.2'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70213729979420
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: cloudinary
|
27
|
-
requirement: &
|
27
|
+
requirement: &70213729994680 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.0.30
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70213729994680
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sqlite3
|
38
|
-
requirement: &
|
38
|
+
requirement: &70213729993740 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70213729993740
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec-rails
|
49
|
-
requirement: &
|
49
|
+
requirement: &70213729992700 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '2.5'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70213729992700
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: valid_attribute
|
60
|
-
requirement: &
|
60
|
+
requirement: &70213729991360 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70213729991360
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: capybara
|
71
|
-
requirement: &
|
71
|
+
requirement: &70213730002500 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70213730002500
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: factory_girl_rails
|
82
|
-
requirement: &
|
82
|
+
requirement: &70213729996140 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '3.0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70213729996140
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: webmock
|
93
|
-
requirement: &
|
93
|
+
requirement: &70213729995080 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70213729995080
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: launchy
|
104
|
-
requirement: &
|
104
|
+
requirement: &70213730007760 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,21 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70213730007760
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: database_cleaner
|
115
|
+
requirement: &70213730006740 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *70213730006740
|
113
124
|
- !ruby/object:Gem::Dependency
|
114
125
|
name: guard-rspec
|
115
|
-
requirement: &
|
126
|
+
requirement: &70213730005440 !ruby/object:Gem::Requirement
|
116
127
|
none: false
|
117
128
|
requirements:
|
118
129
|
- - ! '>='
|
@@ -120,7 +131,7 @@ dependencies:
|
|
120
131
|
version: '0'
|
121
132
|
type: :development
|
122
133
|
prerelease: false
|
123
|
-
version_requirements: *
|
134
|
+
version_requirements: *70213730005440
|
124
135
|
description: Attachments handler for Rails that uses Cloudinary for storage.
|
125
136
|
email:
|
126
137
|
- milovan.zogovic@gmail.com
|
@@ -131,12 +142,17 @@ files:
|
|
131
142
|
- app/controllers/attachinary/application_controller.rb
|
132
143
|
- app/controllers/attachinary/cors_controller.rb
|
133
144
|
- app/controllers/attachinary/files_controller.rb
|
134
|
-
- app/models/attachinary/attachment.rb
|
135
|
-
- app/models/attachinary/file.rb
|
136
145
|
- config/routes.rb
|
137
146
|
- db/migrate/20120612112526_create_attachinary_tables.rb
|
138
|
-
- lib/attachinary/active_record_extension.rb
|
139
147
|
- lib/attachinary/engine.rb
|
148
|
+
- lib/attachinary/orm/active_record/extension.rb
|
149
|
+
- lib/attachinary/orm/active_record/file.rb
|
150
|
+
- lib/attachinary/orm/active_record.rb
|
151
|
+
- lib/attachinary/orm/extension.rb
|
152
|
+
- lib/attachinary/orm/file_mixin.rb
|
153
|
+
- lib/attachinary/orm/mongoid/extension.rb
|
154
|
+
- lib/attachinary/orm/mongoid/file.rb
|
155
|
+
- lib/attachinary/orm/mongoid.rb
|
140
156
|
- lib/attachinary/simple_form.rb
|
141
157
|
- lib/attachinary/version.rb
|
142
158
|
- lib/attachinary/view_helpers.rb
|
@@ -159,7 +175,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
175
|
version: '0'
|
160
176
|
segments:
|
161
177
|
- 0
|
162
|
-
hash:
|
178
|
+
hash: -3340139382106100314
|
163
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
180
|
none: false
|
165
181
|
requirements:
|
@@ -168,11 +184,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
184
|
version: '0'
|
169
185
|
segments:
|
170
186
|
- 0
|
171
|
-
hash:
|
187
|
+
hash: -3340139382106100314
|
172
188
|
requirements: []
|
173
189
|
rubyforge_project:
|
174
|
-
rubygems_version: 1.8.
|
190
|
+
rubygems_version: 1.8.11
|
175
191
|
signing_key:
|
176
192
|
specification_version: 3
|
177
|
-
summary: attachinary-0.0
|
193
|
+
summary: attachinary-1.0.0
|
178
194
|
test_files: []
|
@@ -1,10 +0,0 @@
|
|
1
|
-
module Attachinary
|
2
|
-
class Attachment < ::ActiveRecord::Base
|
3
|
-
belongs_to :parent, polymorphic: true, touch: true
|
4
|
-
belongs_to :file, class_name: 'Attachinary::File', foreign_key: 'file_id'
|
5
|
-
|
6
|
-
validates :parent_id, :parent_type, :scope, presence: true
|
7
|
-
|
8
|
-
attr_accessible :parent_id, :parent_type, :file_id
|
9
|
-
end
|
10
|
-
end
|
@@ -1,189 +0,0 @@
|
|
1
|
-
module Attachinary
|
2
|
-
module ActiveRecordExtension
|
3
|
-
|
4
|
-
def has_attachment(scope, options={})
|
5
|
-
attachinary_apply_defaults!(options)
|
6
|
-
|
7
|
-
# has_one :photo_attachment, ...
|
8
|
-
has_one :"#{scope}_attachment",
|
9
|
-
as: :parent,
|
10
|
-
class_name: '::Attachinary::Attachment',
|
11
|
-
conditions: { scope: scope.to_s },
|
12
|
-
dependent: :destroy
|
13
|
-
|
14
|
-
# has_one :photo_attachment_file, through: :photo_attachment, ...
|
15
|
-
has_one :"#{scope}_attachment_file",
|
16
|
-
through: :"#{scope}_attachment",
|
17
|
-
source: :file
|
18
|
-
|
19
|
-
# attr_accessible :photo_id, :photo_file
|
20
|
-
attr_accessible :"#{scope}_id", :"#{scope}_file" if options[:accessible]
|
21
|
-
|
22
|
-
# attr_writer :photo
|
23
|
-
attr_writer :"#{scope}"
|
24
|
-
|
25
|
-
# def photo
|
26
|
-
# unless defined?(@photo)
|
27
|
-
# @photo = photo_attachment_file
|
28
|
-
# end
|
29
|
-
# @photo
|
30
|
-
# end
|
31
|
-
define_method :"#{scope}" do
|
32
|
-
unless instance_variable_defined? :"@#{scope}"
|
33
|
-
instance_variable_set :"@#{scope}", send(:"#{scope}_attachment_file")
|
34
|
-
end
|
35
|
-
instance_variable_get :"@#{scope}"
|
36
|
-
end
|
37
|
-
|
38
|
-
# def photo_id=(id)
|
39
|
-
# photo = ::Attachinary::File.find_by_id(id)
|
40
|
-
# end
|
41
|
-
define_method :"#{scope}_id=" do |id|
|
42
|
-
send(:"#{scope}=", ::Attachinary::File.find_by_id(id))
|
43
|
-
end
|
44
|
-
|
45
|
-
# def photo_file=(f)
|
46
|
-
# photo = ::Attachinary::File.upload!(f) if f.present?
|
47
|
-
# end
|
48
|
-
define_method :"#{scope}_file=" do |f|
|
49
|
-
send(:"#{scope}=", ::Attachinary::File.upload!(f)) if f.present?
|
50
|
-
end
|
51
|
-
|
52
|
-
# def photo_id
|
53
|
-
# photo.try(:id)
|
54
|
-
# end
|
55
|
-
define_method :"#{scope}_id" do
|
56
|
-
send(:"#{scope}").try(:id)
|
57
|
-
end
|
58
|
-
|
59
|
-
# def photo?
|
60
|
-
# photo.present?
|
61
|
-
# end
|
62
|
-
define_method :"#{scope}?" do
|
63
|
-
send(:"#{scope}").present?
|
64
|
-
end
|
65
|
-
|
66
|
-
# before_save do
|
67
|
-
# photo_attachment_file = photo
|
68
|
-
# end
|
69
|
-
before_save do
|
70
|
-
send(:"#{scope}_attachment_file=", send(:"#{scope}"))
|
71
|
-
end
|
72
|
-
|
73
|
-
# def photo_options
|
74
|
-
# options.merge({
|
75
|
-
# field_name: "photo_id",
|
76
|
-
# maximum: 1
|
77
|
-
# })
|
78
|
-
# end
|
79
|
-
define_method :"#{scope}_options" do
|
80
|
-
options.merge({
|
81
|
-
field_name: "#{scope}_id",
|
82
|
-
file_field_name: "#{scope}_file",
|
83
|
-
single: true,
|
84
|
-
maximum: 1
|
85
|
-
})
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def has_attachments(scope, options={})
|
90
|
-
attachinary_apply_defaults!(options)
|
91
|
-
singular = scope.to_s.singularize
|
92
|
-
|
93
|
-
# has_many :image_attachments
|
94
|
-
has_many :"#{singular}_attachments",
|
95
|
-
as: :parent,
|
96
|
-
class_name: '::Attachinary::Attachment',
|
97
|
-
conditions: { scope: scope.to_s },
|
98
|
-
dependent: :destroy
|
99
|
-
|
100
|
-
# has_many :image_attachment_files, through: :image_attachments
|
101
|
-
has_many :"#{singular}_attachment_files",
|
102
|
-
through: :"#{singular}_attachments",
|
103
|
-
source: :file
|
104
|
-
|
105
|
-
# attr_accessible :image_ids, :image_files
|
106
|
-
attr_accessible :"#{singular}_ids", :"#{singular}_files" if options[:accessible]
|
107
|
-
|
108
|
-
# attr_writer :images
|
109
|
-
attr_writer :"#{scope}"
|
110
|
-
|
111
|
-
# def images
|
112
|
-
# unless defined?(@images)
|
113
|
-
# @images = image_attachment_files
|
114
|
-
# end
|
115
|
-
# @images
|
116
|
-
# end
|
117
|
-
define_method :"#{scope}" do
|
118
|
-
unless instance_variable_defined? :"@#{scope}"
|
119
|
-
instance_variable_set :"@#{scope}", send(:"#{singular}_attachment_files")
|
120
|
-
end
|
121
|
-
instance_variable_get :"@#{scope}"
|
122
|
-
end
|
123
|
-
|
124
|
-
# def image_ids=(ids)
|
125
|
-
# files = [ids].flatten.compact.uniq.reject(&:blank?) do |id|
|
126
|
-
# ::Attachinary::File.find_by_id(id)
|
127
|
-
# end.compact
|
128
|
-
# images = files
|
129
|
-
# end
|
130
|
-
define_method :"#{singular}_ids=" do |ids|
|
131
|
-
files = [ids].flatten.compact.uniq.reject(&:blank?).map do |id|
|
132
|
-
::Attachinary::File.find_by_id(id)
|
133
|
-
end.compact
|
134
|
-
send(:"#{scope}=", files)
|
135
|
-
end
|
136
|
-
|
137
|
-
# def image_files=(fs)
|
138
|
-
# files = fs.map { |f| ::Attachinary::File.upload!(f) }
|
139
|
-
# images = files
|
140
|
-
# end
|
141
|
-
define_method :"#{singular}_files=" do |fs|
|
142
|
-
files = fs.map{ |f| ::Attachinary::File.upload!(f) }.compact
|
143
|
-
send(:"#{scope}=", files)
|
144
|
-
end
|
145
|
-
|
146
|
-
# def image_ids
|
147
|
-
# images.map(&:id)
|
148
|
-
# end
|
149
|
-
define_method :"#{singular}_ids" do
|
150
|
-
send(:"#{scope}").map(&:id)
|
151
|
-
end
|
152
|
-
|
153
|
-
# def images?
|
154
|
-
# images.present?
|
155
|
-
# end
|
156
|
-
define_method :"#{scope}?" do
|
157
|
-
send(:"#{scope}").present?
|
158
|
-
end
|
159
|
-
|
160
|
-
# before_save do
|
161
|
-
# image_attachment_files = images
|
162
|
-
# end
|
163
|
-
before_save do
|
164
|
-
send(:"#{singular}_attachment_files=", send(:"#{scope}"))
|
165
|
-
end
|
166
|
-
|
167
|
-
# def image_options
|
168
|
-
# options.merge({
|
169
|
-
# field_name: "image_ids"
|
170
|
-
# })
|
171
|
-
# end
|
172
|
-
define_method :"#{singular}_options" do
|
173
|
-
options.merge({
|
174
|
-
field_name: "#{singular}_ids",
|
175
|
-
file_field_name: "#{singular}_files",
|
176
|
-
single: false
|
177
|
-
})
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
private
|
182
|
-
def attachinary_apply_defaults!(options)
|
183
|
-
options.reverse_merge!({
|
184
|
-
accessible: true
|
185
|
-
})
|
186
|
-
end
|
187
|
-
|
188
|
-
end
|
189
|
-
end
|