Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveStorage integration #3037

Merged
merged 10 commits into from
Jul 7, 2018
2 changes: 1 addition & 1 deletion app/views/rails_admin/main/_form_file_upload.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- file = form.object.send(field.method_name).presence
- file = field.value

.toggle{style: ('display:none;' if file && field.delete_method && form.object.send(field.delete_method) == '1')}
- if value = field.pretty_value
Expand Down
2 changes: 1 addition & 1 deletion lib/rails_admin/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def default_search_operator=(operator)

# pool of all found model names from the whole application
def models_pool
excluded = (excluded_models.collect(&:to_s) + %w(RailsAdmin::History PaperTrail::Version PaperTrail::VersionAssociation))
excluded = (excluded_models.collect(&:to_s) + %w(RailsAdmin::History PaperTrail::Version PaperTrail::VersionAssociation ActiveStorage::Attachment ActiveStorage::Blob))

(viable_models - excluded).uniq.sort
end
Expand Down
1 change: 1 addition & 0 deletions lib/rails_admin/config/fields.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,5 @@ def self.register_factory(&block)
require 'rails_admin/config/fields/factories/dragonfly'
require 'rails_admin/config/fields/factories/carrierwave'
require 'rails_admin/config/fields/factories/refile'
require 'rails_admin/config/fields/factories/active_storage'
require 'rails_admin/config/fields/factories/association'
23 changes: 23 additions & 0 deletions lib/rails_admin/config/fields/factories/active_storage.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'rails_admin/config/fields'
require 'rails_admin/config/fields/types'
require 'rails_admin/config/fields/types/file_upload'

RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
if defined?(::ActiveStorage) && properties.is_a?(RailsAdmin::Adapters::ActiveRecord::Association) && (match = /\A(.+)_attachment\Z/.match properties.name) && properties.klass.to_s == 'ActiveStorage::Attachment'
name = match[1]
field = RailsAdmin::Config::Fields::Types.load(:active_storage).new(parent, name, properties)
fields << field
associations = ["#{name}_attachment".to_sym, "#{name}_blob".to_sym]
children_fields = associations.map do |child_name|
next unless child_association = parent.abstract_model.associations.detect { |p| p.name.to_sym == child_name }
child_field = fields.detect { |f| f.name == child_name } || RailsAdmin::Config::Fields.default_factory.call(parent, child_association, fields)
child_field.hide unless field == child_field
child_field.filterable(false) unless field == child_field
child_field.name
end.flatten
field.children_fields(children_fields)
true
else
false
end
end
44 changes: 44 additions & 0 deletions lib/rails_admin/config/fields/types/active_storage.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'rails_admin/config/fields/types/file_upload'

module RailsAdmin
module Config
module Fields
module Types
class ActiveStorage < RailsAdmin::Config::Fields::Types::FileUpload
RailsAdmin::Config::Fields::Types.register(self)

register_instance_option :thumb_method do
{resize: '100x100>'}
end

register_instance_option :delete_method do
"remove_#{name}" if bindings[:object].respond_to?("remove_#{name}")
end

register_instance_option :image? do
if value
value.filename.to_s.split('.').last =~ /jpg|jpeg|png|gif|svg/i
end
end

def resource_url(thumb = false)
return nil unless value
if thumb && value.variable?
variant = value.variant(thumb)
Rails.application.routes.url_helpers.rails_blob_representation_path(
variant.blob.signed_id, variant.variation.key, variant.blob.filename, only_path: true
)
else
Rails.application.routes.url_helpers.rails_blob_path(value, only_path: true)
end
end

def value
attachment = super
attachment if attachment && attachment.attached?
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rails_admin/config/fields/types/all.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'rails_admin/config/fields/types/active_record_enum'
require 'rails_admin/config/fields/types/active_storage'
require 'rails_admin/config/fields/types/belongs_to_association'
require 'rails_admin/config/fields/types/boolean'
require 'rails_admin/config/fields/types/bson_object_id'
Expand Down
9 changes: 7 additions & 2 deletions spec/controllers/rails_admin/main_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,9 @@ class TeamWithNumberedPlayers < Team
delete_method :delete_paperclip_asset
end
field :refile_asset if defined?(Refile)
field :active_storage_asset do
delete_method :remove_active_storage_asset
end if defined?(ActiveStorage)
end
controller.params = HashWithIndifferentAccess.new(
'field_test' => {
Expand All @@ -395,7 +398,8 @@ class TeamWithNumberedPlayers < Team
'paperclip_asset' => 'test',
'delete_paperclip_asset' => 'test',
'should_not_be_here' => 'test',
}.merge(defined?(Refile) ? {'refile_asset' => 'test', 'remove_refile_asset' => 'test'} : {}),
}.merge(defined?(Refile) ? {'refile_asset' => 'test', 'remove_refile_asset' => 'test'} : {}).
merge(defined?(ActiveStorage) ? {'active_storage_asset' => 'test', 'remove_active_storage_asset' => 'test'} : {}),
)

controller.send(:sanitize_params_for!, :create, RailsAdmin.config(FieldTest), controller.params['field_test'])
Expand All @@ -408,7 +412,8 @@ class TeamWithNumberedPlayers < Team
'retained_dragonfly_asset' => 'test',
'paperclip_asset' => 'test',
'delete_paperclip_asset' => 'test',
}.merge(defined?(Refile) ? {'refile_asset' => 'test', 'remove_refile_asset' => 'test'} : {}))
}.merge(defined?(Refile) ? {'refile_asset' => 'test', 'remove_refile_asset' => 'test'} : {}).
merge(defined?(ActiveStorage) ? {'active_storage_asset' => 'test', 'remove_active_storage_asset' => 'test'} : {}))
end

it 'allows for polymorphic associations parameters' do
Expand Down
4 changes: 2 additions & 2 deletions spec/dummy_app/Gemfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
source 'https://rubygems.org'

gem 'rails', '~> 5.0.0'
gem 'rails', '~> 5.0'
gem 'rack-cache', require: 'rack/cache'

group :active_record do
Expand All @@ -23,7 +23,7 @@ group :active_record do
end

group :mongoid do
gem 'mongoid', '~> 6.0.0.beta'
gem 'mongoid', '~> 6.0'
gem 'mongoid-paperclip', '>= 0.0.8', require: 'mongoid_paperclip'
gem 'carrierwave-mongoid', '>= 0.6.3', require: 'carrierwave/mongoid'
# gem 'refile-mongoid', '>= 0.0.1', platforms: [:ruby_21, :ruby_22]
Expand Down
4 changes: 4 additions & 0 deletions spec/dummy_app/app/active_record/field_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class FieldTest < ActiveRecord::Base

attachment :refile_asset if defined?(Refile)

has_one_attached :active_storage_asset if defined?(ActiveStorage)
attr_accessor :remove_active_storage_asset
after_save { active_storage_asset.purge if remove_active_storage_asset == '1' }

if ::Rails.version >= '4.1' # enum support was added in Rails 4.1
enum string_enum_field: {S: 's', M: 'm', L: 'l'}
enum integer_enum_field: [:small, :medium, :large]
Expand Down
3 changes: 3 additions & 0 deletions spec/dummy_app/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
rescue LoadError # rubocop:disable HandleExceptions
end

require 'active_storage/engine' if Rails.version >= '5.2.0' && CI_ORM == :active_record

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups, CI_ORM)
Expand All @@ -25,5 +27,6 @@ class Application < Rails::Application
config.active_record.raise_in_transactional_callbacks = true if Rails::VERSION::MAJOR == 4 && Rails::VERSION::MINOR == 2 && CI_ORM == :active_record
config.active_record.time_zone_aware_types = [:datetime, :time] if Rails::VERSION::MAJOR >= 5 && CI_ORM == :active_record
config.active_record.sqlite3.represent_boolean_as_integer = true if CI_ORM == :active_record && config.active_record.sqlite3.respond_to?(:represent_boolean_as_integer=)
config.active_storage.service = :local if defined?(ActiveStorage)
end
end
3 changes: 3 additions & 0 deletions spec/dummy_app/config/storage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
local:
service: Disk
root: <%= Rails.root.join('public', 'system') %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This migration comes from active_storage (originally 20170806125915)
class CreateActiveStorageTables < MigrationBase
def change
create_table :active_storage_blobs do |t|
t.string :key, null: false
t.string :filename, null: false
t.string :content_type
t.text :metadata
if t.respond_to? :bigint
t.bigint :byte_size, null: false
else
t.integer :byte_size, null: false
end
t.string :checksum, null: false
t.datetime :created_at, null: false

t.index [:key], unique: true
end

create_table :active_storage_attachments do |t|
t.string :name, null: false
t.references :record, null: false, polymorphic: true, index: false
t.references :blob, null: false

t.datetime :created_at, null: false

t.index [:record_type, :record_id, :name, :blob_id], name: "index_active_storage_attachments_uniqueness", unique: true
end
end
end
14 changes: 14 additions & 0 deletions spec/rails_admin/config/fields/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ class CommentReversed < Tableless
end
end
end

if defined?(ActiveStorage)
context 'of a ActiveStorage installation' do
it 'is _attachment and _blob fields' do
expect(RailsAdmin.config(FieldTest).fields.detect { |f| f.name == :active_storage_asset }.children_fields).to match_array [:active_storage_asset_attachment, :active_storage_asset_blob]
end

it 'is hidden, not filterable' do
fields = RailsAdmin.config(FieldTest).fields.select { |f| [:active_storage_asset_attachment, :active_storage_asset_blob].include?(f.name) }
expect(fields).to all(be_hidden)
expect(fields).not_to include(be_filterable)
end
end
end
end

describe '#form_default_value' do
Expand Down
74 changes: 74 additions & 0 deletions spec/rails_admin/config/fields/types/active_storage_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
require 'spec_helper'

describe RailsAdmin::Config::Fields::Types::ActiveStorage do
it_behaves_like 'a generic field type', :string_field, :active_storage

let(:record) { FactoryGirl.create :field_test }
let(:field) do
RailsAdmin.config('FieldTest').fields.detect do |f|
f.name == :active_storage_asset
end.with(object: record)
end

describe '#image?' do
context 'when attachment is an image' do
let(:record) { FactoryGirl.create :field_test, active_storage_asset: {io: StringIO.new('dummy'), filename: "test.jpg", content_type: "image/jpeg"} }

it 'returns true' do
expect(field.image?).to be_truthy
end
end

context 'when attachment is not an image' do
let(:record) { FactoryGirl.create :field_test, active_storage_asset: {io: StringIO.new('dummy'), filename: "test.txt", content_type: "text/plain"} }

it 'returns false' do
expect(field.image?).to be_falsy
end
end
end

describe '#resource_url' do
context 'when calling with thumb = false' do
let(:record) { FactoryGirl.create :field_test, active_storage_asset: {io: StringIO.new('dummy'), filename: "test.jpg", content_type: "image/jpeg"} }

it 'returns original url' do
expect(field.resource_url).not_to match(/representations/)
end
end

context 'when attachment is an image' do
let(:record) { FactoryGirl.create :field_test, active_storage_asset: {io: StringIO.new('dummy'), filename: "test.jpg", content_type: "image/jpeg"} }

it 'returns variant\'s url' do
expect(field.resource_url(true)).to match(/representations/)
end
end

context 'when attachment is not an image' do
let(:record) { FactoryGirl.create :field_test, active_storage_asset: {io: StringIO.new('dummy'), filename: "test.txt", content_type: "text/plain"} }

it 'returns original url' do
expect(field.resource_url(true)).not_to match(/representations/)
end
end
end

describe '#value' do
context 'when attachment exists' do
let(:record) { FactoryGirl.create :field_test, active_storage_asset: {io: StringIO.new('dummy'), filename: "test.jpg", content_type: "image/jpeg"} }

it 'returns attached object' do
expect(field.value).to be_a(ActiveStorage::Attached::One)
end
end

context 'when attachment does not exist' do
let(:record) { FactoryGirl.create :field_test }

it 'returns nil' do
expect(field.value).to be_nil
end
end
end
end if defined?(ActiveStorage)
4 changes: 4 additions & 0 deletions spec/rails_admin/config/fields/types/file_upload_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@
delete_method :delete_paperclip_asset
end
field :refile_asset
field :active_storage_asset do
delete_method :remove_active_storage_asset
end if defined?(ActiveStorage)
end
end
expect(RailsAdmin.config(FieldTest).field(:carrierwave_asset).allowed_methods.collect(&:to_s)).to eq %w(carrierwave_asset remove_carrierwave_asset carrierwave_asset_cache)
expect(RailsAdmin.config(FieldTest).field(:dragonfly_asset).allowed_methods.collect(&:to_s)).to eq %w(dragonfly_asset remove_dragonfly_asset retained_dragonfly_asset)
expect(RailsAdmin.config(FieldTest).field(:paperclip_asset).allowed_methods.collect(&:to_s)).to eq %w(paperclip_asset delete_paperclip_asset)
expect(RailsAdmin.config(FieldTest).field(:refile_asset).allowed_methods.collect(&:to_s)).to eq %w(refile_asset remove_refile_asset) if defined?(Refile)
expect(RailsAdmin.config(FieldTest).field(:active_storage_asset).allowed_methods.collect(&:to_s)).to eq %w(active_storage_asset remove_active_storage_asset) if defined?(ActiveStorage)
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
SimpleCov.start do
add_filter '/spec/'
add_filter '/vendor/bundle/'
minimum_coverage(91.21)
minimum_coverage(CI_ORM == :mongoid ? 91.08 : 91.21)
end

require File.expand_path('../dummy_app/config/environment', __FILE__)
Expand Down