activestorage-memory 0.1.1 → 0.2.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 +4 -4
- data/README.md +11 -2
- data/app/controllers/activestorage/memory/memory_controller.rb +60 -0
- data/config/routes.rb +6 -0
- data/lib/active_storage/service/memory_service.rb +86 -5
- data/lib/activestorage/memory/engine.rb +7 -0
- data/lib/{active_storage → activestorage}/memory/version.rb +2 -2
- data/lib/{active_storage → activestorage}/memory.rb +2 -1
- data/spec/active_storage/service/memory_service_spec.rb +99 -0
- data/spec/activestorage/memory_spec.rb +7 -0
- data/spec/controllers/activestorage/memory/memory_controller_spec.rb +136 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +7 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +15 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +33 -0
- data/spec/dummy/config/application.rb +44 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +76 -0
- data/spec/dummy/config/environments/production.rb +97 -0
- data/spec/dummy/config/environments/test.rb +66 -0
- data/spec/dummy/config/initializers/assets.rb +12 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/permissions_policy.rb +13 -0
- data/spec/dummy/config/locales/en.yml +31 -0
- data/spec/dummy/config/puma.rb +35 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/storage.yml +37 -0
- data/spec/dummy/config.ru +6 -0
- data/spec/dummy/db/migrate/20240413101449_create_active_storage_tables.active_storage.rb +57 -0
- data/spec/dummy/db/schema.rb +44 -0
- data/spec/dummy/log/development.log +53 -0
- data/spec/dummy/log/test.log +4820 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/storage/development.sqlite3 +0 -0
- data/spec/dummy/storage/test.sqlite3 +0 -0
- data/spec/dummy/tmp/local_secret.txt +1 -0
- data/spec/dummy/tmp/restart.txt +0 -0
- data/spec/rails_helper.rb +65 -0
- data/spec/spec_helper.rb +15 -0
- metadata +118 -18
- data/.github/workflows/main.yml +0 -18
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/Gemfile +0 -10
- data/Gemfile.lock +0 -204
- data/LICENSE.txt +0 -21
- data/activestorage-memory.gemspec +0 -36
- data/bin/console +0 -15
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83bd480b89220732381633492509732f10f905c5861e76078c4c6e6daba5538c
|
4
|
+
data.tar.gz: 16d37bbbe47843e3681d58145a0d994ea4aa7691084b4fba430d8dbe8dee3a98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1054af1c3c162d07abba56c9cfd3ff6a6ad1338873647171bd4361148563615d56780e2a76ee35d1bca8dee686c0c7f2c871310dca59c8ebfe3bdad4228e13d
|
7
|
+
data.tar.gz: fe03e7402ead1314a7666b4eb15622547cebda2a3103c774b6a3ca2d8655337d1d628c112c2b465a6ca7275088cf5d7f2a96f3c55e7326c00f794d47b4bd6ae7
|
data/README.md
CHANGED
@@ -34,11 +34,20 @@ To use the Memory service in test, you add the following to config/environments/
|
|
34
34
|
config.active_storage.service = :memory
|
35
35
|
```
|
36
36
|
|
37
|
-
In Active Storage's analyzer feature, asynchronous jobs are executed. So
|
37
|
+
In Active Storage's analyzer feature, asynchronous jobs are executed. So you should set the queue adapter to inline at config/environments/test.
|
38
38
|
```
|
39
|
-
config.active_job.queue_adapter = :
|
39
|
+
config.active_job.queue_adapter = :inline
|
40
40
|
```
|
41
41
|
|
42
|
+
If you are conducting file downloads and uploads during system testing or integration testing, please add the following to the routing.
|
43
|
+
|
44
|
+
``` config/routes.rb
|
45
|
+
|
46
|
+
mount ActiveStorage::Memory::Engine => "/" if Rails.env.test?
|
47
|
+
|
48
|
+
```
|
49
|
+
|
50
|
+
|
42
51
|
You can read more about Active Storage in the Active Storage Overview guide.
|
43
52
|
|
44
53
|
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Activestorage::Memory
|
4
|
+
class MemoryController < ActiveStorage::BaseController
|
5
|
+
skip_forgery_protection
|
6
|
+
|
7
|
+
def show
|
8
|
+
key = decode_verified_key
|
9
|
+
|
10
|
+
unless key
|
11
|
+
head :not_found
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
service = named_memory_service(key[:service_name])
|
16
|
+
if service.exist?(key[:key])
|
17
|
+
send_data(service.store[key[:key]], content_type: key[:content_type], disposition: key[:disposition])
|
18
|
+
else
|
19
|
+
head :not_found
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def update
|
24
|
+
token = decode_verified_token
|
25
|
+
|
26
|
+
unless token
|
27
|
+
head :not_found
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
unless acceptable_content?(token)
|
32
|
+
head :unprocessable_entity
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
named_memory_service(token[:service_name]).upload token[:key], request.body, checksum: token[:checksum]
|
37
|
+
head :no_content
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def named_memory_service(name)
|
43
|
+
ActiveStorage::Blob.services.fetch(name) do
|
44
|
+
ActiveStorage::Blob.service
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def decode_verified_key
|
49
|
+
ActiveStorage.verifier.verified(params[:encoded_key], purpose: :blob_key)&.deep_symbolize_keys
|
50
|
+
end
|
51
|
+
|
52
|
+
def decode_verified_token
|
53
|
+
ActiveStorage.verifier.verified(params[:encoded_token], purpose: :blob_token)&.deep_symbolize_keys
|
54
|
+
end
|
55
|
+
|
56
|
+
def acceptable_content?(token)
|
57
|
+
token[:content_type] == request.content_mime_type.to_s && token[:content_length] == request.content_length
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/config/routes.rb
ADDED
@@ -11,9 +11,10 @@ module ActiveStorage
|
|
11
11
|
@config = config
|
12
12
|
end
|
13
13
|
|
14
|
-
def upload(key, io, **)
|
14
|
+
def upload(key, io, checksum: nil, **)
|
15
15
|
instrument(:upload, key: key) do
|
16
16
|
store[key] = io.read
|
17
|
+
ensure_integrity_of(key, checksum) if checksum
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -41,6 +42,14 @@ module ActiveStorage
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
45
|
+
def delete_prefixed(prefix)
|
46
|
+
instrument :delete_prefixed, prefix: prefix do
|
47
|
+
store.each_keys do |key|
|
48
|
+
store.delete(key) if key.start_with?(prefix)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
44
53
|
def exist?(key)
|
45
54
|
instrument(:exist, key: key) do |payload|
|
46
55
|
answer = store.key?(key)
|
@@ -49,13 +58,28 @@ module ActiveStorage
|
|
49
58
|
end
|
50
59
|
end
|
51
60
|
|
52
|
-
def
|
53
|
-
instrument
|
54
|
-
|
55
|
-
|
61
|
+
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, **)
|
62
|
+
instrument :url, key: key do |payload|
|
63
|
+
verified_token_with_expiration = generate_verified_token(
|
64
|
+
key,
|
65
|
+
expires_in: expires_in,
|
66
|
+
content_type: content_type,
|
67
|
+
content_length: content_length,
|
68
|
+
checksum: checksum
|
69
|
+
)
|
70
|
+
url_helpers.update_rails_memory_service_url(
|
71
|
+
verified_token_with_expiration,
|
72
|
+
url_options
|
73
|
+
).tap do |generated_url|
|
74
|
+
payload[:url] = generated_url
|
75
|
+
end
|
56
76
|
end
|
57
77
|
end
|
58
78
|
|
79
|
+
def headers_for_direct_upload(_key, content_type:, **)
|
80
|
+
{ 'Content-Type' => content_type }
|
81
|
+
end
|
82
|
+
|
59
83
|
private
|
60
84
|
|
61
85
|
def stream(key)
|
@@ -66,5 +90,62 @@ module ActiveStorage
|
|
66
90
|
rescue KeyError
|
67
91
|
raise ActiveStorage::FileNotFoundError
|
68
92
|
end
|
93
|
+
|
94
|
+
def url_helpers
|
95
|
+
@url_helpers ||= Activestorage::Memory::Engine.routes.url_helpers
|
96
|
+
end
|
97
|
+
|
98
|
+
def generate_verified_token(key, expires_in:, content_type:, content_length:, checksum:)
|
99
|
+
ActiveStorage.verifier.generate(
|
100
|
+
{
|
101
|
+
key: key,
|
102
|
+
content_type: content_type,
|
103
|
+
content_length: content_length,
|
104
|
+
checksum: checksum,
|
105
|
+
service_name: name
|
106
|
+
},
|
107
|
+
expires_in: expires_in,
|
108
|
+
purpose: :blob_token
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def private_url(key, expires_in:, filename:, content_type:, disposition: :inline, **)
|
113
|
+
generate_url(key, expires_in: expires_in, filename: filename, content_type: content_type, disposition: disposition)
|
114
|
+
end
|
115
|
+
|
116
|
+
def public_url(key, filename:, content_type: nil, disposition: :attachment, **)
|
117
|
+
generate_url(key, expires_in: nil, filename: filename, content_type: content_type, disposition: disposition)
|
118
|
+
end
|
119
|
+
|
120
|
+
def generate_url(key, expires_in:, filename:, content_type:, disposition:)
|
121
|
+
content_disposition = content_disposition_with(type: disposition, filename: ActiveStorage::Filename.wrap(filename))
|
122
|
+
verified_key_with_expiration = ActiveStorage.verifier.generate(
|
123
|
+
{
|
124
|
+
key: key,
|
125
|
+
disposition: content_disposition,
|
126
|
+
content_type: content_type,
|
127
|
+
service_name: name
|
128
|
+
},
|
129
|
+
expires_in: expires_in,
|
130
|
+
purpose: :blob_key
|
131
|
+
)
|
132
|
+
|
133
|
+
if url_options.blank?
|
134
|
+
raise ArgumentError, "Cannot generate URL for #{filename} using Memory service, please set ActiveStorage::Current.url_options."
|
135
|
+
end
|
136
|
+
|
137
|
+
url_helpers.rails_memory_service_url(verified_key_with_expiration, filename: filename, **url_options)
|
138
|
+
end
|
139
|
+
|
140
|
+
def url_options
|
141
|
+
ActiveStorage::Current.url_options || Rails.application.default_url_options
|
142
|
+
end
|
143
|
+
|
144
|
+
def ensure_integrity_of(key, checksum)
|
145
|
+
return if OpenSSL::Digest.new('md5', store[key]).base64digest == checksum
|
146
|
+
|
147
|
+
delete key
|
148
|
+
raise ActiveStorage::IntegrityError
|
149
|
+
end
|
69
150
|
end
|
70
151
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe ActiveStorage::Service::MemoryService do
|
4
|
+
let(:service) { ActiveStorage::Service::MemoryService.new }
|
5
|
+
let(:content) { 'content' }
|
6
|
+
let(:io) { StringIO.new(content) }
|
7
|
+
let(:key) { 'key' }
|
8
|
+
let(:host) { 'example.com' }
|
9
|
+
|
10
|
+
before do
|
11
|
+
ActiveStorage::Current.url_options = { host: host }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#upload' do
|
15
|
+
it 'stores by key' do
|
16
|
+
service.upload(key, io)
|
17
|
+
expect(service.store[key]).to eq(content)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#download' do
|
22
|
+
context 'when key does not exist' do
|
23
|
+
it 'raises ActiveStorage::FileNotFoundError' do
|
24
|
+
expect { service.download(key) }.to raise_error(ActiveStorage::FileNotFoundError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when key exists' do
|
29
|
+
before do
|
30
|
+
service.upload(key, io)
|
31
|
+
end
|
32
|
+
it 'retrieves by key' do
|
33
|
+
expect(service.download(key).read).to eq(content)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#delete' do
|
39
|
+
context 'when key does not exist' do
|
40
|
+
it 'ignores key errors' do
|
41
|
+
expect { service.delete(key) }.not_to raise_error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when key exists' do
|
46
|
+
before do
|
47
|
+
service.upload(key, io)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'deletes by key' do
|
51
|
+
service.delete(key)
|
52
|
+
expect(service.store).not_to have_key(key)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#exist?' do
|
58
|
+
context 'when key does not exist' do
|
59
|
+
it 'returns false' do
|
60
|
+
expect(service.exist?(key)).to be false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when key exists' do
|
65
|
+
before do
|
66
|
+
service.upload(key, io)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'checks by key' do
|
70
|
+
expect(service.exist?(key)).to be true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#url_for_direct_upload' do
|
76
|
+
let(:filename) { 'filename' }
|
77
|
+
let(:content_type) { 'image/jpeg' }
|
78
|
+
let(:content_length) { content.size }
|
79
|
+
let(:checksum) { OpenSSL::Digest.new('md5', content).base64digest }
|
80
|
+
let(:service_name) { 'memory' }
|
81
|
+
let(:expires_in) { 5.minutes }
|
82
|
+
|
83
|
+
before do
|
84
|
+
service.upload(key, io)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'returns a memory url' do
|
88
|
+
expect(service.url(key, expires_in: expires_in, filename: filename, content_type: content_type)).to start_with("http://#{host}/")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#headers_for_direct_upload' do
|
93
|
+
let(:content_type) { 'image/jpeg' }
|
94
|
+
|
95
|
+
it 'returns content type' do
|
96
|
+
expect(service.headers_for_direct_upload(key, content_type: content_type)).to eq('Content-Type' => content_type)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe Activestorage::Memory::MemoryController, type: :request do
|
6
|
+
let(:key) { 'file_key' }
|
7
|
+
let(:content) { 'content' }
|
8
|
+
let(:filename) { 'file.jpg' }
|
9
|
+
let(:content_type) { 'image/jpeg' }
|
10
|
+
let(:service_name) { :memory }
|
11
|
+
let(:disposition) { "inline; filename=\"file.jpg\"; filename*=UTF-8''file.jpg" }
|
12
|
+
let(:expires_in) { ActiveStorage.service_urls_expire_in }
|
13
|
+
let(:checksum) { OpenSSL::Digest.new('md5', content).base64digest }
|
14
|
+
let!(:blob) do
|
15
|
+
ActiveStorage::Blob.create_and_upload!(
|
16
|
+
key: key,
|
17
|
+
io: StringIO.new(content),
|
18
|
+
filename: filename,
|
19
|
+
content_type: content_type,
|
20
|
+
service_name: service_name
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
before do
|
25
|
+
ActiveStorage::Current.url_options = { only_path: true }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "GET #show" do
|
29
|
+
let(:valid_key) do
|
30
|
+
ActiveStorage.verifier.generate(
|
31
|
+
{
|
32
|
+
key: key,
|
33
|
+
service_name: service_name,
|
34
|
+
content_type: content_type,
|
35
|
+
disposition: disposition
|
36
|
+
},
|
37
|
+
expires_in: expires_in,
|
38
|
+
purpose: :blob_key
|
39
|
+
)
|
40
|
+
end
|
41
|
+
let(:invalid_key) { 'invalid_key' }
|
42
|
+
|
43
|
+
subject { get "/rails/active_storage/memory/#{valid_key}/#{filename}" }
|
44
|
+
|
45
|
+
context "when key is valid" do
|
46
|
+
it "returns http success if key is valid and file exists" do
|
47
|
+
subject
|
48
|
+
expect(response).to have_http_status(:success)
|
49
|
+
expect(response.body).to eq(content)
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when file does not exist" do
|
53
|
+
before do
|
54
|
+
ActiveStorage::Blob.services.fetch(service_name).delete(key)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns http not_found" do
|
58
|
+
subject
|
59
|
+
expect(response).to have_http_status(:not_found)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when key is invalid" do
|
65
|
+
subject { get "/rails/active_storage/memory/#{invalid_key}/#{filename}" }
|
66
|
+
|
67
|
+
it "returns http not_found" do
|
68
|
+
subject
|
69
|
+
expect(response).to have_http_status(:not_found)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "PATCH #update" do
|
75
|
+
let(:valid_token) do
|
76
|
+
ActiveStorage.verifier.generate(
|
77
|
+
{
|
78
|
+
key: key,
|
79
|
+
service_name: service_name,
|
80
|
+
checksum: checksum,
|
81
|
+
content_type: content_type,
|
82
|
+
content_length: content.length
|
83
|
+
},
|
84
|
+
purpose: :blob_token
|
85
|
+
)
|
86
|
+
end
|
87
|
+
let(:invalid_token) { 'invalid_token' }
|
88
|
+
|
89
|
+
context "when token is valid" do
|
90
|
+
context "when content is acceptable" do
|
91
|
+
subject do
|
92
|
+
put(
|
93
|
+
"/rails/active_storage/memory/#{valid_token}",
|
94
|
+
params: content,
|
95
|
+
headers: { 'Content-Type' => content_type, 'Content-Length' => content.size }
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "returns http no_content if token is valid and content is acceptable" do
|
100
|
+
subject
|
101
|
+
expect(response).to have_http_status(:no_content)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "when content is not acceptable" do
|
106
|
+
subject do
|
107
|
+
put(
|
108
|
+
"/rails/active_storage/memory/#{valid_token}",
|
109
|
+
params: content,
|
110
|
+
headers: { 'Content-Type' => "image/png", 'Content-Length' => content.size }
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "returns http unprocessable_entity" do
|
115
|
+
subject
|
116
|
+
expect(response).to have_http_status(:unprocessable_entity)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when token is invalid" do
|
122
|
+
subject do
|
123
|
+
put(
|
124
|
+
"/rails/active_storage/memory/#{invalid_token}",
|
125
|
+
params: content,
|
126
|
+
headers: { 'Content-Type' => content_type, 'Content-Length' => content.size }
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "returns http not_found" do
|
131
|
+
subject
|
132
|
+
expect(response).to have_http_status(:not_found)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class ApplicationJob < ActiveJob::Base
|
2
|
+
# Automatically retry jobs that encountered a deadlock
|
3
|
+
# retry_on ActiveRecord::Deadlocked
|
4
|
+
|
5
|
+
# Most jobs are safe to ignore if the underlying records are no longer available
|
6
|
+
# discard_on ActiveJob::DeserializationError
|
7
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Dummy</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<%= csrf_meta_tags %>
|
7
|
+
<%= csp_meta_tag %>
|
8
|
+
|
9
|
+
<%= stylesheet_link_tag "application" %>
|
10
|
+
</head>
|
11
|
+
|
12
|
+
<body>
|
13
|
+
<%= yield %>
|
14
|
+
</body>
|
15
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= yield %>
|
data/spec/dummy/bin/rake
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
# path to your application root.
|
5
|
+
APP_ROOT = File.expand_path("..", __dir__)
|
6
|
+
|
7
|
+
def system!(*args)
|
8
|
+
system(*args, exception: true)
|
9
|
+
end
|
10
|
+
|
11
|
+
FileUtils.chdir APP_ROOT do
|
12
|
+
# This script is a way to set up or update your development environment automatically.
|
13
|
+
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
|
14
|
+
# Add necessary setup steps to this file.
|
15
|
+
|
16
|
+
puts "== Installing dependencies =="
|
17
|
+
system! "gem install bundler --conservative"
|
18
|
+
system("bundle check") || system!("bundle install")
|
19
|
+
|
20
|
+
# puts "\n== Copying sample files =="
|
21
|
+
# unless File.exist?("config/database.yml")
|
22
|
+
# FileUtils.cp "config/database.yml.sample", "config/database.yml"
|
23
|
+
# end
|
24
|
+
|
25
|
+
puts "\n== Preparing database =="
|
26
|
+
system! "bin/rails db:prepare"
|
27
|
+
|
28
|
+
puts "\n== Removing old logs and tempfiles =="
|
29
|
+
system! "bin/rails log:clear tmp:clear"
|
30
|
+
|
31
|
+
puts "\n== Restarting application server =="
|
32
|
+
system! "bin/rails restart"
|
33
|
+
end
|