active_archiver 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bcef705dfea7f0005f7b7eb59cce1cd6cd934704
4
- data.tar.gz: d1f50fd1bf33c9ae919a94716dd9a70334d31508
3
+ metadata.gz: e1aa60b9ed13c4fcec274ab0ba54ae740c8c6761
4
+ data.tar.gz: 27d6f63c609c7da615408b3d6fecacdc81011f39
5
5
  SHA512:
6
- metadata.gz: 1f257ece53dd33750e37b8201878b6a59baf1d10df61420a4f9b9e3dc8d64c12f9b1d6bc03a70b9f63398b639f4b5222dab457aabfafe822d6f0212b2d423411
7
- data.tar.gz: 6f841954a95e45166e5b7f6004685f61f80b947ca67aea2b614c1cdb98b71b13d2ea8b1986552b698d458392a4071140725959d72fcee8b9f77fbff362aaba89
6
+ metadata.gz: 99ad9501c2e3ae9f11633b3a5eae1eb2e69ce7367fdb129aeb3d91ec9612071063ffc4f7f00e50def88baa114dfccc1f5057336f0dd6e2a198713ea84fbb6bfd
7
+ data.tar.gz: 6d880ec17fe0b46e38cc97556b531f80fe73a7a526a44c3d653735e584d162060a5b51527a1ad6046fcedd9661586ef4e70e1d854bfd2828ecd4663f462895a3
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.13.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_archiver.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # ActiveArchiver
2
+
3
+ Provide export / import to ActiveRecord and support CarrierWave.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'active_archiver', github:'zaru/active_archiver'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ ## Usage
18
+
19
+ ### sample code
20
+
21
+ ```
22
+ export = User.find(1).export
23
+
24
+ User.find(1).destroy
25
+ User.find(1)
26
+ => ActiveRecord::RecordNotFound: Couldn't find User with 'id'=1
27
+
28
+ User.import(export)
29
+ User.find(1)
30
+ => #<User id: 1, ...>
31
+ ```
32
+
33
+ ### export
34
+
35
+ Returns the specified model object as a hash. Images uploaded with CarrierWave are encoded in Base64.
36
+
37
+ ```ruby
38
+ export = User.last.export
39
+
40
+ => {:attributes=>
41
+ {"id"=>3,
42
+ "last_name"=>"hoge",
43
+ "first_name"=>"piyo",
44
+ "email"=>"hogepiyo@example.com",
45
+ "created_at"=>Sun, 06 Nov 2016 21:04:11 JST +09:00,
46
+ "updated_at"=>Tue, 22 Nov 2016 12:16:28 JST +09:00},
47
+ :associations=>[]}
48
+ ```
49
+
50
+ If you want to export related models as well
51
+
52
+ ```ruby
53
+ export = User.last.export(includes: [:photos])
54
+
55
+ => {:attributes=>
56
+ {"id"=>3,
57
+ "last_name"=>"hoge",
58
+ "first_name"=>"piyo",
59
+ "email"=>"hogepiyo@example.com",
60
+ "created_at"=>Sun, 06 Nov 2016 21:04:11 JST +09:00,
61
+ "updated_at"=>Tue, 22 Nov 2016 12:16:28 JST +09:00},
62
+ :associations=>
63
+ [{:model_name=>"Photo",
64
+ :association_name=>:photos,
65
+ :attributes=>
66
+ {"id"=>57,
67
+ "user_id"=>3,
68
+ "image"=>
69
+ {:url=>"https://example.com/uploads/hoge.png",
70
+ :file_name=>"hoge.png",
71
+ :blob=>
72
+ "data:image/png;base64,iVBORw...
73
+ ```
74
+
75
+ To specify a nested model.
76
+
77
+ ```
78
+ class User < ApplicationRecord
79
+ has_many :photos
80
+ has_many :pets
81
+ end
82
+
83
+ class Pet < ApplicationRecord
84
+ has_many :pet_photos
85
+ end
86
+ ```
87
+
88
+ ```
89
+ export = User.last.export(includes: [:photos, pets:[:pet_photos]])
90
+ ```
91
+
92
+ ### import
93
+
94
+ ```
95
+ User.import(export)
96
+ ```
97
+
98
+ ### archive
99
+
100
+ Write the temporary file.
101
+
102
+ ```
103
+ Hoge.find(1).archive
104
+
105
+ => #<File:/tmp/20161125-12571-ak10w5.json (closed)>
106
+ ```
107
+
108
+ ## Contributing
109
+
110
+ Bug reports and pull requests are welcome on GitHub at https://github.com/zaru/active_archiver.
111
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'active_archiver/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "active_archiver"
8
+ spec.version = ActiveArchiver::VERSION
9
+ spec.authors = ["zaru"]
10
+ spec.email = ["zarutofu@gmail.com"]
11
+
12
+ spec.summary = %q{Provide export / import to ActiveRecord}
13
+ spec.description = %q{Provide export / import to ActiveRecord}
14
+ spec.homepage = "https://github.com/zaru/active_archiver"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord", ">= 4"
22
+ spec.add_dependency "activesupport", ">= 4"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.13"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "active_archiver"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ require "active_archiver/version"
2
+ require "carrierwave/serialization"
3
+ require "active_archiver/base64_decode"
4
+ require "active_archiver/active_record_ext"
5
+
6
+ module ActiveArchiver
7
+ end
8
+
9
+ ActiveSupport.on_load :active_record do
10
+ ActiveRecord::Base.include(ActiveArchiver::ActiveRecordExt)
11
+ end
@@ -0,0 +1,99 @@
1
+ module ActiveArchiver
2
+ module ActiveRecordExt
3
+
4
+ def self.included(model)
5
+ model.extend ClassMethods
6
+ end
7
+
8
+ def export(includes: [])
9
+ CarrierWave::Uploader::Base.active_archiver_blob_data = true
10
+ hash = {}
11
+ hash[:attributes] = self.serializable_hash
12
+ hash[:associations] = []
13
+ hash = recursive_export(hash, self, includes)
14
+ CarrierWave::Uploader::Base.active_archiver_blob_data = false
15
+ hash
16
+ end
17
+
18
+ def archive(includes: [], basename: ["", ".json"], dir: Dir.tmpdir)
19
+ Tempfile.open(basename, dir) do |fp|
20
+ fp.puts export(includes: includes).to_json
21
+ fp
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def recursive_export(hash, receiver, models)
28
+ case models
29
+ when Array
30
+ models.each do |v|
31
+ recursive_export(hash, receiver, v)
32
+ end
33
+ when Hash
34
+ models.each do |k,v|
35
+ recursive_export(hash, receiver, k)
36
+ recursive_export(hash, receiver.send(k), v)
37
+ end
38
+ else
39
+ if receiver.respond_to?(:class_name)
40
+ receiver.each do |rec|
41
+ hash = set_data(hash, rec, models)
42
+ end
43
+ else
44
+ hash = set_data(hash, receiver, models)
45
+ end
46
+ end
47
+
48
+ hash
49
+ end
50
+
51
+ def set_data(hash, receiver, models)
52
+ if receiver.send(models).respond_to?(:class_name)
53
+ model_name = receiver.send(models).class_name
54
+ receiver.send(models).all.each do |r|
55
+ hash[:associations] << data_struct(model_name, models, r.serializable_hash)
56
+ end
57
+ else
58
+ model_name = receiver.send(models).class.class_name
59
+ hash[:associations] << data_struct(model_name, models, receiver.send(models).serializable_hash)
60
+ end
61
+ hash
62
+ end
63
+
64
+ def data_struct(model_name, association_name, attributes)
65
+ {
66
+ model_name: model_name,
67
+ association_name: association_name,
68
+ attributes: attributes
69
+ }
70
+ end
71
+
72
+ module ClassMethods
73
+ def import(hash, validate: false)
74
+ hash = hash.with_indifferent_access
75
+ obj = self.find_or_initialize_by(id: hash["attributes"]["id"])
76
+ obj.attributes = hash["attributes"]
77
+ obj = restore_image(obj, hash)
78
+ obj.save(validate: validate)
79
+
80
+ hash["associations"].each do |r|
81
+ r_obj = Object.const_get(r["model_name"]).find_or_initialize_by(id: r["attributes"]["id"])
82
+ r_obj.attributes = r["attributes"]
83
+ r_obj = restore_image(r_obj, r)
84
+ r_obj.save(validate: validate)
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def restore_image(obj, data)
91
+ blobs = data["attributes"].select{|k,v| v.is_a?(Hash) && v.has_key?("blob") }
92
+ blobs.each do |key, blob|
93
+ obj.send("#{key}=", ActiveArchiver::Base64Decode.create_from_canvas_base64(blob["blob"], blob["file_name"]))
94
+ end
95
+ obj
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,28 @@
1
+ module ActiveArchiver
2
+ class Base64Decode < StringIO
3
+ def self.create_from_canvas_base64(str, file_name)
4
+ return nil if str.nil?
5
+ head, data = str.split(",", 2)
6
+ return nil if data.nil?
7
+ _, mime_type = head.split(/:|;/)
8
+ bin = Base64.decode64(data)
9
+
10
+ self.new(bin, mime_type, file_name)
11
+ end
12
+
13
+ def initialize(blob, content_type, file_name)
14
+ super(blob)
15
+ @content_type = content_type
16
+ @file_name = file_name
17
+ self
18
+ end
19
+
20
+ def original_filename
21
+ @file_name
22
+ end
23
+
24
+ def content_type
25
+ @content_type
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveArchiver
2
+ VERSION = "0.1.3"
3
+ end
@@ -0,0 +1,30 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ class Base
4
+
5
+ @@active_archiver_blob_data = false
6
+
7
+ class << self
8
+ def active_archiver_blob_data=(flag)
9
+ @@active_archiver_blob_data = flag
10
+ end
11
+ end
12
+
13
+ def serializable_hash(options = nil)
14
+ if @@active_archiver_blob_data
15
+ {
16
+ url: url,
17
+ file_name: File.basename(url),
18
+ blob: "data:#{content_type};base64,#{Base64.strict_encode64(read)}"
19
+ }.merge Hash[versions.map { |name, version| [name, {
20
+ url: version.url,
21
+ file_name: File.basename(version.url),
22
+ blob: "data:#{version.content_type};base64,#{Base64.strict_encode64(version.read)}"
23
+ }] }]
24
+ else
25
+ super
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_archiver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - zaru
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
11
  date: 2016-12-05 00:00:00.000000000 Z
12
12
  dependencies:
@@ -86,7 +86,21 @@ email:
86
86
  executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
- files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - README.md
95
+ - Rakefile
96
+ - active_archiver.gemspec
97
+ - bin/console
98
+ - bin/setup
99
+ - lib/active_archiver.rb
100
+ - lib/active_archiver/active_record_ext.rb
101
+ - lib/active_archiver/base64_decode.rb
102
+ - lib/active_archiver/version.rb
103
+ - lib/carrierwave/serialization.rb
90
104
  homepage: https://github.com/zaru/active_archiver
91
105
  licenses: []
92
106
  metadata: {}