rails_pallet 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +24 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +69 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +213 -0
- data/Guardfile +11 -0
- data/MIT-LICENSE +20 -0
- data/README.md +233 -0
- data/Rakefile +36 -0
- data/app/assets/images/rails_pallet/.keep +0 -0
- data/app/assets/javascripts/rails_pallet/application.js +13 -0
- data/app/assets/stylesheets/rails_pallet/application.css +15 -0
- data/app/controllers/rails_pallet/application_controller.rb +4 -0
- data/app/controllers/rails_pallet/uploads_controller.rb +19 -0
- data/app/helpers/rails_pallet/application_helper.rb +4 -0
- data/app/models/rails_pallet/upload.rb +61 -0
- data/app/responders/rails_pallet_responder.rb +36 -0
- data/app/serializers/rails_pallet/upload_serializer.rb +3 -0
- data/app/views/layouts/rails_pallet/application.html.erb +14 -0
- data/bin/rails +12 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20150612152328_create_rails_pallet_uploads.rb +7 -0
- data/db/migrate/20150612152417_add_attachment_file_to_uploads.rb +11 -0
- data/lib/generators/rails_pallet/install/USAGE +5 -0
- data/lib/generators/rails_pallet/install/install_generator.rb +21 -0
- data/lib/generators/rails_pallet/install/templates/initializer.rb +9 -0
- data/lib/generators/rails_pallet/upload_controller/USAGE +8 -0
- data/lib/generators/rails_pallet/upload_controller/templates/controller.rb +15 -0
- data/lib/generators/rails_pallet/upload_controller/upload_controller_generator.rb +47 -0
- data/lib/rails_pallet/active_record_extension.rb +78 -0
- data/lib/rails_pallet/engine.rb +5 -0
- data/lib/rails_pallet/version.rb +3 -0
- data/lib/rails_pallet.rb +26 -0
- data/lib/tasks/rails_pallet_tasks.rake +4 -0
- data/paperclip_upload.gemspec +34 -0
- metadata +343 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module RailsPallet
|
2
|
+
class UploadsController < ApplicationController
|
3
|
+
self.responder = RailsPalletResponder
|
4
|
+
respond_to :json
|
5
|
+
|
6
|
+
skip_before_action :verify_authenticity_token
|
7
|
+
|
8
|
+
def create
|
9
|
+
new_upload = RailsPallet::Upload.create(permitted_params)
|
10
|
+
respond_with new_upload, status: :created
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def permitted_params
|
16
|
+
params.permit(:file)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
#
|
3
|
+
# Table name: rails_pallet_uploads
|
4
|
+
#
|
5
|
+
# id :integer not null, primary key
|
6
|
+
# created_at :datetime not null
|
7
|
+
# updated_at :datetime not null
|
8
|
+
# file_file_name :string
|
9
|
+
# file_content_type :string
|
10
|
+
# file_file_size :integer
|
11
|
+
# file_updated_at :datetime
|
12
|
+
#
|
13
|
+
|
14
|
+
module RailsPallet
|
15
|
+
class Upload < ActiveRecord::Base
|
16
|
+
IDENTIFIER_LENGTH = 8
|
17
|
+
|
18
|
+
has_attached_file :file,
|
19
|
+
path: ':rails_root/public/uploads/:identifier/:filename',
|
20
|
+
url: "/uploads/:identifier/:basename.:extension"
|
21
|
+
|
22
|
+
do_not_validate_attachment_file_type :file
|
23
|
+
validates_attachment_presence :file
|
24
|
+
|
25
|
+
def identifier
|
26
|
+
raise "valid with saved instance only" if id.blank?
|
27
|
+
self.class.hashid.encode(id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def file_extension
|
31
|
+
return unless file.exists?
|
32
|
+
File.extname(file.original_filename).split('.').last
|
33
|
+
end
|
34
|
+
|
35
|
+
def file_name
|
36
|
+
return unless file.exists?
|
37
|
+
file_file_name.gsub(".#{file_extension}", "")
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.find_by_identifier(_identifier)
|
41
|
+
decoded_id = identifier_to_id(_identifier)
|
42
|
+
RailsPallet::Upload.find(decoded_id)
|
43
|
+
end
|
44
|
+
|
45
|
+
def download_url
|
46
|
+
file.url
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.hashid
|
50
|
+
Hashids.new(RailsPallet.hash_salt, IDENTIFIER_LENGTH)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.identifier_to_id(_identifier)
|
54
|
+
hashid.decode(_identifier).first
|
55
|
+
end
|
56
|
+
|
57
|
+
Paperclip.interpolates(:identifier) do |attachment, _|
|
58
|
+
attachment.instance.identifier
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class RailsPalletResponder < ActionController::Responder
|
2
|
+
def respond
|
3
|
+
return display_errors if has_errors?
|
4
|
+
return head :no_content if delete?
|
5
|
+
|
6
|
+
display resource, status_code: status_code
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def display(_resource, given_options = {})
|
12
|
+
controller.render options.merge(given_options).merge(json: serializer.as_json)
|
13
|
+
end
|
14
|
+
|
15
|
+
def serializer
|
16
|
+
serializer_class = ActiveModel::Serializer.serializer_for(resource)
|
17
|
+
if serializer_class.present?
|
18
|
+
serializer_class.new(resource, options)
|
19
|
+
else
|
20
|
+
resource
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def status_code
|
25
|
+
return :created if post?
|
26
|
+
:ok
|
27
|
+
end
|
28
|
+
|
29
|
+
def display_errors
|
30
|
+
controller.render(status: :unprocessable_entity, json: { msg: "invalid_attributes", errors: format_errors })
|
31
|
+
end
|
32
|
+
|
33
|
+
def format_errors
|
34
|
+
resource.errors.as_json
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>RailsPallet</title>
|
5
|
+
<%= stylesheet_link_tag "rails_pallet/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "rails_pallet/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/bin/rails
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
|
3
|
+
|
4
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
5
|
+
ENGINE_PATH = File.expand_path('../../lib/rails_pallet/engine', __FILE__)
|
6
|
+
|
7
|
+
# Set up gems listed in the Gemfile.
|
8
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
9
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
10
|
+
|
11
|
+
require 'rails/all'
|
12
|
+
require 'rails/engine/commands'
|
data/config/routes.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
class RailsPallet::InstallGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path('../templates', __FILE__)
|
3
|
+
|
4
|
+
def create_initializer
|
5
|
+
template "initializer.rb", "config/initializers/rails_pallet.rb"
|
6
|
+
end
|
7
|
+
|
8
|
+
def mount_routes
|
9
|
+
line = "Rails.application.routes.draw do"
|
10
|
+
gsub_file "config/routes.rb", /(#{Regexp.escape(line)})/mi do |match|
|
11
|
+
<<-HERE.gsub(/^ {9}/, '')
|
12
|
+
#{match}
|
13
|
+
mount RailsPallet::Engine => '/'
|
14
|
+
HERE
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_engine_migrations
|
19
|
+
rake "railties:install:migrations"
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
RailsPallet.setup do |config|
|
2
|
+
# The upload module uses a salt string to generate an unique hash for each instance.
|
3
|
+
# A salt string can be defined here to replace the default and increase the module's security.
|
4
|
+
# config.hash_salt = "A new and improved string"
|
5
|
+
|
6
|
+
# If true, you will need to pass [host_model_paperclip_attribute_name]_+upload|upload_identifier
|
7
|
+
# instead just "upload" or "upload_identifier" to the host model to use an upload resource.
|
8
|
+
# config.use_prefix = false
|
9
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Description:
|
2
|
+
Allows you to create a custom controller to handle uploads
|
3
|
+
|
4
|
+
Example:
|
5
|
+
rails generate rails_pallet:upload_controller api/attachments api/base
|
6
|
+
|
7
|
+
This will create:
|
8
|
+
a controller inside app/controllers/api/attachments_controller.rb inheriting from the existent app/controllers/api/base_controller.rb
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class UploadController < ApplicationController
|
2
|
+
self.responder = RailsPalletResponder
|
3
|
+
respond_to :json
|
4
|
+
|
5
|
+
def create
|
6
|
+
new_upload = RailsPallet::Upload.create(permitted_params)
|
7
|
+
respond_with new_upload, status: :created
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def permitted_params
|
13
|
+
params.permit(:file)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class RailsPallet::UploadControllerGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path('../templates', __FILE__)
|
3
|
+
argument :base_controller, type: :string, default: "application"
|
4
|
+
|
5
|
+
def generate_controller
|
6
|
+
generate "controller #{resource_path} --no-helper --no-assets --no-view-specs --no-controller-specs"
|
7
|
+
end
|
8
|
+
|
9
|
+
def replace_controller_with_template
|
10
|
+
copy_file "controller.rb", controller_path, force: true
|
11
|
+
end
|
12
|
+
|
13
|
+
def customize_controller
|
14
|
+
line = "class UploadController < ApplicationController"
|
15
|
+
gsub_file controller_path, /(#{Regexp.escape(line)})/mi do
|
16
|
+
"class #{controller_class} < #{base_controller_class}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_routes
|
21
|
+
line = "Rails.application.routes.draw do"
|
22
|
+
gsub_file "config/routes.rb", /(#{Regexp.escape(line)})/mi do |match|
|
23
|
+
<<-HERE.gsub(/^ {9}/, '')
|
24
|
+
#{match}
|
25
|
+
post "#{resource_path}", to: "#{resource_path}#create", defaults: { format: :json }
|
26
|
+
HERE
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def controller_class
|
33
|
+
"#{name.classify.pluralize}Controller"
|
34
|
+
end
|
35
|
+
|
36
|
+
def base_controller_class
|
37
|
+
"#{base_controller.classify}Controller"
|
38
|
+
end
|
39
|
+
|
40
|
+
def controller_path
|
41
|
+
"app/controllers/#{resource_path}_controller.rb"
|
42
|
+
end
|
43
|
+
|
44
|
+
def resource_path
|
45
|
+
name.tableize
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module RailsPallet
|
2
|
+
module ActiveRecordExtension
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class_methods do
|
6
|
+
def has_attached_upload(_paperclip_attr_name, _options = {})
|
7
|
+
load_upload_options(_options)
|
8
|
+
upload_identifier_attr_name = build_upload_attr_name(_paperclip_attr_name, "identifier")
|
9
|
+
upload_attr_name = build_upload_attr_name(_paperclip_attr_name)
|
10
|
+
|
11
|
+
attr_accessor upload_identifier_attr_name, upload_attr_name
|
12
|
+
|
13
|
+
before_validation do
|
14
|
+
identifier = send(upload_identifier_attr_name)
|
15
|
+
|
16
|
+
if identifier
|
17
|
+
found_upload = RailsPallet::Upload.find_by_identifier(identifier)
|
18
|
+
send("#{upload_attr_name}=", found_upload)
|
19
|
+
end
|
20
|
+
|
21
|
+
upload_object = send(upload_attr_name)
|
22
|
+
|
23
|
+
if upload_object
|
24
|
+
if !upload_object.is_a?(RailsPallet::Upload)
|
25
|
+
raise "invalid RailsPallet::Upload instance"
|
26
|
+
end
|
27
|
+
|
28
|
+
send("#{_paperclip_attr_name}=", upload_object.file)
|
29
|
+
upload_object.destroy
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
has_attached_file(_paperclip_attr_name, _options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def allow_encoded_file_for(_paperclip_attr_name)
|
37
|
+
encoded_attr_name = "encoded_#{_paperclip_attr_name}"
|
38
|
+
attr_accessor encoded_attr_name
|
39
|
+
|
40
|
+
before_validation do
|
41
|
+
encoded_attr = send(encoded_attr_name)
|
42
|
+
if encoded_attr
|
43
|
+
headerless_encoded_file = encoded_attr.split(",").last
|
44
|
+
StringIO.open(Base64.decode64(headerless_encoded_file)) do |data|
|
45
|
+
send("#{_paperclip_attr_name}=", data)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def build_upload_attr_name(_paperclip_attr_name, _sufix = nil)
|
54
|
+
if !!upload_options.fetch(:use_prefix, RailsPallet.use_prefix)
|
55
|
+
prefix = _paperclip_attr_name
|
56
|
+
end
|
57
|
+
|
58
|
+
upload_attr_name = [prefix, ["upload", _sufix].compact.join("_")].compact.join("_")
|
59
|
+
|
60
|
+
if self.method_defined?(upload_attr_name)
|
61
|
+
raise "you are trying to redefine #{upload_attr_name} attribute"
|
62
|
+
end
|
63
|
+
|
64
|
+
upload_attr_name
|
65
|
+
end
|
66
|
+
|
67
|
+
def load_upload_options(_options = {})
|
68
|
+
@upload_options = _options.fetch(:upload, {})
|
69
|
+
end
|
70
|
+
|
71
|
+
def upload_options
|
72
|
+
@upload_options ||= {}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
ActiveRecord::Base.send(:include, RailsPallet::ActiveRecordExtension)
|
data/lib/rails_pallet.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "paperclip"
|
2
|
+
require "responders"
|
3
|
+
require 'hashids'
|
4
|
+
require "active_model_serializers"
|
5
|
+
require "rails_pallet/active_record_extension"
|
6
|
+
require "rails_pallet/engine"
|
7
|
+
|
8
|
+
module RailsPallet
|
9
|
+
extend self
|
10
|
+
|
11
|
+
attr_writer :hash_salt, :use_prefix
|
12
|
+
|
13
|
+
def hash_salt
|
14
|
+
return "default" unless @hash_salt
|
15
|
+
@hash_salt
|
16
|
+
end
|
17
|
+
|
18
|
+
def use_prefix
|
19
|
+
@use_prefix == true
|
20
|
+
end
|
21
|
+
|
22
|
+
def setup
|
23
|
+
yield self
|
24
|
+
require "rails_pallet"
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
# Maintain your gem's version:
|
4
|
+
require "rails_pallet/version"
|
5
|
+
|
6
|
+
# Describe your gem and declare its dependencies:
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "rails_pallet"
|
9
|
+
s.version = RailsPallet::VERSION
|
10
|
+
s.authors = ["Leandro Segovia"]
|
11
|
+
s.email = ["ldlsegovia@gmail.com"]
|
12
|
+
s.homepage = "https://github.com/platanus/rails_pallet"
|
13
|
+
s.summary = "Rails engine to save paperclip attachments asynchronously"
|
14
|
+
s.description = "This gem allows you: 1) perform multiple POST requests to create multiple files. 2) relate those files with a model using identifiers instead the files themselves"
|
15
|
+
s.license = "MIT"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split($/).reject { |fn| fn.start_with? "spec" }
|
18
|
+
|
19
|
+
s.add_runtime_dependency 'rails', '~> 4.2', '>= 4.2.1'
|
20
|
+
s.add_runtime_dependency 'hashids', '~> 1.0', '>= 1.0.2'
|
21
|
+
s.add_runtime_dependency 'paperclip', '~> 4.2', '>= 4.2.0'
|
22
|
+
s.add_runtime_dependency 'responders', '~> 2.1', '>= 2.1.0'
|
23
|
+
s.add_dependency "active_model_serializers", "~> 0.9.3"
|
24
|
+
|
25
|
+
s.add_development_dependency 'rspec-rails', '~> 3.2', '>= 3.2.1'
|
26
|
+
s.add_development_dependency "pry-rails", "~> 0.3.3"
|
27
|
+
s.add_development_dependency 'factory_girl_rails', '~> 4.5', '>= 4.5.0'
|
28
|
+
s.add_development_dependency 'shoulda-matchers', '~> 2.8', '>= 2.8.0'
|
29
|
+
s.add_development_dependency 'guard', '~> 2.12', '>= 2.12.5'
|
30
|
+
s.add_development_dependency 'guard-rspec', '~> 4.5', '>= 4.5.0'
|
31
|
+
s.add_development_dependency 'annotate', '~> 2.6', '>= 2.6.6'
|
32
|
+
s.add_development_dependency "sqlite3", '~> 1.3', '>= 1.3.10'
|
33
|
+
s.add_development_dependency "recursive-open-struct", "~> 0.6.4"
|
34
|
+
end
|