Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
reviewdog -fail-on-error -reporter=github-pr-review -runners=brakeman,fasterer,rubocop
reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer,rubocop

# NOTE: removed brakeman due some issues
# NOTE: check with: reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer -diff="git diff" -tee
48 changes: 48 additions & 0 deletions .github/workflows/specs_mssql_rails81.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
name: Specs MSSQL Rails 8.1

on:
pull_request:
branches: [main]
push:
branches: [main]

jobs:
tests:
runs-on: ubuntu-latest

strategy:
matrix:
ruby: ['3.2', '3.4']

env:
DB_TEST: mssql
RAILS_VERSION: 8.1

services:
postgres:
image: mcr.microsoft.com/mssql/server:2022-latest
env:
ACCEPT_EULA: 'Y'
SA_PASSWORD: Pa%%w0rd
ports:
- 1433:1433

steps:
- name: Install dependencies
run: sudo apt-get update -qq && sudo apt-get install -yqq freetds-dev freetds-bin libvips-dev

- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Database setup
run: bin/rails db:create db:migrate db:test:prepare

- name: Run tests
run: bin/rspec --profile
56 changes: 56 additions & 0 deletions .github/workflows/specs_mysql_rails81.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
name: Specs MySQL Rails 8.1

on:
pull_request:
branches: [main]
push:
branches: [main]

jobs:
tests:
runs-on: ubuntu-latest

strategy:
matrix:
ruby: ['3.2', '3.4']

env:
DB_TEST: mysql
RAILS_VERSION: 8.1

services:
mysql:
image: mysql
env:
MYSQL_USER: root
MYSQL_PASSWORD: root
# options: >-
# --health-cmd="mysqladmin ping"
# --health-interval 10s
# --health-timeout 5s
# --health-retries 5
ports:
- 3306:3306

steps:
- name: Install dependencies
run: sudo apt-get update -qq && sudo apt-get install -yqq freetds-dev freetds-bin libvips-dev

- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Start database service
run: sudo /etc/init.d/mysql start

- name: Database setup
run: bin/rails db:create db:migrate db:test:prepare

- name: Run tests
run: bin/rspec --profile
53 changes: 53 additions & 0 deletions .github/workflows/specs_postgres_rails81.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
name: Specs Postgres Rails 8.1

on:
pull_request:
branches: [main]
push:
branches: [main]

jobs:
tests:
runs-on: ubuntu-latest

strategy:
matrix:
ruby: ['3.2', '3.4']

env:
DB_TEST: postgres
RAILS_VERSION: 8.1

services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- name: Install dependencies
run: sudo apt-get update -qq && sudo apt-get install -yqq freetds-dev freetds-bin libvips-dev

- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Database setup
run: bin/rails db:create db:migrate db:test:prepare

- name: Run tests
run: bin/rspec --profile
39 changes: 39 additions & 0 deletions .github/workflows/specs_sqlite_rails81.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
name: Specs SQLite Rails 8.1

on:
pull_request:
branches: [main]
push:
branches: [main]

jobs:
tests:
runs-on: ubuntu-latest

strategy:
matrix:
ruby: ['3.2', '3.3', '3.4']

env:
DB_TEST: sqlite
RAILS_VERSION: 8.1

steps:
- name: Install dependencies
run: sudo apt-get update -qq && sudo apt-get install -yqq freetds-dev freetds-bin libvips-dev

- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Database setup
run: bin/rails db:create db:migrate db:test:prepare

- name: Run tests
run: bin/rspec --profile
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ RSpec/NestedGroups:
# Default is 3
Max: 5

RSpec/Output:
Exclude:
- spec/dummy/bin/*

Style/ClassAndModuleChildren:
Exclude:
- 'lib/active_storage/service/db_service.rb'
Expand Down
8 changes: 6 additions & 2 deletions app/controllers/active_storage_db/files_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ def show
def update
if (token = decode_verified_token)
file_uploaded = upload_file(token, body: request.body)
head(file_uploaded ? :no_content : :unprocessable_entity)
head(file_uploaded ? :no_content : unprocessable)
else
head(:not_found)
end
rescue ActiveStorage::IntegrityError
head(:unprocessable_entity)
head(unprocessable)
end

private
Expand Down Expand Up @@ -59,5 +59,9 @@ def upload_file(token, body:)
db_service.upload(token[:key], request.body, checksum: token[:checksum])
true
end

def unprocessable
Gem::Version.new(Rails.version) >= Gem::Version.new("7.1") ? :unprocessable_content : :unprocessable_entity
end
end
end
32 changes: 20 additions & 12 deletions lib/active_storage/service/db_service.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# frozen_string_literal: true

require 'active_storage/service/db_service_rails60'
require 'active_storage/service/db_service_rails61'
require 'active_storage/service/db_service_rails70'
require "active_storage/service/db_service_rails60"
require "active_storage/service/db_service_rails61"
require "active_storage/service/db_service_rails70"

module ActiveStorage
# Wraps a DB table as an Active Storage service. See ActiveStorage::Service
Expand All @@ -19,7 +19,7 @@ class Service::DBService < Service
# :nocov:

def initialize(public: false, **)
@chunk_size = ENV.fetch('ASDB_CHUNK_SIZE') { 1.megabytes }
@chunk_size = ENV.fetch("ASDB_CHUNK_SIZE") { 1.megabytes }
@public = public
end

Expand Down Expand Up @@ -69,7 +69,7 @@ def delete_prefixed(prefix)
instrument :delete_prefixed, prefix: prefix do
comment = "DBService#delete_prefixed"
sanitized_prefix = "#{ApplicationRecord.sanitize_sql_like(prefix)}%"
::ActiveStorageDB::File.annotate(comment).where('ref LIKE ?', sanitized_prefix).destroy_all
::ActiveStorageDB::File.annotate(comment).where("ref LIKE ?", sanitized_prefix).destroy_all
end
end

Expand All @@ -90,7 +90,7 @@ def url_for_direct_upload(key, expires_in:, content_type:, content_length:, chec
content_type: content_type,
content_length: content_length,
checksum: checksum,
service_name: respond_to?(:name) ? name : 'db'
service_name: respond_to?(:name) ? name : "db"
},
expires_in: expires_in,
purpose: :blob_token
Expand All @@ -103,17 +103,25 @@ def url_for_direct_upload(key, expires_in:, content_type:, content_length:, chec
end

def headers_for_direct_upload(_key, content_type:, **)
{ 'Content-Type' => content_type }
{ "Content-Type" => content_type }
end

private

def adapter_sqlite?
@adapter_sqlite ||= ActiveStorageDB::File.connection.adapter_name == 'SQLite'
@adapter_sqlite ||= active_storage_db_adapter_name == "SQLite"
end

def adapter_sqlserver?
@adapter_sqlserver ||= ActiveStorageDB::File.connection.adapter_name == 'SQLServer'
@adapter_sqlserver ||= active_storage_db_adapter_name == "SQLServer"
end

def active_storage_db_adapter_name
if ActiveStorageDB::File.respond_to?(:lease_connection)
ActiveStorageDB::File.lease_connection.adapter_name
else
ActiveStorageDB::File.connection.adapter_name
end
end

def generate_url(key, expires_in:, filename:, content_type:, disposition:)
Expand All @@ -123,7 +131,7 @@ def generate_url(key, expires_in:, filename:, content_type:, disposition:)
key: key,
disposition: content_disposition,
content_type: content_type,
service_name: respond_to?(:name) ? name : 'db'
service_name: respond_to?(:name) ? name : "db"
},
expires_in: expires_in,
purpose: :blob_key
Expand Down Expand Up @@ -162,10 +170,10 @@ def object_for(key, fields: nil)
end

def stream(key)
data_size = adapter_sqlserver? ? 'DATALENGTH(data)' : 'OCTET_LENGTH(data)'
data_size = adapter_sqlserver? ? "DATALENGTH(data)" : "OCTET_LENGTH(data)"
size = object_for(key, fields: "#{data_size} AS size")&.size || raise(ActiveStorage::FileNotFoundError)
(size / @chunk_size.to_f).ceil.times.each do |i|
range = (i * @chunk_size..((i + 1) * @chunk_size) - 1)
range = (i * @chunk_size)..(((i + 1) * @chunk_size) - 1)
yield download_chunk(key, range)
end
end
Expand Down
14 changes: 9 additions & 5 deletions spec/dummy/app/controllers/posts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ def create

respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.html { redirect_to @post, notice: "Post was successfully created." }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: { errors: @post.errors }, status: :unprocessable_entity }
format.json { render json: { errors: @post.errors }, status: unprocessable }
end
end
end
Expand All @@ -42,11 +42,11 @@ def create
def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.html { redirect_to @post, notice: "Post was successfully updated." }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: { errors: @post.errors }, status: :unprocessable_entity }
format.json { render json: { errors: @post.errors }, status: unprocessable }
end
end
end
Expand All @@ -56,7 +56,7 @@ def update
def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.html { redirect_to posts_url, notice: "Post was successfully destroyed." }
format.json { head :no_content }
end
end
Expand All @@ -70,4 +70,8 @@ def load_post
def post_params
params.fetch(:post) { {} }.permit!
end

def unprocessable
Gem::Version.new(Rails.version) >= Gem::Version.new("7.1") ? :unprocessable_content : :unprocessable_entity
end
end
2 changes: 1 addition & 1 deletion spec/dummy/app/models/application_record.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

class ApplicationRecord < ActiveRecord::Base
if Gem::Version.new(Rails.version) >= Gem::Version.new('7.0')
if Rails::VERSION::MAJOR >= 7
primary_abstract_class
else
self.abstract_class = true
Expand Down
Loading
Loading