effective_assets 0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +341 -72
  4. data/app/assets/javascripts/effective/snippets/effective_asset.js.coffee +53 -0
  5. data/app/assets/javascripts/effective_assets.js +4 -0
  6. data/app/assets/javascripts/effective_assets/asset_box.js.coffee +36 -0
  7. data/app/assets/javascripts/effective_assets/asset_box_dialog.js.coffee +49 -0
  8. data/app/assets/javascripts/effective_assets/asset_box_drag_and_drop.js.coffee +2 -0
  9. data/app/assets/javascripts/effective_assets/asset_box_filtering.js.coffee +16 -0
  10. data/app/assets/javascripts/effective_assets/asset_box_sorting.js.coffee +8 -0
  11. data/app/assets/javascripts/effective_assets/jquery_ui_sortable.js +813 -585
  12. data/app/assets/javascripts/effective_assets/s3_uploader.js.coffee +268 -0
  13. data/app/assets/javascripts/effective_assets_iframe.js.coffee +28 -0
  14. data/app/assets/stylesheets/active_admin/effective_assets.css.scss +57 -0
  15. data/app/assets/stylesheets/effective_assets/_asset_box_input.scss +54 -175
  16. data/app/assets/stylesheets/effective_assets/_iframe_bootstrap.scss +1714 -0
  17. data/app/assets/stylesheets/effective_assets/_input_bootstrap.scss +508 -0
  18. data/app/assets/stylesheets/effective_assets_iframe.css.scss +23 -0
  19. data/app/controllers/effective/assets_controller.rb +41 -0
  20. data/app/controllers/effective/s3_uploads_controller.rb +58 -74
  21. data/app/helpers/effective_assets_helper.rb +30 -14
  22. data/app/helpers/effective_assets_s3_helper.rb +69 -0
  23. data/app/models/concerns/acts_as_asset_box.rb +75 -11
  24. data/app/models/effective/access_denied.rb +17 -0
  25. data/app/models/effective/asset.rb +130 -93
  26. data/app/models/effective/attachment.rb +2 -7
  27. data/app/models/effective/delayed_job.rb +33 -78
  28. data/app/models/effective/snippets/effective_asset.rb +19 -0
  29. data/app/models/effective/user_uploads.rb +19 -0
  30. data/app/models/inputs/asset_box.rb +154 -0
  31. data/app/models/inputs/asset_box_form_input.rb +7 -0
  32. data/app/models/inputs/asset_box_formtastic_input.rb +9 -0
  33. data/app/models/inputs/asset_box_input.rb +13 -82
  34. data/app/models/inputs/asset_box_simple_form_input.rb +7 -0
  35. data/app/uploaders/effective_assets_uploader.rb +14 -2
  36. data/app/uploaders/{asset_uploader.rb → test_asset_uploader.rb} +1 -1
  37. data/app/views/active_admin/effective_assets/_edit.html.haml +3 -3
  38. data/app/views/active_admin/effective_assets/_new.html.haml +2 -1
  39. data/app/views/asset_box_input/_attachment_as_list.html.haml +17 -0
  40. data/app/views/asset_box_input/_attachment_as_table.html.haml +32 -0
  41. data/app/views/asset_box_input/_attachment_as_thumbnail.html.haml +20 -0
  42. data/app/views/asset_box_input/_dialog.html.haml +18 -0
  43. data/app/views/asset_box_input/_progress_bar_template.html.haml +8 -0
  44. data/app/views/asset_box_input/_uploader.html.haml +21 -115
  45. data/app/views/effective/assets/iframe.html.haml +17 -0
  46. data/app/views/effective/snippets/_effective_asset.html.haml +8 -0
  47. data/config/routes.rb +8 -2
  48. data/db/migrate/01_create_effective_assets.rb.erb +3 -0
  49. data/lib/effective_assets.rb +34 -3
  50. data/lib/effective_assets/engine.rb +11 -8
  51. data/lib/effective_assets/version.rb +1 -1
  52. data/lib/generators/templates/asset_uploader.rb +35 -0
  53. data/lib/generators/templates/effective_assets.rb +31 -4
  54. data/lib/tasks/effective_assets_tasks.rake +115 -4
  55. data/spec/internal/config/database.yml +3 -0
  56. data/spec/internal/config/initializers/effective_assets.rb +18 -0
  57. data/spec/internal/config/routes.rb +3 -0
  58. data/spec/internal/db/combustion_test.sqlite +0 -0
  59. data/spec/internal/db/schema.rb +52 -0
  60. data/spec/internal/log/test.log +793 -0
  61. data/spec/{dummy → internal}/public/favicon.ico +0 -0
  62. data/spec/internal/public/sprites.png +0 -0
  63. data/spec/models/asset_spec.rb +119 -35
  64. data/spec/spec_helper.rb +9 -3
  65. metadata +95 -234
  66. data/app/assets/images/effective_assets/s3_down_button.gif +0 -0
  67. data/app/assets/images/effective_assets/s3_over_button.gif +0 -0
  68. data/app/assets/images/effective_assets/s3_up_button.gif +0 -0
  69. data/app/assets/images/effective_assets/s3_upload.swf +0 -0
  70. data/app/assets/javascripts/effective_assets/asset_box_input.js.coffee +0 -71
  71. data/app/assets/javascripts/effective_assets/asset_box_uploader.js +0 -122
  72. data/app/assets/javascripts/effective_assets/asset_box_uploader_customization.js +0 -166
  73. data/app/controllers/effective/attachments_controller.rb +0 -14
  74. data/app/views/asset_box_input/_attachment_fields.html.haml +0 -14
  75. data/spec/dummy/README.rdoc +0 -261
  76. data/spec/dummy/Rakefile +0 -7
  77. data/spec/dummy/app/assets/javascripts/application.js +0 -15
  78. data/spec/dummy/app/assets/stylesheets/application.css +0 -13
  79. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  80. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  81. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  82. data/spec/dummy/config.ru +0 -4
  83. data/spec/dummy/config/application.rb +0 -65
  84. data/spec/dummy/config/boot.rb +0 -10
  85. data/spec/dummy/config/database.yml +0 -25
  86. data/spec/dummy/config/environment.rb +0 -5
  87. data/spec/dummy/config/environments/development.rb +0 -37
  88. data/spec/dummy/config/environments/production.rb +0 -67
  89. data/spec/dummy/config/environments/test.rb +0 -37
  90. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  91. data/spec/dummy/config/initializers/inflections.rb +0 -15
  92. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  93. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  94. data/spec/dummy/config/initializers/session_store.rb +0 -8
  95. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  96. data/spec/dummy/config/locales/en.yml +0 -5
  97. data/spec/dummy/config/routes.rb +0 -58
  98. data/spec/dummy/db/development.sqlite3 +0 -0
  99. data/spec/dummy/db/schema.rb +0 -16
  100. data/spec/dummy/db/test.sqlite3 +0 -0
  101. data/spec/dummy/log/development.log +0 -71
  102. data/spec/dummy/log/test.log +0 -33
  103. data/spec/dummy/public/404.html +0 -26
  104. data/spec/dummy/public/422.html +0 -26
  105. data/spec/dummy/public/500.html +0 -25
  106. data/spec/dummy/script/rails +0 -6
  107. data/spec/dummy/spec_link +0 -3
@@ -0,0 +1,23 @@
1
+ @import "effective_assets/asset_box_input";
2
+
3
+ body {
4
+ padding: 10px;
5
+ }
6
+
7
+ .form-control.filter-attachments {
8
+ display: inline;
9
+ font-weight: normal;
10
+ width: auto;
11
+ min-width: 50%;
12
+ margin-left: 10px;
13
+ }
14
+
15
+ .asset-box-input.dragin {
16
+ border: 1px solid blue;
17
+ border-radius: 4px;
18
+ border-color: #66afe9;
19
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(102, 175, 233, 0.6);
20
+ outline: 0 none;
21
+ }
22
+
23
+ @import "effective_assets/iframe_bootstrap";
@@ -0,0 +1,41 @@
1
+ # This is basically for the CkEditor Pictures functionality
2
+
3
+ module Effective
4
+ class AssetsController < ApplicationController
5
+ layout false
6
+
7
+ def index # This is the Modal dialog that is read by CKEDITOR
8
+ EffectiveAssets.authorized?(self, :index, Effective::Asset.new(:user_id => current_user.try(:id)))
9
+
10
+ @assets = Effective::Asset.where(:user_id => current_user.try(:id))
11
+ @aws_acl = EffectiveAssets.aws_acl.presence || 'public-read'
12
+
13
+ if params[:only] == 'images'
14
+ @assets = @assets.images
15
+ @file_types = [:jpg, :gif, :png, :bmp, :ico]
16
+ @aws_acl = 'public-read' # The CKEditor Insert Image functionality needs a public-read image here
17
+ elsif params[:only] == 'nonimages'
18
+ @assets = @assets.nonimages
19
+ @file_types = [:pdf, :zip, :doc, :docx, :xls, :xlsx, :txt, :avi, :m4v, :m2v, :mov, :mp3, :mp4]
20
+ end
21
+
22
+ @user_uploads = UserUploads.new(@assets)
23
+
24
+ render :file => 'effective/assets/iframe'
25
+ end
26
+
27
+ def destroy
28
+ @asset = Effective::Asset.find(params[:id])
29
+ EffectiveAssets.authorized?(self, :destroy, @asset)
30
+
31
+ if @asset.destroy
32
+ flash[:success] = 'Successfully deleted asset'
33
+ else
34
+ flash[:danger] = 'Unable to delete asset'
35
+ end
36
+
37
+ redirect_to(:back) rescue redirect_to(effective_assets.effective_assets_path)
38
+ end
39
+
40
+ end
41
+ end
@@ -1,98 +1,82 @@
1
- require 's3_swf_upload'
2
- require 'base64'
3
-
4
1
  module Effective
5
2
  class S3UploadsController < ApplicationController
6
- skip_authorize_resource if defined?(CanCan)
7
-
8
- respond_to :js, :xml
9
-
10
- include S3SwfUpload::Signature
11
-
12
- def index
13
- # This is actually a 'new' action. Not an index. The s3 flash uploader is hardcoded to check this url as an xml request
14
-
15
- EffectiveAssets.authorized?(self, :create, Effective::Asset)
3
+ skip_authorization_check if defined?(CanCan)
4
+ skip_before_filter :verify_authenticity_token
16
5
 
17
- bucket = EffectiveAssets.aws_bucket
18
- access_key_id = EffectiveAssets.aws_access_key_id
19
- acl = EffectiveAssets.aws_acl
20
- secret_key = EffectiveAssets.aws_secret_access_key
21
- key = params[:key]
22
- content_type = params[:content_type]
23
- https = 'false'
24
- error_message = ''
25
- expiration_date = 1.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')
6
+ # When we create an Asset, we're effectively reserving the ID
7
+ # But the Asset itself isn't really there or uploaded yet.
8
+ # But we want to start uploading to the final s3 path
26
9
 
27
- policy = Base64.encode64(
28
- "{
29
- 'expiration': '#{expiration_date}',
30
- 'conditions': [
31
- {'bucket': '#{bucket}'},
32
- {'key': '#{key}'},
33
- {'acl': '#{acl}'},
34
- {'Content-Type': '#{content_type}'},
35
- {'Content-Disposition': 'attachment'},
36
- ['starts-with', '$Filename', ''],
37
- ['eq', '$success_action_status', '201']
38
- ]
39
- }").gsub(/\n|\r/, '')
10
+ def create
11
+ # Here we initialize an empty placeholder Asset, so we can reserve the ID
12
+ @asset = Effective::Asset.new(:user_id => ((current_user.try(:id) || 1) rescue 1), :upload_file => 'placeholder')
13
+ @asset.extra = params[:extra] if params[:extra].kind_of?(Hash)
40
14
 
41
- signature = b64_hmac_sha1(secret_key, policy)
15
+ EffectiveAssets.authorized?(self, :create, @asset)
42
16
 
43
- respond_to do |format|
44
- format.xml {
45
- render :xml => {
46
- :policy => policy,
47
- :signature => signature,
48
- :bucket => bucket,
49
- :accesskeyid => access_key_id,
50
- :acl => acl,
51
- :expirationdate => expiration_date,
52
- :https => https,
53
- :errorMessage => error_message.to_s,
54
- }.to_xml
55
- }
17
+ if @asset.save
18
+ render(:text => {:id => @asset.id, :s3_key => asset_s3_key(@asset)}.to_json, :status => 200)
19
+ else
20
+ render(:text => '', :status => 400)
56
21
  end
57
22
  end
58
23
 
59
- def create
60
- EffectiveAssets.authorized?(self, :create, Effective::Asset)
24
+ def update
25
+ @asset = Effective::Asset.find(params[:id])
61
26
 
62
- # If we're passed Asset information, then create an Asset
63
- if params[:file_path].present?
64
- asset = Asset.create_from_s3_uploader(params[:file_path],
65
- {
66
- :title => params[:title],
67
- :description => params[:description],
68
- :tags => params[:tags],
69
- :content_type => params[:content_type],
70
- :data_size => params[:file_size],
71
- :user_id => current_user.try(:id)
72
- }
73
- )
74
- else
75
- asset = (Asset.find(params[:asset_id].to_i) rescue false)
76
- end
27
+ EffectiveAssets.authorized?(self, :update, @asset)
77
28
 
78
- unless asset
79
- render :text => '', :status => :unprocessable_entity
80
- return
29
+ unless params[:skip_update] # This is useful for the acts_as_asset_box Attach action
30
+ if update_placeholder_asset(@asset, params) == false
31
+ render :text => '', :status => :unprocessable_entity
32
+ return
33
+ end
81
34
  end
82
35
 
83
36
  # If the attachment information is present, then our input needs some attachment HTML
84
- if params.key?(:attachable_type)
85
- attachment = Attachment.new
37
+ if params.key?(:attachable_object_name)
38
+ attachment = Effective::Attachment.new
86
39
  attachment.attachable_type = params[:attachable_type].try(:classify)
87
- attachment.attachable_id = params[:attachable_id].try(:to_i) if params[:attachable_id].present? # attachable_id can be nil if we're on a New action
88
- attachment.asset_id = asset.try(:id)
40
+ attachment.attachable_id = params[:attachable_id].try(:to_i)
41
+ attachment.asset_id = @asset.try(:id)
89
42
  attachment.box = params[:box]
90
43
  attachment.position = 0
44
+ attachable_object_name = params[:attachable_object_name].to_s
45
+ attachment_actions = params[:attachment_actions]
46
+
47
+ attachment_partial =
48
+ case params[:attachment_style].to_s
49
+ when 'table'
50
+ 'attachment_as_table'
51
+ when 'list'
52
+ 'attachment_as_list'
53
+ else # :thumbnail, nil, or anything
54
+ 'attachment_as_thumbnail'
55
+ end
91
56
 
92
- render :partial => 'asset_box_input/attachment_fields', :locals => {:attachment => attachment}, :status => 200, :content_type => 'text/html'
57
+ render :partial => "asset_box_input/#{attachment_partial}", :locals => {:attachment => attachment, :attachable_object_name => attachable_object_name, :attachment_actions => attachment_actions}, :status => 200, :content_type => 'text/html'
93
58
  else
94
59
  render :text => '', :status => 200
95
60
  end
96
61
  end
62
+
63
+ private
64
+
65
+ def update_placeholder_asset(asset, opts)
66
+ asset.upload_file = opts[:upload_file]
67
+ asset.data_size = opts[:data_size]
68
+ asset.content_type = opts[:content_type]
69
+ asset.title = opts[:title]
70
+ asset.aws_acl = opts[:aws_acl]
71
+ asset[:data] = opts[:title]
72
+
73
+ # If our S3 Uploader has any issue uploading/saving the asset, destroy the placeholder empty one
74
+ asset.save ? true : (asset.try(:destroy) and false)
75
+ end
76
+
77
+ def asset_s3_key(asset)
78
+ "#{EffectiveAssets.aws_path.chomp('/')}/#{asset.id.to_i}/${filename}"
79
+ end
80
+
97
81
  end
98
82
  end
@@ -14,42 +14,58 @@ module EffectiveAssetsHelper
14
14
  end
15
15
 
16
16
  opts = opts.merge({:alt => asset.description || asset.title || asset.file_name}).merge(options)
17
- image_tag(_effective_asset_image_url(asset, version), opts).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
17
+
18
+ content_tag(:img, nil, opts.merge(:src => _effective_asset_image_url(asset, version))).gsub('"', "'").html_safe
18
19
  end
19
20
 
20
21
  def effective_asset_link_to(asset, version = nil, options = {})
21
- link_title = asset.title || asset.file_name || asset.description || "Asset ##{asset.id}"
22
+ options_title = options.delete(:title)
23
+ link_title = options_title || asset.title || asset.file_name || asset.description || "Asset ##{asset.id}"
22
24
 
23
- link_to(link_title, asset.url).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
25
+ if asset.image?
26
+ link_to(link_title, _effective_asset_image_url(asset, version), options).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
27
+ else
28
+ link_to(link_title, asset.url, options).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
29
+ end
24
30
  end
25
31
 
26
32
  def effective_asset_video_tag(asset)
27
33
  render(:partial => 'assets/video', :locals => { :asset => asset }).gsub('"', "'").html_safe # we need all ' quotes or it breaks Insert as functionality
28
34
  end
29
35
 
36
+ def effective_asset_title(asset)
37
+ [
38
+ asset.title,
39
+ asset.description,
40
+ asset.tags,
41
+ "Size: #{number_to_human_size(asset.data_size)}",
42
+ "Content Type: #{asset.content_type}"
43
+ ].compact.join("\n")
44
+ end
45
+
30
46
  def _effective_asset_image_url(asset, version = nil)
31
- return '/assets/mime-types/file.png' if !asset.content_type.present? or asset.content_type == 'unknown'
47
+ # asset_url and image_url will work in Rails4
48
+
49
+ return image_path('mime-types/file.png') if !asset.content_type.present? or asset.content_type == 'unknown'
32
50
 
33
51
  if asset.icon?
34
52
  asset.url
35
53
  elsif asset.image?
36
- (version == nil or asset.still_processing?) ? asset.url : asset.url.insert(asset.url.rindex('/')+1, "#{version.to_s}_")
54
+ asset.url(version)
37
55
  elsif asset.audio?
38
- '/assets/mime-types/mp3.png'
56
+ image_path('mime-types/mp3.png')
39
57
  elsif asset.video?
40
- '/assets/mime-types/video.png'
58
+ image_path('mime-types/video.png')
41
59
  elsif asset.content_type.include? 'msword'
42
- '/assets/mime-types/word.jpg'
60
+ image_path('mime-types/word.jpg')
43
61
  elsif asset.content_type.include? 'excel'
44
- '/assets/mime-types/excel.jpg'
62
+ image_path('mime-types/excel.png')
45
63
  elsif asset.content_type.include? 'application/pdf'
46
- '/assets/mime-types/pdf.png'
64
+ image_path('mime-types/pdf.png')
47
65
  elsif asset.content_type.include? 'application/zip'
48
- '/assets/mime-types/zip.png'
66
+ image_path('mime-types/zip.png')
49
67
  else
50
- '/assets/mime-types/file.png'
68
+ image_path('mime-types/file.png')
51
69
  end
52
70
  end
53
-
54
-
55
71
  end
@@ -0,0 +1,69 @@
1
+ module EffectiveAssetsS3Helper
2
+
3
+ def s3_uploader_fields(options = {})
4
+ S3Uploader.new(options).fields.map do |name, value|
5
+ hidden_field_tag(name, value, :disabled => 'disabled')
6
+ end.join.html_safe
7
+ end
8
+
9
+ def s3_uploader_url
10
+ Effective::Asset.s3_base_path.chomp('/') + '/'
11
+ end
12
+
13
+ # Copied and modified from https://github.com/waynehoover/s3_direct_upload/blob/master/lib/s3_direct_upload/form_helper.rb
14
+ class S3Uploader
15
+ def initialize(options)
16
+ @options = options.reverse_merge(
17
+ aws_access_key_id: EffectiveAssets.aws_access_key_id,
18
+ aws_secret_access_key: EffectiveAssets.aws_secret_access_key,
19
+ bucket: EffectiveAssets.aws_bucket,
20
+ aws_acl: EffectiveAssets.aws_acl,
21
+ expiration: 10.hours.from_now.utc.iso8601,
22
+ max_file_size: 1000.megabytes,
23
+ key_starts_with: "#{EffectiveAssets.aws_path.chomp('/')}/",
24
+ key: '${filename}' # We use an AJAX request to update this key to a useful value
25
+ )
26
+ end
27
+
28
+ def fields
29
+ {
30
+ :key => @options[:key],
31
+ :acl => @options[:aws_acl],
32
+ 'AWSAccessKeyId' => @options[:aws_access_key_id],
33
+ :policy => policy,
34
+ :signature => signature,
35
+ :success_action_status => '201',
36
+ 'X-Requested-With' => 'xhr'
37
+ }
38
+ end
39
+
40
+ def policy
41
+ Base64.encode64(policy_data.to_json).gsub("\n", "")
42
+ end
43
+
44
+ def policy_data
45
+ {
46
+ expiration: @options[:expiration],
47
+ conditions: [
48
+ ['starts-with', '$key', @options[:key_starts_with]],
49
+ ['starts-with', '$x-requested-with', ''],
50
+ ['content-length-range', 0, @options[:max_file_size]],
51
+ ['starts-with','$content-type', @options[:content_type_starts_with] || ''],
52
+ {:bucket => @options[:bucket]},
53
+ {:acl => @options[:aws_acl]},
54
+ {:success_action_status => '201'}
55
+ ] + (@options[:conditions] || [])
56
+ }
57
+ end
58
+
59
+ def signature
60
+ Base64.encode64(
61
+ OpenSSL::HMAC.digest(
62
+ OpenSSL::Digest::SHA1.new(),
63
+ @options[:aws_secret_access_key], policy
64
+ )
65
+ ).gsub("\n", "")
66
+ end
67
+ end
68
+
69
+ end
@@ -37,7 +37,6 @@ module ActsAsAssetBox
37
37
  has_many :attachments, :as => :attachable, :class_name => "Effective::Attachment", :dependent => :delete_all
38
38
  has_many :assets, :through => :attachments, :class_name => "Effective::Asset"
39
39
 
40
- #attr_accessible :attachments_attributes
41
40
  accepts_nested_attributes_for :attachments, :reject_if => :all_blank, :allow_destroy => true
42
41
 
43
42
  # Setup validations
@@ -45,9 +44,9 @@ module ActsAsAssetBox
45
44
  if boxes.first.kind_of?(Hash) # We were passed some validation requirements
46
45
  boxes = boxes.first
47
46
 
48
- @@acts_as_asset_box_boxes = boxes.keys
49
-
50
47
  boxes.each do |box, validation|
48
+ self.send(:define_method, box) { assets(box) }
49
+
51
50
  if validation == true
52
51
  validates box, :asset_box_presence => true
53
52
  elsif validation.kind_of?(Integer) or validation.kind_of?(Range)
@@ -55,11 +54,15 @@ module ActsAsAssetBox
55
54
  end
56
55
  end
57
56
  else
58
- @@acts_as_asset_box_boxes = boxes
57
+ boxes.each do |key|
58
+ self.send(:define_method, key) { assets(key) }
59
+ end
59
60
  end
60
61
 
61
62
  class_eval do
62
63
  def attachments_attributes=(atts)
64
+ @last_atts == atts ? return : @last_atts = atts
65
+
63
66
  current_box = ''; position = 0
64
67
 
65
68
  atts.each do |k, v|
@@ -67,7 +70,7 @@ module ActsAsAssetBox
67
70
  atts[k]['position'] = (position += 1) if atts[k]['_destroy'] != '1'
68
71
  end
69
72
 
70
- assign_nested_attributes_for_collection_association(:attachments, atts, {})
73
+ assign_nested_attributes_for_collection_association(:attachments, atts)
71
74
  end
72
75
  end
73
76
  end
@@ -77,11 +80,12 @@ module ActsAsAssetBox
77
80
 
78
81
  def assets(box = nil)
79
82
  box = (box.present? ? box.to_s : 'assets')
83
+ boxes = box.pluralize
80
84
 
81
- if box == box.pluralize
82
- attachments.select { |attachment| attachment.box == box }.map { |attachment| attachment.asset }
85
+ if box == boxes
86
+ attachments.map { |attachment| attachment.asset if attachment.box == boxes }.compact
83
87
  else
84
- attachments.to_a.find { |attachment| attachment.box == box.pluralize }.try(:asset)
88
+ attachments.to_a.find { |attachment| attachment.box == boxes }.try(:asset)
85
89
  end
86
90
  end
87
91
 
@@ -89,9 +93,69 @@ module ActsAsAssetBox
89
93
  assets(:asset)
90
94
  end
91
95
 
92
- # This handles all the boxes type function calls
93
- def method_missing(method_name, *args, &block)
94
- (@@acts_as_asset_box_boxes || []).include?(method_name.to_sym) ? assets(method_name) : super
96
+ def add_to_asset_box(box, *items)
97
+ box = (box.present? ? box.to_s : 'assets')
98
+ boxes = box.pluralize
99
+ items = [items].flatten.compact
100
+
101
+ if items.present? && items.any? { |obj| !obj.kind_of?(Effective::Asset) }
102
+ raise ArgumentError.new('add_to_asset_box expects one or more Effective::Assets, or an Array of Effective::Assets')
103
+ end
104
+
105
+ if box == boxes # If we're adding to a pluralized box, we want to add our attachment onto the end
106
+ pos = attachments.select { |attachment| attachment.box == boxes }.last.try(:position).to_i + 1
107
+ else # If we're adding to a singular box, we want our attachments to be on the front
108
+ pos = attachments.to_a.find { |attachment| attachment.box == boxes }.try(:position).to_i
109
+
110
+ # Push all the attachments forward
111
+ attachments.each { |att| att.position = (att.position + items.length) if att.box == boxes }
112
+ end
113
+
114
+ # Build the attachments
115
+ items.each_with_index do |item, x|
116
+ attachment = self.attachments.build(:position => (pos+x), :box => boxes)
117
+
118
+ attachment.attachable = self
119
+ attachment.asset = item
120
+ end
121
+
122
+ attachments.to_a.sort_by!(&:position)
123
+
124
+ true
125
+ end
126
+
127
+ def add_to_asset_box!(box, *items)
128
+ add_to_asset_box(box, items) && save!
129
+ end
130
+
131
+ # The idea here is that if you want to replace an Asset with Another one
132
+ # the Attachment should keep the same order, and only the asset should change
133
+
134
+ def replace_in_asset_box(box, original, overwrite)
135
+ box = (box.present? ? box.to_s : 'assets')
136
+ boxes = box.pluralize
137
+
138
+ unless original.present? && original.kind_of?(Effective::Asset)
139
+ raise ArgumentError.new("second parameter 'original' must be a single Effective::Asset")
140
+ end
141
+
142
+ unless overwrite.present? && overwrite.kind_of?(Effective::Asset)
143
+ raise ArgumentError.new("third parameter 'overwrite' must be a single Effective::Asset")
144
+ end
145
+
146
+ attachment = attachments.to_a.find { |attachment| attachment.box == boxes && attachment.asset == original }
147
+
148
+ if attachment.present?
149
+ attachment.asset = overwrite
150
+ true
151
+ else
152
+ false
153
+ end
154
+ end
155
+
156
+ def replace_in_asset_box!(box, original, overwrite)
157
+ replace_in_asset_box(box, original, overwrite) && save!
95
158
  end
159
+
96
160
  end
97
161