oss-ar 0.0.1
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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +93 -0
- data/README.md +171 -0
- data/Rakefile +8 -0
- data/lib/oss/adapters/aliyun_adapter.rb +31 -0
- data/lib/oss/adapters/qiniu_adapter.rb +44 -0
- data/lib/oss-activerecord/attachment.rb +137 -0
- data/lib/oss-activerecord/version.rb +5 -0
- data/lib/oss-activerecord.rb +11 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 79aec43def861f705ca99fba23e6272e42beb2285c26c0eb8e49fe1b000ef954
|
4
|
+
data.tar.gz: 4a9d2644fb91513fc45fe10c93d8d6ce3d66afac4c36c12f6b4b8af36681f4d2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b870eb437f04415281f9258511234da6d5b71b2fc1de5a414c678ee5e1752ee7aab98facd3beb59db7edf6830a0a83f0e2d66822e94263bc8aad07c55436eaf4
|
7
|
+
data.tar.gz: 62e94d621972d750cba9f201415911dce13d3e83baaf24ec71bc8a649e0b52d6e9d3669b14c12b17cdbf136cc7b3ab85effbaa32604ab0e8b5e59280298e6414
|
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in oss-activerecord.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem "rake", "~> 13.0"
|
10
|
+
end
|
11
|
+
|
12
|
+
group :test do
|
13
|
+
gem "rspec", "~> 3.0"
|
14
|
+
end
|
15
|
+
|
16
|
+
gem "activerecord", "~> 7.1"
|
17
|
+
gem "sqlite3", "~> 1.4"
|
18
|
+
gem "sorbet-runtime", "~> 0.5.11357"
|
19
|
+
|
20
|
+
gem "aliyun-sdk", "~> 0.8.0"
|
21
|
+
gem "qiniu", "~> 6.9"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
oss-ar (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activemodel (7.1.3.2)
|
10
|
+
activesupport (= 7.1.3.2)
|
11
|
+
activerecord (7.1.3.2)
|
12
|
+
activemodel (= 7.1.3.2)
|
13
|
+
activesupport (= 7.1.3.2)
|
14
|
+
timeout (>= 0.4.0)
|
15
|
+
activesupport (7.1.3.2)
|
16
|
+
base64
|
17
|
+
bigdecimal
|
18
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
19
|
+
connection_pool (>= 2.2.5)
|
20
|
+
drb
|
21
|
+
i18n (>= 1.6, < 2)
|
22
|
+
minitest (>= 5.1)
|
23
|
+
mutex_m
|
24
|
+
tzinfo (~> 2.0)
|
25
|
+
aliyun-sdk (0.8.0)
|
26
|
+
nokogiri (~> 1.6)
|
27
|
+
rest-client (~> 2.0)
|
28
|
+
base64 (0.2.0)
|
29
|
+
bigdecimal (3.1.7)
|
30
|
+
concurrent-ruby (1.2.3)
|
31
|
+
connection_pool (2.4.1)
|
32
|
+
diff-lcs (1.5.1)
|
33
|
+
domain_name (0.6.20240107)
|
34
|
+
drb (2.2.1)
|
35
|
+
http-accept (1.7.0)
|
36
|
+
http-cookie (1.0.5)
|
37
|
+
domain_name (~> 0.5)
|
38
|
+
i18n (1.14.4)
|
39
|
+
concurrent-ruby (~> 1.0)
|
40
|
+
mime-types (3.5.2)
|
41
|
+
mime-types-data (~> 3.2015)
|
42
|
+
mime-types-data (3.2024.0305)
|
43
|
+
minitest (5.22.3)
|
44
|
+
mutex_m (0.2.0)
|
45
|
+
netrc (0.11.0)
|
46
|
+
nokogiri (1.16.4-x86_64-darwin)
|
47
|
+
racc (~> 1.4)
|
48
|
+
qiniu (6.9.1)
|
49
|
+
mime-types (~> 3.1)
|
50
|
+
rest-client (~> 2.0)
|
51
|
+
rexml (~> 3.2)
|
52
|
+
racc (1.7.3)
|
53
|
+
rake (13.2.1)
|
54
|
+
rest-client (2.1.0)
|
55
|
+
http-accept (>= 1.7.0, < 2.0)
|
56
|
+
http-cookie (>= 1.0.2, < 2.0)
|
57
|
+
mime-types (>= 1.16, < 4.0)
|
58
|
+
netrc (~> 0.8)
|
59
|
+
rexml (3.2.6)
|
60
|
+
rspec (3.13.0)
|
61
|
+
rspec-core (~> 3.13.0)
|
62
|
+
rspec-expectations (~> 3.13.0)
|
63
|
+
rspec-mocks (~> 3.13.0)
|
64
|
+
rspec-core (3.13.0)
|
65
|
+
rspec-support (~> 3.13.0)
|
66
|
+
rspec-expectations (3.13.0)
|
67
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
68
|
+
rspec-support (~> 3.13.0)
|
69
|
+
rspec-mocks (3.13.0)
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
71
|
+
rspec-support (~> 3.13.0)
|
72
|
+
rspec-support (3.13.1)
|
73
|
+
sorbet-runtime (0.5.11357)
|
74
|
+
sqlite3 (1.7.3-x86_64-darwin)
|
75
|
+
timeout (0.4.1)
|
76
|
+
tzinfo (2.0.6)
|
77
|
+
concurrent-ruby (~> 1.0)
|
78
|
+
|
79
|
+
PLATFORMS
|
80
|
+
x86_64-darwin-22
|
81
|
+
|
82
|
+
DEPENDENCIES
|
83
|
+
activerecord (~> 7.1)
|
84
|
+
aliyun-sdk (~> 0.8.0)
|
85
|
+
oss-ar!
|
86
|
+
qiniu (~> 6.9)
|
87
|
+
rake (~> 13.0)
|
88
|
+
rspec (~> 3.0)
|
89
|
+
sorbet-runtime (~> 0.5.11357)
|
90
|
+
sqlite3 (~> 1.4)
|
91
|
+
|
92
|
+
BUNDLED WITH
|
93
|
+
2.4.6
|
data/README.md
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# oss-activerecord
|
2
|
+
|
3
|
+
一种用于将国内的云存储服务与 ActiveRecord 集成的解决方案。
|
4
|
+
|
5
|
+
## 写在最前
|
6
|
+
|
7
|
+
该 gem 主要包括两个部分:
|
8
|
+
|
9
|
+
1. 一个 OSS 服务的适配器,将不同的 OSS 服务抽象为统一的接口,方便在不同的 OSS 服务商之间切换。
|
10
|
+
2. 一个 OSS::Attachment 数据表,将 OSS 上传的对象纳入在一个表中管理,方便日后的迁移。
|
11
|
+
|
12
|
+
## 安装
|
13
|
+
|
14
|
+
在 Gemfile 中添加:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'oss-activerecord'
|
18
|
+
```
|
19
|
+
|
20
|
+
然后执行:
|
21
|
+
|
22
|
+
```bash
|
23
|
+
$ bundle
|
24
|
+
```
|
25
|
+
|
26
|
+
最后在 Ruby 项目中引入:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require 'oss-activerecord'
|
30
|
+
```
|
31
|
+
|
32
|
+
## OSS Adapter
|
33
|
+
|
34
|
+
没有为 OSS Adapter 提供一个统一的类,而是提供不同的云厂商的适配器,你可以根据自己的需求选择合适的适配器。(这么做是因为 Ruby 语言不需要)
|
35
|
+
|
36
|
+
目前已支持的 OSS 服务商有:
|
37
|
+
|
38
|
+
- 阿里云 OSS:`OSS::Adapters::AliyunAdapter`
|
39
|
+
- 七牛云 OSS:`OSS::Adapters::QiniuAdapter`
|
40
|
+
|
41
|
+
### 创建 adapter
|
42
|
+
|
43
|
+
创建遵从相同的接口签名,以阿里云 OSS 为例:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
gem "aliyun-sdk"
|
47
|
+
|
48
|
+
require 'oss/adapters/aliyun_adapter'
|
49
|
+
adapter = OSS::Adapters::AliyunAdapter.new(
|
50
|
+
access_key: 'your-access-key-id',
|
51
|
+
secret_key: 'your-access-key-secret',
|
52
|
+
endpoint: 'your-endpoint',
|
53
|
+
bucket: 'your-bucket'
|
54
|
+
)
|
55
|
+
```
|
56
|
+
|
57
|
+
以七牛云 OSS 为例:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
gem "qiniu"
|
61
|
+
|
62
|
+
require 'oss/adapters/qiniu_adapter'
|
63
|
+
adapter = OSS::Adapters::QiniuAdapter.new(
|
64
|
+
access_key: 'your-access-key',
|
65
|
+
secret_key: 'your-secret-key',
|
66
|
+
endpoint: 'your-endpoint',
|
67
|
+
bucket: 'your-bucket'
|
68
|
+
)
|
69
|
+
```
|
70
|
+
|
71
|
+
### 上传文件
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
adapter.upload('path/to/file', 'object-key')
|
75
|
+
```
|
76
|
+
|
77
|
+
### 返回签名 URL
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
adapter.signed_url('object-key')
|
81
|
+
```
|
82
|
+
|
83
|
+
## `OSS::Attachment`
|
84
|
+
|
85
|
+
该模块主要是将所有与云存储对象相关的属性都关联一个表,方便统一管理和日后的迁移。同时,为了维护项目本身的兼容性,也为了适应更常见的需求,该模块将表关联的操作透明化。
|
86
|
+
|
87
|
+
### 创建表
|
88
|
+
|
89
|
+
在使用该模块之前,要求系统中已经存在一个 `oss_attachments` 表,类似的迁移脚本:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
create_table :attachments do |t|
|
93
|
+
t.string :object_key, comment: 'OSS 对象的 key'
|
94
|
+
t.references :attachable, polymorphic: true, comment: '关联的对象'
|
95
|
+
t.string :context, comment: '属性上下文'
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
### 关联模型
|
100
|
+
|
101
|
+
以 `User` 模型为例:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class User < ActiveRecord::Base
|
105
|
+
extend OSS::Attachment::Attachable
|
106
|
+
|
107
|
+
has_one_attached :avatar, :avatar_url
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
该动作创建了一个 `avatar` 关联,同时创建了一个 `avatar_url` 的属性用于兼容性操作。
|
112
|
+
|
113
|
+
### 使用属性 URL
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
user = User.new
|
117
|
+
|
118
|
+
# 保存 URL
|
119
|
+
user.avatar_url = 'object_key' # or full url、full url with signature
|
120
|
+
user.save! # 这一步才会写入数据库
|
121
|
+
|
122
|
+
# 读取 URL
|
123
|
+
user.avatar_url # get full url
|
124
|
+
```
|
125
|
+
|
126
|
+
### has_many_attached
|
127
|
+
|
128
|
+
除了 `has_one_attached` 之外,还支持 `has_many_attached`:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
class User < ActiveRecord::Base
|
132
|
+
extend OSS::Attachment::Attachable
|
133
|
+
|
134
|
+
has_many_attached :photos, :photo_urls
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
此时可以使用 `photo_urls` 进行操作。
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
user = User.new
|
142
|
+
|
143
|
+
# 保存 URL
|
144
|
+
user.photo_urls = ['object_key1', 'object_key2'] # or full urls、full urls with signature
|
145
|
+
user.save! # 这一步才会写入数据库
|
146
|
+
|
147
|
+
# 读取 URL
|
148
|
+
user.photo_urls # get full urls
|
149
|
+
```
|
150
|
+
|
151
|
+
## 开发
|
152
|
+
|
153
|
+
```bash
|
154
|
+
git clone 本仓库
|
155
|
+
|
156
|
+
# 安装依赖项目
|
157
|
+
bundle
|
158
|
+
|
159
|
+
# 运行单元测试
|
160
|
+
bundle exec rspec
|
161
|
+
|
162
|
+
# 生成 gem
|
163
|
+
gem build oss-activerecord.gemspec
|
164
|
+
|
165
|
+
# 推送 gem
|
166
|
+
gem push oss-activerecord-x.x.x.gem
|
167
|
+
```
|
168
|
+
|
169
|
+
## 贡献
|
170
|
+
|
171
|
+
问题报告和 pull requests 在 GitHub 上:https://github.com/[USERNAME]/meta-oss.
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aliyun/oss'
|
4
|
+
|
5
|
+
module OSS
|
6
|
+
module Adapters
|
7
|
+
class AliyunAdapter
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig {params(endpoint: String, access_key: String, secret_key: String, bucket: String).void}
|
11
|
+
def initialize(endpoint:, access_key:, secret_key:, bucket:)
|
12
|
+
@client = Aliyun::OSS::Client.new(
|
13
|
+
endpoint: endpoint,
|
14
|
+
access_key_id: access_key,
|
15
|
+
access_key_secret: secret_key
|
16
|
+
)
|
17
|
+
@bucket = @client.get_bucket(bucket)
|
18
|
+
end
|
19
|
+
|
20
|
+
sig {params(filepath: String, object_key: String).void}
|
21
|
+
def upload(filepath, object_key)
|
22
|
+
@bucket.put_object(object_key, file: filepath)
|
23
|
+
end
|
24
|
+
|
25
|
+
sig {params(object_key: String).returns(String)}
|
26
|
+
def signed_url(object_key)
|
27
|
+
@bucket.object_url(object_key, true, 60)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'qiniu'
|
4
|
+
|
5
|
+
module OSS
|
6
|
+
module Adapters
|
7
|
+
class QiniuAdapter
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig {params(endpoint: String, access_key: String, secret_key: String, bucket: String).void}
|
11
|
+
def initialize(endpoint: ,access_key:, secret_key:, bucket:)
|
12
|
+
Qiniu.establish_connection! access_key: access_key, secret_key: secret_key
|
13
|
+
@endpoint = endpoint
|
14
|
+
@bucket = bucket
|
15
|
+
end
|
16
|
+
|
17
|
+
sig {params(filepath: String, object_key: String).void}
|
18
|
+
def upload(filepath, object_key)
|
19
|
+
# 构建上传策略,上传策略的更多参数请参照 http://developer.qiniu.com/article/developer/security/put-policy.html
|
20
|
+
put_policy = Qiniu::Auth::PutPolicy.new(
|
21
|
+
@bucket, # 存储空间
|
22
|
+
object_key, # 指定上传的资源名,如果传入 nil,就表示不指定资源名,将使用默认的资源名
|
23
|
+
3600 # token 过期时间,默认为 3600 秒,即 1 小时
|
24
|
+
)
|
25
|
+
# 生成上传 Token
|
26
|
+
uptoken = Qiniu::Auth.generate_uptoken(put_policy)
|
27
|
+
# 调用 upload_with_token_2 方法上传
|
28
|
+
Qiniu::Storage.upload_with_token_2(
|
29
|
+
uptoken,
|
30
|
+
filepath,
|
31
|
+
object_key,
|
32
|
+
nil, # 可以接受一个 Hash 作为自定义变量,请参照 http://developer.qiniu.com/article/kodo/kodo-developer/up/vars.html#xvar
|
33
|
+
bucket: @bucket
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
sig {params(object_key: String).returns(String)}
|
38
|
+
def signed_url(object_key)
|
39
|
+
primitive_url = File.join(@endpoint, object_key)
|
40
|
+
Qiniu::Auth.authorize_download_url(primitive_url)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module OSS
|
6
|
+
class Attachment < ActiveRecord::Base
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
self.primary_key = :object_key
|
10
|
+
|
11
|
+
validates :object_key, presence: true, uniqueness: { scope: %i[attachable_id attachable_type context] }
|
12
|
+
|
13
|
+
belongs_to :attachable, polymorphic: true, optional: false, autosave: true
|
14
|
+
|
15
|
+
sig {returns(T.nilable(String))}
|
16
|
+
def url
|
17
|
+
return object_key if object_key.nil? || full_url?(object_key)
|
18
|
+
|
19
|
+
if self.class.use_signed_url
|
20
|
+
self.class.oss_adapter.signed_url(object_key)
|
21
|
+
else
|
22
|
+
File.join(self.class.endpoint, object_key)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
sig {params(url: T.nilable(String)).void}
|
27
|
+
def url=(url)
|
28
|
+
if url.nil?
|
29
|
+
self.object_key = nil
|
30
|
+
else
|
31
|
+
self.object_key = self.class.resolve_object_key(url)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def full_url?(url)
|
38
|
+
url.start_with?(%r{https?://})
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
extend T::Sig
|
43
|
+
|
44
|
+
attr_accessor :endpoint, :use_signed_url, :oss_adapter
|
45
|
+
|
46
|
+
sig {params(object_key: String, filepath: String).returns(String)}
|
47
|
+
def upload(object_key, filepath)
|
48
|
+
oss_adapter.upload(object_key, filepath)
|
49
|
+
end
|
50
|
+
|
51
|
+
sig {params(object_key: String).returns(String)}
|
52
|
+
def signed_url(object_key)
|
53
|
+
oss_adapter.signed_url(object_key)
|
54
|
+
end
|
55
|
+
|
56
|
+
sig {params(url: String).returns(String)}
|
57
|
+
def resolve_object_key(url)
|
58
|
+
return url unless descendant_of_endpoint?(url)
|
59
|
+
|
60
|
+
# 首先去掉 url 的 query 部分
|
61
|
+
url = url.split('?').first
|
62
|
+
# 然后获取相对路径
|
63
|
+
p = Pathname.new(url).relative_path_from(Pathname.new(endpoint))
|
64
|
+
|
65
|
+
p.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
sig {params(object_key: String).returns(String)}
|
69
|
+
def resolve_full_url(object_key)
|
70
|
+
return object_key if object_key.nil? || full_url?(object_key)
|
71
|
+
|
72
|
+
if use_signed_url
|
73
|
+
oss_adapter.signed_url(object_key)
|
74
|
+
else
|
75
|
+
File.join(endpoint, object_key)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def full_url?(url)
|
82
|
+
url.start_with?(%r{https?://})
|
83
|
+
end
|
84
|
+
|
85
|
+
def descendant_of_endpoint?(url)
|
86
|
+
endpoint = self.endpoint
|
87
|
+
|
88
|
+
# 确保尾部有斜杠
|
89
|
+
endpoint = "#{endpoint}/" unless endpoint.end_with?('/')
|
90
|
+
url = "#{url}/" unless url.end_with?('/')
|
91
|
+
|
92
|
+
# 检查 url 是否是 endpoint 的子路径
|
93
|
+
url.start_with?(endpoint)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
module Attachable
|
98
|
+
extend T::Sig
|
99
|
+
|
100
|
+
sig {params(association_name: Symbol, attribute_name: Symbol).void}
|
101
|
+
def has_one_attached(association_name, attribute_name)
|
102
|
+
has_one association_name, ->{ where(context: association_name) }, class_name: 'OSS::Attachment', as: :attachable
|
103
|
+
|
104
|
+
define_method("#{attribute_name}=") do |url|
|
105
|
+
attachment = send(association_name) || Attachment.new(context: association_name)
|
106
|
+
object_key = Attachment.resolve_object_key(url)
|
107
|
+
attachment.object_key = object_key
|
108
|
+
send("#{association_name}=", attachment)
|
109
|
+
end
|
110
|
+
|
111
|
+
define_method(attribute_name) do
|
112
|
+
record = send(association_name)
|
113
|
+
record&.url
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
sig {params(association_name: Symbol, attribute_name: Symbol).void}
|
118
|
+
def has_many_attached(association_name, attribute_name)
|
119
|
+
has_many association_name, ->{ where context: association_name }, class_name: 'OSS::Attachment', as: :attachable, dependent: :delete_all, validate: false
|
120
|
+
|
121
|
+
define_method("#{attribute_name}=") do |urls|
|
122
|
+
object_keys = urls.map { |url| Attachment.resolve_object_key(url) }
|
123
|
+
|
124
|
+
attachments = object_keys.map do |object_key|
|
125
|
+
Attachment.new(context: association_name, object_key: object_key)
|
126
|
+
end
|
127
|
+
send("#{association_name}=", attachments)
|
128
|
+
end
|
129
|
+
|
130
|
+
define_method(attribute_name) do
|
131
|
+
record = send(association_name)
|
132
|
+
record.map(&:url)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oss-ar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- yetrun
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-06 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- yetrun@foxmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rspec"
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- lib/oss-activerecord.rb
|
26
|
+
- lib/oss-activerecord/attachment.rb
|
27
|
+
- lib/oss-activerecord/version.rb
|
28
|
+
- lib/oss/adapters/aliyun_adapter.rb
|
29
|
+
- lib/oss/adapters/qiniu_adapter.rb
|
30
|
+
homepage: https://github.com/yetrun/oss-activerecord
|
31
|
+
licenses:
|
32
|
+
- LGPL-2.0
|
33
|
+
metadata:
|
34
|
+
homepage_uri: https://github.com/yetrun/oss-activerecord
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.0.0
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubygems_version: 3.4.6
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: 将国内的云存储服务与 ActiveRecord 集成的解决方案
|
54
|
+
test_files: []
|