Skip to content

Commit b26f15c

Browse files
committed
migrate to active storage tables
1 parent 6c66077 commit b26f15c

15 files changed

+171
-95
lines changed

Gemfile

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ end
99
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
1010
gem 'rails', '~> 6.0'
1111
# Use postgresql as the database for Active Record
12-
gem 'pg', '~> 1.0'
12+
gem 'pg', '~> 0.20'
1313
# Use Puma as the app server
1414
gem 'puma', '~> 3.7'
1515
# Use SCSS for stylesheets
1616
gem 'sass-rails', '~> 5.0'
1717
# Use Uglifier as compressor for JavaScript assets
1818
gem 'uglifier', '>= 1.3.0'
1919
# Use CoffeeScript for .coffee assets and views
20-
gem 'coffee-rails', '~> 4.2'
20+
gem 'coffee-rails', '~> 5.0'
2121
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
2222
gem 'jbuilder', '~> 2.5'
2323

@@ -28,7 +28,7 @@ gem 'jquery-rails'
2828

2929
gem 'bcrypt', '~> 3.1.7'
3030
gem "font-awesome-rails"
31-
gem 'aws-sdk-s3'
31+
gem 'aws-sdk-s3', require: false
3232
gem "paperclip", "~> 6.1.0"
3333
gem 'faker'
3434

Gemfile.lock

+5-5
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ GEM
9797
childprocess (3.0.0)
9898
climate_control (0.2.0)
9999
coderay (1.1.2)
100-
coffee-rails (4.2.2)
100+
coffee-rails (5.0.0)
101101
coffee-script (>= 2.2.0)
102-
railties (>= 4.0.0)
102+
railties (>= 5.2.0)
103103
coffee-script (2.4.1)
104104
coffee-script-source
105105
execjs
@@ -154,7 +154,7 @@ GEM
154154
mime-types
155155
mimemagic (~> 0.3.0)
156156
terrapin (~> 0.6.0)
157-
pg (1.2.3)
157+
pg (0.21.0)
158158
pry (0.13.1)
159159
coderay (~> 1.1)
160160
method_source (~> 1.0)
@@ -258,14 +258,14 @@ DEPENDENCIES
258258
binding_of_caller
259259
byebug
260260
capybara (~> 2.13)
261-
coffee-rails (~> 4.2)
261+
coffee-rails (~> 5.0)
262262
faker
263263
font-awesome-rails
264264
jbuilder (~> 2.5)
265265
jquery-rails
266266
listen (>= 3.0.5, < 3.2)
267267
paperclip (~> 6.1.0)
268-
pg (~> 1.0)
268+
pg (~> 0.20)
269269
pry-rails
270270
puma (~> 3.7)
271271
rails (~> 6.0)

bin/bundle

-3
This file was deleted.

bin/rails

-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
#!/usr/bin/env ruby
2-
begin
3-
load File.expand_path('../spring', __FILE__)
4-
rescue LoadError => e
5-
raise unless e.message.include?('spring')
6-
end
72
APP_PATH = File.expand_path('../config/application', __dir__)
83
require_relative '../config/boot'
94
require 'rails/commands'

bin/rake

-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
#!/usr/bin/env ruby
2-
begin
3-
load File.expand_path('../spring', __FILE__)
4-
rescue LoadError => e
5-
raise unless e.message.include?('spring')
6-
end
72
require_relative '../config/boot'
83
require 'rake'
94
Rake.application.run

bin/setup

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
#!/usr/bin/env ruby
2-
require 'pathname'
32
require 'fileutils'
4-
include FileUtils
53

64
# path to your application root.
7-
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
5+
APP_ROOT = File.expand_path('..', __dir__)
86

97
def system!(*args)
108
system(*args) || abort("\n== Command #{args} failed ==")
119
end
1210

13-
chdir APP_ROOT do
14-
# This script is a starting point to setup your application.
11+
FileUtils.chdir APP_ROOT do
12+
# This script is a way to setup or update your development environment automatically.
13+
# This script is idempotent, so that you can run it at anytime and get an expectable outcome.
1514
# Add necessary setup steps to this file.
1615

1716
puts '== Installing dependencies =='
1817
system! 'gem install bundler --conservative'
1918
system('bundle check') || system!('bundle install')
2019

21-
# Install JavaScript dependencies if using Yarn
22-
# system('bin/yarn')
23-
24-
2520
# puts "\n== Copying sample files =="
2621
# unless File.exist?('config/database.yml')
27-
# cp 'config/database.yml.sample', 'config/database.yml'
22+
# FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
2823
# end
2924

3025
puts "\n== Preparing database =="
31-
system! 'bin/rails db:setup'
26+
system! 'bin/rails db:prepare'
3227

3328
puts "\n== Removing old logs and tempfiles =="
3429
system! 'bin/rails log:clear tmp:clear'

bin/spring

-17
This file was deleted.

bin/update

-29
This file was deleted.

bin/yarn

-11
This file was deleted.

config/environments/development.rb

+4
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,8 @@
5151
# Use an evented file watcher to asynchronously detect changes in source code,
5252
# routes, locales, etc. This feature depends on the listen gem.
5353
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
54+
55+
56+
# Store files on Amazon S3.
57+
config.active_storage.service = :amazon
5458
end

config/environments/production.rb

+3
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,7 @@
8888

8989
# Do not dump schema after migrations.
9090
config.active_record.dump_schema_after_migration = false
91+
92+
# Store files on Amazon S3.
93+
config.active_storage.service = :amazon
9194
end

config/storage.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
amazon:
2+
service: S3
3+
access_key_id: Rails.application.credentials.s3_access_key_id
4+
secret_access_key: Rails.application.credentials.s3_secret_access_key
5+
region: Rails.application.credentials.s3_region
6+
bucket: Rails.application.credentials[Rails.env.to_sym][:s3_bucket]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This migration comes from active_storage (originally 20170806125915)
2+
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
3+
def change
4+
create_table :active_storage_blobs do |t|
5+
t.string :key, null: false
6+
t.string :filename, null: false
7+
t.string :content_type
8+
t.text :metadata
9+
t.bigint :byte_size, null: false
10+
t.string :checksum, null: false
11+
t.datetime :created_at, null: false
12+
13+
t.index [ :key ], unique: true
14+
end
15+
16+
create_table :active_storage_attachments do |t|
17+
t.string :name, null: false
18+
t.references :record, null: false, polymorphic: true, index: false
19+
t.references :blob, null: false
20+
21+
t.datetime :created_at, null: false
22+
23+
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
24+
t.foreign_key :active_storage_blobs, column: :blob_id
25+
end
26+
end
27+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
class ConvertToActiveStorage < ActiveRecord::Migration[6.0]
2+
require 'open-uri'
3+
4+
def up
5+
# postgres
6+
get_blob_id = 'LASTVAL()'
7+
# mariadb
8+
# get_blob_id = 'LAST_INSERT_ID()'
9+
# sqlite
10+
# get_blob_id = 'LAST_INSERT_ROWID()'
11+
12+
active_storage_blob_statement = ActiveRecord::Base.connection.raw_connection.prepare('active_storage_blob_statement', <<-SQL)
13+
INSERT INTO active_storage_blobs (
14+
key, filename, content_type, metadata, byte_size, checksum, created_at
15+
) VALUES ($1, $2, $3, '{}', $4, $5, $6)
16+
SQL
17+
18+
active_storage_attachment_statement = ActiveRecord::Base.connection.raw_connection.prepare('active_storage_attachment_statement', <<-SQL)
19+
INSERT INTO active_storage_attachments (
20+
name, record_type, record_id, blob_id, created_at
21+
) VALUES ($1, $2, $3, #{get_blob_id}, $4)
22+
SQL
23+
24+
Rails.application.eager_load!
25+
models = ActiveRecord::Base.descendants.reject(&:abstract_class?)
26+
27+
transaction do
28+
models.each do |model|
29+
attachments = model.column_names.map do |c|
30+
if c =~ /(.+)_file_name$/
31+
$1
32+
end
33+
end.compact
34+
35+
if attachments.blank?
36+
next
37+
end
38+
39+
model.find_each.each do |instance|
40+
attachments.each do |attachment|
41+
if instance.send(attachment).path.blank?
42+
next
43+
end
44+
45+
ActiveRecord::Base.connection.raw_connection.exec_prepared(
46+
'active_storage_blob_statement', [
47+
key(instance, attachment),
48+
instance.send("#{attachment}_file_name"),
49+
instance.send("#{attachment}_content_type"),
50+
instance.send("#{attachment}_file_size"),
51+
checksum(instance.send(attachment)),
52+
instance.updated_at.iso8601
53+
])
54+
55+
ActiveRecord::Base.connection.raw_connection.exec_prepared(
56+
'active_storage_attachment_statement', [
57+
attachment,
58+
model.name,
59+
instance.id,
60+
instance.updated_at.iso8601,
61+
])
62+
end
63+
end
64+
end
65+
end
66+
end
67+
68+
def down
69+
raise ActiveRecord::IrreversibleMigration
70+
end
71+
72+
private
73+
74+
def key(instance, attachment)
75+
SecureRandom.uuid
76+
# Alternatively:
77+
# instance.send("#{attachment}_file_name")
78+
end
79+
80+
def checksum(attachment)
81+
# local files stored on disk:
82+
# url = attachment.path
83+
# Digest::MD5.base64digest(File.read(url))
84+
85+
# remote files stored on another person's computer:
86+
url = attachment.url
87+
Digest::MD5.base64digest(Net::HTTP.get(URI(url)))
88+
end
89+
end

db/schema.rb

+28-6
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,40 @@
22
# of editing this file, please use the migrations feature of Active Record to
33
# incrementally modify your database, and then regenerate this schema definition.
44
#
5-
# Note that this schema.rb definition is the authoritative source for your
6-
# database schema. If you need to create the application database on another
7-
# system, you should be using db:schema:load, not running all the migrations
8-
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
9-
# you'll amass, the slower it'll run and the greater likelihood for issues).
5+
# This file is the source Rails uses to define your schema when running `rails
6+
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
7+
# be faster and is potentially less error prone than running all of your
8+
# migrations from scratch. Old migrations may fail to apply correctly if those
9+
# migrations use external dependencies or application code.
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema.define(version: 20170913140950) do
13+
ActiveRecord::Schema.define(version: 2020_05_05_020722) do
1414

1515
# These are extensions that must be enabled in order to support this database
1616
enable_extension "plpgsql"
1717

18+
create_table "active_storage_attachments", force: :cascade do |t|
19+
t.string "name", null: false
20+
t.string "record_type", null: false
21+
t.bigint "record_id", null: false
22+
t.bigint "blob_id", null: false
23+
t.datetime "created_at", null: false
24+
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
25+
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
26+
end
27+
28+
create_table "active_storage_blobs", force: :cascade do |t|
29+
t.string "key", null: false
30+
t.string "filename", null: false
31+
t.string "content_type"
32+
t.text "metadata"
33+
t.bigint "byte_size", null: false
34+
t.string "checksum", null: false
35+
t.datetime "created_at", null: false
36+
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
37+
end
38+
1839
create_table "businesses", force: :cascade do |t|
1940
t.integer "author_id", null: false
2041
t.string "name", null: false
@@ -84,4 +105,5 @@
84105
t.index ["username"], name: "index_users_on_username", unique: true
85106
end
86107

108+
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
87109
end

0 commit comments

Comments
 (0)