image_thread 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 930e6c0b738a5266a59c45cac3d594e51256caee
4
+ data.tar.gz: e3035e6bb80b3d4319d5083ac5c3986815f57767
5
+ SHA512:
6
+ metadata.gz: cf42af7b93564bfdc34535d0798f2281eb23daf371304471deb5ffd3b3d89b49f34b37b8e4f49f65a6a5a05ab809554051930d1f4f4913875fc2f308f841244b
7
+ data.tar.gz: f4cec8f27c0113a48db881e0b25af1f0b23001898a1841f7bfc7fca9e373bcfb9b9ce1417b6195c84da09d75e4e7c1882bbd52cea3a76fb2a9231f0ee9e6d1d9
data/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # ImageThread
2
+
3
+ Gem for multiply file upload (for backend).
4
+
5
+ One thread (thread of images) have many images. Attach thread to your model and
6
+ you get "album"
7
+
8
+ Dependencies:
9
+ 1. carrierwave
10
+ 2. foreigner
11
+
12
+ ## TODOs:
13
+ 1. Single/Multi uploaders
14
+ 2. Validators - size, count, format and etc
15
+ 3. Handle errors
16
+ 4. Customize uploaders
17
+ 5. I18n
18
+ 6. Reorder images in thread
19
+ 7. Placeholder generator for nonexistent files
20
+
21
+ ## Features
22
+ 1. Dynamic thumbs (i.e. thread.image[0].thumb('120x120') or thread.image[0].thumb('300x100!'))
23
+ 2. Settings: remove file on destroy(ex.: has_image_thread :images, delete: :file )
24
+
25
+ ## Examples
26
+
27
+ ## Installation
28
+
29
+ Add this line to your application's Gemfile:
30
+
31
+ gem 'image_thread'
32
+
33
+ And then execute:
34
+
35
+ $ bundle
36
+
37
+ Or install it yourself as:
38
+
39
+ $ gem install image_thread
40
+
41
+ Copy migrations:
42
+
43
+ rails generate image_thread:install
44
+
45
+ Then run this migration.
46
+
47
+ ## Usage
48
+
49
+ ### Setup client-side
50
+ Add js to your manifest file
51
+
52
+ require image_thread
53
+
54
+ If you use custom class for uploader (default: '*.image_thread_fileupload*') require only uploader without init file
55
+
56
+ require image_thread/uploader
57
+
58
+ and init uploader(s):
59
+
60
+ $(function(){
61
+ $('#custom-selector').each(function(){
62
+ $(this).fileupload({
63
+ formData: {
64
+ uploader: $(this).data('uploader'),
65
+ thread: $(this).data('thread'),
66
+ dir: $(this).data('dir')
67
+ },
68
+ inputName: $(this).data('name'),
69
+ previewCrop: true,
70
+ previewMaxWidth: 120,
71
+ previewMaxHeight: 120,
72
+ filesContainer: $(this).closest('.uploader-container').find('.files')
73
+ });
74
+ });
75
+ });
76
+
77
+ ### Add thread to model
78
+ 1. Create filed %{your_thread_name}_id in your model (Link to thread)
79
+ 2. Inside model class add line: has_image_thread :%{your_thread_name}
80
+
81
+ ### Upload files
82
+ 1. In form use this: image_thread_field helper(like text_field etc): form.image_thread_field(:%{your_thread_name}, options)
83
+
84
+ ## Contributing
85
+
86
+ 1. Fork it ( http://github.com/<my-github-username>/image_thread/fork )
87
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
88
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
89
+ 4. Push to the branch (`git push origin my-new-feature`)
90
+ 5. Create new Pull Request
@@ -0,0 +1,22 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record'
4
+
5
+ module ImageThread
6
+ class InstallGenerator < ::Rails::Generators::Base
7
+ include ::Rails::Generators::Migration
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+ class_option :with_changes, :type => :boolean, :default => false, :desc => "Store changeset (diff) with each version"
11
+
12
+ desc 'Generates (but does not run) a migration to add image thread tables.'
13
+
14
+ def create_migration_file
15
+ migration_template 'create_image_thread_tables.rb', 'db/migrate/create_image_thread_tables.rb'
16
+ end
17
+
18
+ def self.next_migration_number(dirname)
19
+ ::ActiveRecord::Generators::Base.next_migration_number(dirname)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ class CreateImageThreadTables < ActiveRecord::Migration
2
+ def up
3
+ create_table :image_thread_threads do |t|
4
+ t.references :default_image, default: nil, comment: 'Reference to default image of thread'
5
+ t.references :owner, comment: 'Thread owner'
6
+ t.datetime :created_at
7
+ end
8
+
9
+ add_index :image_thread_threads, :default_image_id
10
+
11
+ create_table :image_thread_images do |t|
12
+ t.references :thread
13
+ t.string :name, comment: 'Displayed file name'
14
+ t.string :source, null: false, comment: 'Real file name'
15
+ t.string :state, default: 'new', null: false, comment: 'File state: active, new, deleted, archive'
16
+ t.integer :order_pos, default: 0, comment: 'Order position'
17
+ t.string :dir, default: ''
18
+ t.datetime :created_at
19
+ end
20
+
21
+ add_index :image_thread_images, :thread_id
22
+
23
+ add_foreign_key :image_thread_threads, :image_thread_images, column: :default_image_id, dependent: :nullify
24
+ add_foreign_key :image_thread_images, :image_thread_threads, column: :thread_id, dependent: :nullify
25
+ end
26
+
27
+ def down
28
+ remove_foreign_key :image_thread_threads, column: :default_image_id
29
+ remove_foreign_key :image_thread_images, column: :thread_id
30
+
31
+ remove_index :image_thread_threads, :default_image_id
32
+ remove_index :image_thread_images, :thread_id
33
+
34
+ drop_table :image_thread_images
35
+ drop_table :image_thread_threads
36
+ end
37
+ end
@@ -0,0 +1,6 @@
1
+ module ImageThread
2
+ class Engine < ::Rails::Engine
3
+ config.autoload_paths += %W(#{config.root}/lib/**/)
4
+ config.assets.paths += %W(#{config.root}/vendor/assets/fonts/)
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ module ImageThread
2
+ class DifferentThreads < StandardError; end
3
+ class WrongProcessMethod < StandardError; end
4
+ end
@@ -0,0 +1,84 @@
1
+ module ImageThread
2
+ module ModelMethods
3
+
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def has_image_thread(field, opt = {})
10
+ field_id = [field, 'id'].join('_')
11
+ before_save_method = ['append_images', field].join('_')
12
+
13
+ # Options
14
+ delete = opt[:delete] || [] # :row, :files
15
+
16
+
17
+ class_eval do
18
+ belongs_to field, class_name: 'ImageThread::Thread'
19
+ before_save before_save_method.to_sym
20
+
21
+ define_method before_save_method do
22
+ thread_id = nil
23
+ image_ids = instance_variable_get(:"@#{field}_images").map { |i| i[:id] }
24
+
25
+ ImageThread::Image.select('id, thread_id').where(id: image_ids).each do |image|
26
+ if !thread_id.blank? && thread_id != image.thread_id
27
+ raise DifferentThreads, "Try to save images from different thread as one. Image ids: #{image_ids}"
28
+ end
29
+
30
+ thread_id = image.thread_id
31
+ end
32
+
33
+ #TODO: Deactivate images
34
+
35
+ transaction do
36
+ instance_variable_get(:"@#{field}_images").each do |image|
37
+ image = ImageThread::Image.find image[:id]
38
+
39
+ unless image.blank?
40
+ image.update(state: image[:state]) unless image[:state].blank?
41
+
42
+ if state == ImageThread::Image::STATE_DELETED
43
+ # Remove all files
44
+ if delete.include?(:files)
45
+ dir_name = File.dirname(image.source.path)
46
+ file_name = File.basename(image.source.path)
47
+
48
+ Dir.chdir(dir_name)
49
+ Dir.glob(['*', file_name].join).each do |file|
50
+ File.delete File.expand_path(file)
51
+ end
52
+
53
+ File.expand_path image.source
54
+ end
55
+
56
+ # Remove row from DB
57
+ image.destroy if delete.include?(:row) || delete.include?(:files)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
63
+
64
+ _assign_attribute(field_id, thread_id)
65
+ instance_variable_set(:"@#{field}_images", [])
66
+ end
67
+
68
+ define_method [field, 'images='].join('_') do |images|
69
+ res = []
70
+ images.each do |image|
71
+ id, state = image.split(':')
72
+ res << {id: id, state: state}
73
+ end
74
+ instance_variable_set(:"@#{field}_images", res)
75
+ end
76
+
77
+ define_method [field, 'images'].join('_') do
78
+ instance_variable_get(:"@#{field}_images")
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,37 @@
1
+ module ActionView
2
+ module Helpers
3
+ module FormHelper
4
+ def image_thread_field(object_name, method, options = nil)
5
+ tag = ActionView::Helpers::Tags::Base.new(object_name, [method, 'images'].join('_'), self)
6
+ thread = options.delete(:thread)
7
+
8
+ options.update(class: 'image_thread_fileupload')
9
+ options.update(data: { url: '/image_thread/images',
10
+ uploader: [object_name, method, 'uploader', SecureRandom.hex(16)].join('_'),
11
+ thread: thread.to_i,
12
+ dir: options[:dir],
13
+ name: tag.send(:tag_name, true) })
14
+
15
+ template = <<-HTML
16
+ <div class="uploader-container">
17
+ <span class="btn btn-success fileinput-button">
18
+ <span class="glyphicon glyphicon-plus"> Add files</span>
19
+ #{file_field_tag(:source, options)}
20
+ </span>
21
+ <div class="files uploader-#{method} clearfix">#{render_image_thread(thread, tag.send(:tag_name, true))}</div>
22
+ </div>
23
+ HTML
24
+
25
+ template.html_safe
26
+ end
27
+ end
28
+
29
+ class FormBuilder
30
+ def image_thread_field(method, options = {})
31
+ options[:thread] = self.object.send([method, 'id'].join('_'))
32
+ options[:dir] = (options[:dir] || self.object.class.to_s).parameterize('_')
33
+ @template.image_thread_field(@object_name, method, options)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,68 @@
1
+ module ImageThread
2
+ module Uploaders
3
+ class ImageUploader < ::CarrierWave::Uploader::Base
4
+ include CarrierWave::MiniMagick
5
+
6
+ attr_writer :name
7
+
8
+ process resize_to_limit: [2000, 2000]
9
+ process convert: :jpg
10
+
11
+
12
+ def thumb(size)
13
+ uploader = Class.new(self.class)
14
+ ::CarrierWave::Uploader.const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
15
+
16
+ uploader.versions.clear
17
+ uploader.version_names = [size]
18
+
19
+ img = uploader.new(self.model)
20
+ img.retrieve_from_store!(self.file.identifier)
21
+ cached = File.join(CarrierWave.root, img.url)
22
+
23
+ unless File.exist?(cached)
24
+ file.copy_to(cached)
25
+
26
+ size = size.split('x').map(&:to_i)
27
+ resize = case size
28
+ when /!$/ then :resize_to_fit
29
+ when /\#$/ then :resize_to_limit
30
+ else :resize_to_fill
31
+ end
32
+
33
+ img.send resize, *size
34
+ img.name = file.original_filename
35
+ img.store!
36
+ end
37
+
38
+ img
39
+ end
40
+
41
+ def extension_white_list
42
+ %w(jpg jpeg gif png)
43
+ end
44
+
45
+ def filename
46
+ @name ||= "#{secure_token(25)}.jpg" if original_filename.present?
47
+ end
48
+
49
+ def store_dir
50
+ dir = model.dir || 'all'
51
+
52
+ ['uploads', 'images', dir, model.thread_id].join('/')
53
+ end
54
+
55
+ def move_to_store
56
+ true
57
+ end
58
+
59
+ protected
60
+
61
+ def secure_token(length = 20)
62
+ var = :"@#{mounted_as}_secure_token"
63
+ model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.hex(length/2))
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module ImageThread
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,29 @@
1
+ require 'rails/all'
2
+
3
+ require 'carrierwave'
4
+ require 'foreigner'
5
+ require 'migration_comments'
6
+ require 'image_thread/patches/form_helper'
7
+ require 'image_thread/model_methods'
8
+
9
+ module ImageThread
10
+ extend ActiveSupport::Autoload
11
+
12
+ mattr_accessor :image_table_name
13
+ @@image_table_name = :image_thread_images
14
+
15
+ mattr_accessor :thread_table_name
16
+ @@thread_table_name = :image_thread_threads
17
+
18
+ def self.setup
19
+ yield self
20
+ end
21
+ end
22
+
23
+ ActiveSupport.on_load(:active_record) do
24
+ include ImageThread::ModelMethods
25
+ end
26
+
27
+ require 'image_thread/exceptions'
28
+ require 'image_thread/version'
29
+ require 'image_thread/engine'
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: image_thread
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Arthur Shcheglov(fc_arny)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 4.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 4.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: carrierwave
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mini_magick
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: foreigner
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: migration_comments
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Images for models
112
+ email:
113
+ - arthur.shcheglov@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - README.md
119
+ - lib/generators/image_thread/install_generator.rb
120
+ - lib/generators/image_thread/templates/create_image_thread_tables.rb
121
+ - lib/image_thread.rb
122
+ - lib/image_thread/engine.rb
123
+ - lib/image_thread/exceptions.rb
124
+ - lib/image_thread/model_methods.rb
125
+ - lib/image_thread/patches/form_helper.rb
126
+ - lib/image_thread/uploaders/image_uploader.rb
127
+ - lib/image_thread/version.rb
128
+ homepage: http://martsoft.ru/soft/image_thread
129
+ licenses:
130
+ - MIT
131
+ metadata: {}
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubyforge_project:
148
+ rubygems_version: 2.2.2
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: Images for models
152
+ test_files: []
153
+ has_rdoc: