From e29193edfa8696e9bae26940a18f9f4155252ce5 Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:06:37 -0300 Subject: [PATCH 01/10] feat(gemspec): update ffi and install shrine and image_processing --- Gemfile.lock | 16 +++++++++++++++- activeadmin_addons.gemspec | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2e4bc6a2..795978ec 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,9 +96,12 @@ GEM climate_control (0.2.0) coderay (1.1.2) concurrent-ruby (1.1.8) + content_disposition (1.0.0) crass (1.0.6) database_cleaner (1.8.2) diff-lcs (1.3) + down (5.2.4) + addressable (~> 2.8) enumerize (2.3.1) activesupport (>= 3.2) erubi (1.10.0) @@ -107,7 +110,7 @@ GEM factory_bot_rails (5.1.1) factory_bot (~> 5.1.0) railties (>= 4.2.0) - ffi (1.12.2) + ffi (1.15.5) formatador (0.2.5) formtastic (3.1.5) actionpack (>= 3.2.13) @@ -133,6 +136,9 @@ GEM activesupport (>= 4.1) i18n (1.8.10) concurrent-ruby (~> 1.0) + image_processing (1.12.1) + mini_magick (>= 4.9.5, < 5) + ruby-vips (>= 2.0.17, < 3) inherited_resources (1.11.0) actionpack (>= 5.0, < 6.1) has_scope (~> 0.6) @@ -170,6 +176,7 @@ GEM mime-types (3.3.1) mime-types-data (~> 3.2015) mime-types-data (3.2019.1009) + mini_magick (4.11.0) mini_mime (1.0.2) mini_portile2 (2.6.1) minitest (5.14.4) @@ -280,6 +287,8 @@ GEM ruby-progressbar (~> 1.7) unicode-display_width (~> 1.4.0) ruby-progressbar (1.10.1) + ruby-vips (2.1.4) + ffi (~> 1.12) rubyzip (2.2.0) sassc (2.2.1) ffi (~> 1.9) @@ -296,6 +305,9 @@ GEM shellany (0.0.1) shoulda-matchers (4.2.0) activesupport (>= 4.2.0) + shrine (3.4.0) + content_disposition (~> 1.0) + down (~> 5.1) sprockets (4.0.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -343,6 +355,7 @@ DEPENDENCIES factory_bot_rails guard guard-rspec + image_processing mimemagic! paperclip pry-rails @@ -352,6 +365,7 @@ DEPENDENCIES rspec_junit_formatter rubocop (~> 0.65.0) shoulda-matchers + shrine (~> 3.0) sqlite3 webdrivers webpacker (~> 5.0) diff --git a/activeadmin_addons.gemspec b/activeadmin_addons.gemspec index e0dc6d31..db6ecb1d 100644 --- a/activeadmin_addons.gemspec +++ b/activeadmin_addons.gemspec @@ -32,6 +32,7 @@ Gem::Specification.new do |s| s.add_development_dependency "factory_bot_rails" s.add_development_dependency "guard" s.add_development_dependency "guard-rspec" + s.add_development_dependency "image_processing" s.add_development_dependency "paperclip" s.add_development_dependency "pry-rails" s.add_development_dependency "puma" @@ -40,6 +41,7 @@ Gem::Specification.new do |s| s.add_development_dependency "rspec_junit_formatter" s.add_development_dependency "rubocop", "~> 0.65.0" s.add_development_dependency "shoulda-matchers" + s.add_development_dependency "shrine", "~> 3.0" s.add_development_dependency "sqlite3" s.add_development_dependency "webdrivers" end From e13e573989f161734963b36ecc4cf6c0dd8a5b58 Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:07:13 -0300 Subject: [PATCH 02/10] feat(shrine-initializer): define basic initializer --- spec/dummy/config/initializers/shrine.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 spec/dummy/config/initializers/shrine.rb diff --git a/spec/dummy/config/initializers/shrine.rb b/spec/dummy/config/initializers/shrine.rb new file mode 100644 index 00000000..8ba7a579 --- /dev/null +++ b/spec/dummy/config/initializers/shrine.rb @@ -0,0 +1,22 @@ +require 'shrine' + +if Rails.env.development? + require 'shrine/storage/file_system' + + Shrine.storages = { + cache: Shrine::Storage::FileSystem.new('public', prefix: 'uploads/cache'), + store: Shrine::Storage::FileSystem.new('public', prefix: 'uploads') + } +else + require 'shrine/storage/memory' + + Shrine.storages = { + cache: Shrine::Storage::Memory.new, + store: Shrine::Storage::Memory.new + } +end + +Shrine.plugin :activerecord +Shrine.plugin :cached_attachment_data +Shrine.plugin :restore_cached_data +Shrine.plugin :derivatives From 0a144f42bd531eb185793253d4ab4cb739b73bf4 Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:08:23 -0300 Subject: [PATCH 03/10] feat(image-uploader): define basic image uploader with derivates --- spec/dummy/app/uploaders/image_uploader.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 spec/dummy/app/uploaders/image_uploader.rb diff --git a/spec/dummy/app/uploaders/image_uploader.rb b/spec/dummy/app/uploaders/image_uploader.rb new file mode 100644 index 00000000..57232f4e --- /dev/null +++ b/spec/dummy/app/uploaders/image_uploader.rb @@ -0,0 +1,18 @@ +require 'image_processing/vips' + +class ImageUploader < Shrine + DERIVATIVE_SIZES = { + jpg_small: { size: [100, 100], type: 'jpg' } + } + + Attacher.derivatives do |original| + vips = ImageProcessing::Vips.source(original) + + DERIVATIVE_SIZES.reduce({}) do |derivatives_hash, (name, derivative_info)| + derivatives_hash[name] = vips.convert(derivative_info[:type]).resize_to_limit!( + *derivative_info[:size] + ) + derivatives_hash + end + end +end From 21dd5da2ba38def56630f360c29202e51582d74b Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:09:16 -0300 Subject: [PATCH 04/10] feat(image-builder): define case for shrine --- .../addons/image_builder.rb | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/activeadmin_addons/addons/image_builder.rb b/lib/activeadmin_addons/addons/image_builder.rb index 8a4d2747..ff7c322d 100644 --- a/lib/activeadmin_addons/addons/image_builder.rb +++ b/lib/activeadmin_addons/addons/image_builder.rb @@ -1,11 +1,38 @@ +require 'pry' + module ActiveAdminAddons class ImageBuilder < CustomBuilder def render return nil if data.nil? - raise "you need to pass a paperclip image attribute" unless data.respond_to?(:url) + + if Object.const_defined?('Paperclip::Attachment') && data.is_a?(Paperclip::Attachment) + paperclip_data + elsif Object.const_defined?('Shrine::UploadedFile') && data.is_a?(Shrine::UploadedFile) + shrine_data + else + raise "you need to pass a paperclip or shrine image attribute" + end + end + + private + + def paperclip_data style = options.fetch(:style, :original) context.image_tag(data.url(style)) if data.file? end + + def shrine_data + image_options = options[:image_options].presence || {} + if options[:style] && derivatives.include?(options[:style]) + context.image_tag(model.send("#{attribute}_url", options[:style]), image_options) + else + context.image_tag(data.url, image_options) + end + end + + def derivatives + model.send("#{attribute}_derivatives") + end end end From 588fbac366ed9fa601a613ef0b0c030bf7d1c459 Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:10:11 -0300 Subject: [PATCH 05/10] feat(invoice): include picture_data and image uploader --- spec/dummy/app/models/invoice.rb | 1 + .../db/migrate/20220401181023_add_picture_data_to_invoice.rb | 5 +++++ spec/dummy/db/schema.rb | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 spec/dummy/db/migrate/20220401181023_add_picture_data_to_invoice.rb diff --git a/spec/dummy/app/models/invoice.rb b/spec/dummy/app/models/invoice.rb index 6b1d133c..f8f1fab9 100644 --- a/spec/dummy/app/models/invoice.rb +++ b/spec/dummy/app/models/invoice.rb @@ -6,6 +6,7 @@ class Invoice < ActiveRecord::Base extend ::Enumerize include Paperclip::Glue include AASM + include ImageUploader::Attachment(:picture) belongs_to :category belongs_to :city diff --git a/spec/dummy/db/migrate/20220401181023_add_picture_data_to_invoice.rb b/spec/dummy/db/migrate/20220401181023_add_picture_data_to_invoice.rb new file mode 100644 index 00000000..a630053b --- /dev/null +++ b/spec/dummy/db/migrate/20220401181023_add_picture_data_to_invoice.rb @@ -0,0 +1,5 @@ +class AddPictureDataToInvoice < ActiveRecord::Migration[5.2] + def change + add_column :invoices, :picture_data, :text + end +end diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb index 20792307..546364b9 100644 --- a/spec/dummy/db/schema.rb +++ b/spec/dummy/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_02_28_122115) do +ActiveRecord::Schema.define(version: 2022_04_01_181023) do create_table "active_admin_comments", force: :cascade do |t| t.string "namespace" @@ -93,6 +93,7 @@ t.string "aasm_state" t.boolean "active", default: true t.string "shipping_status" + t.text "picture_data" t.index ["category_id"], name: "index_invoices_on_category_id" t.index ["city_id"], name: "index_invoices_on_city_id" end From e684a1bbd340ccca3e41e30ea494e1226015057a Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:10:37 -0300 Subject: [PATCH 06/10] feat(admin/invoice): include picture for shrine cases --- spec/dummy/app/admin/invoices.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/dummy/app/admin/invoices.rb b/spec/dummy/app/admin/invoices.rb index 47425e85..9d34d84a 100644 --- a/spec/dummy/app/admin/invoices.rb +++ b/spec/dummy/app/admin/invoices.rb @@ -1,6 +1,6 @@ ActiveAdmin.register Invoice do - permit_params :legal_date, :number, :paid, :state, :attachment, :photo, :category_id, - :city_id, :amount, :color, :updated_at, :active, item_ids: [], other_item_ids: [] + permit_params :legal_date, :number, :paid, :state, :attachment, :photo, :category_id, :city_id, + :amount, :color, :updated_at, :picture, :active, item_ids: [], other_item_ids: [] filter :id, as: :numeric_range_filter @@ -17,6 +17,7 @@ tag_column :state, interactive: true bool_column :paid image_column :photo, style: :thumb + image_column :picture, style: :jpg_small attachment_column :attachment number_column :amount, as: :currency, unit: "$", separator: "," toggle_bool_column :active @@ -35,6 +36,7 @@ list_row :details, localize: true image_row("Mi foto", :photo, style: :big, &:photo) attachment_row("My doc", :attachment, label: 'Download file', truncate: false, &:attachment) + image_row("Mi picture", :picture, image_options: { width: 100 }, &:picture) row :legal_date number_row("Monto", :amount, as: :human, &:amount) row :city @@ -87,6 +89,8 @@ f.input :photo + f.input :picture, as: :file + f.input :color, as: :color_picker, palette: Invoice.colors From 8bc29f13cdc2f01b94bf2eb7e6fa0e899a6a3ef8 Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:10:52 -0300 Subject: [PATCH 07/10] test(image-builder): include tests for shrine case --- spec/features/image_builder_spec.rb | 146 +++++++++++++++++++++------- 1 file changed, 111 insertions(+), 35 deletions(-) diff --git a/spec/features/image_builder_spec.rb b/spec/features/image_builder_spec.rb index 56d6aa18..73290ae5 100644 --- a/spec/features/image_builder_spec.rb +++ b/spec/features/image_builder_spec.rb @@ -12,64 +12,140 @@ def create_photo_invoice create_invoice(photo: File.new(ENGINE_RAILS_ROOT + 'spec/assets/Rails.png')) end - context "without options" do - before do - register_index(Invoice) do - image_column :photo + def create_picture_invoice + create_invoice(picture: File.new(ENGINE_RAILS_ROOT + 'spec/assets/Rails.png')) + end + + describe '#shrine' do + context "without options" do + before do + register_index(Invoice) do + image_column :picture + end + + create_picture_invoice + visit admin_invoices_path end - create_photo_invoice - visit admin_invoices_path + it "shows the attachent as an image" do + img = page.find('img') + expect(img[:src]).not_to be(nil) + end end - it "shows the attachent as an image" do - img = page.find('img') - expect(img[:src]).to match(/Rails.png/) + context "passing style option" do + let(:invoice) { create_picture_invoice } + + before do + register_index(Invoice) do + image_column :picture, style: :jpg_small + end + + invoice.picture_derivatives! + invoice.save! + visit admin_invoices_path + end + + it "shows the attachent as an image" do + img = page.find('img') + expect(img[:src]).not_to be(nil) + end + + it 'has the derivative' do + expect(invoice.picture_derivatives).to include(:jpg_small) + end end - end - context "passing style option" do - before do - register_index(Invoice) do - image_column :photo, style: :thumb + context "passing a block" do + before do + register_show(Invoice) do + image_row(:picture, &:picture) + end + + visit admin_invoice_path(create_picture_invoice) end - create_photo_invoice - visit admin_invoices_path + it "shows the attachent as an image" do + img = page.find('img') + expect(img[:src]).not_to be(nil) + end end - it "shows the attachent as an image" do - img = page.find('img') - expect(img[:src]).to match(%r{thumb/Rails.png}) + context "using a label" do + before do + register_show(Invoice) do + image_row("My Picture", :picture) + end + + visit admin_invoice_path(create_picture_invoice) + end + + it "shows custom label" do + expect(page).to have_content("My Picture") + end end end - context "passing a block" do - before do - register_show(Invoice) do - image_row(:photo, &:photo) + describe '#paperclip' do + context "without options" do + before do + register_index(Invoice) do + image_column :photo + end + + create_photo_invoice + visit admin_invoices_path end - visit admin_invoice_path(create_photo_invoice) + it "shows the attachent as an image" do + img = page.find('img') + expect(img[:src]).to match(/Rails.png/) + end end - it "shows the attachent as an image" do - img = page.find('img') - expect(img[:src]).to match(/Rails.png/) + context "passing style option" do + before do + register_index(Invoice) do + image_column :photo, style: :thumb + end + + create_photo_invoice + visit admin_invoices_path + end + + it "shows the attachent as an image" do + img = page.find('img') + expect(img[:src]).to match(%r{thumb/Rails.png}) + end end - end - context "using a label" do - before do - register_show(Invoice) do - image_row("Mi foto", :photo) + context "passing a block" do + before do + register_show(Invoice) do + image_row(:photo, &:photo) + end + + visit admin_invoice_path(create_photo_invoice) end - visit admin_invoice_path(create_photo_invoice) + it "shows the attachent as an image" do + img = page.find('img') + expect(img[:src]).to match(/Rails.png/) + end end - it "shows custom label" do - expect(page).to have_content("Mi Foto") + context "using a label" do + before do + register_show(Invoice) do + image_row("Mi foto", :photo) + end + + visit admin_invoice_path(create_photo_invoice) + end + + it "shows custom label" do + expect(page).to have_content("Mi Foto") + end end end end From 14eb6f6feeaaf39f0bd30ab245e968e9ccb83a51 Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 1 Apr 2022 18:37:23 -0300 Subject: [PATCH 08/10] feat(config): include aptfile and instalation in circleci --- .circleci/config.yml | 6 ++++++ spec/dummy/Aptfile | 5 +++++ 2 files changed, 11 insertions(+) create mode 100644 spec/dummy/Aptfile diff --git a/.circleci/config.yml b/.circleci/config.yml index d07339b6..2fb19cde 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,6 +32,12 @@ commands: keys: - bundler-dependencies-{{ checksum "Gemfile.lock" }} - bundler-dependencies- + - run: + name: Install apt and vips buildpack dependencies + command: | + cd spec/dummy/ + xargs -a Aptfile sudo apt-get install + sudo apt-get install libvips - run: name: Install bundle dependencies command: | diff --git a/spec/dummy/Aptfile b/spec/dummy/Aptfile new file mode 100644 index 00000000..02b92fa8 --- /dev/null +++ b/spec/dummy/Aptfile @@ -0,0 +1,5 @@ +libglib2.0-0 +libglib2.0-dev +libpoppler-glib8 +libwebp-dev +webp From 90ab956a423589d98290a4b01058025e7fb0891a Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 8 Apr 2022 17:22:09 -0400 Subject: [PATCH 09/10] feat(images-instructions): re name instructions and include shrine explication --- docs/images.md | 53 ++++++++++++++++++++++++++++++++++++++++ docs/paperclip_images.md | 25 ------------------- 2 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 docs/images.md delete mode 100644 docs/paperclip_images.md diff --git a/docs/images.md b/docs/images.md new file mode 100644 index 00000000..7e49d34b --- /dev/null +++ b/docs/images.md @@ -0,0 +1,53 @@ +# Images Integration + +## Paperclip + +### Image Row + +```ruby +show do + attributes_table do + image_row :photo + end +end +``` + + + +### Image Column + +```ruby +index do + image_column :photo, style: :thumb +end +``` + + + +> You can pass `style` attribute matching paperclip's style definition + +## Shrine + +### Image Row + +The Shrine implementation receives an optional `image_options` which is then used as the options for the [`image_tag`](https://apidock.com/rails/ActionView/Helpers/AssetTagHelper/image_tag) method. +```ruby +show do + attributes_table do + image_row :photo, image_options: { width: 400 } + end +end +``` + + + +### Image Column + +To use the Shrine [derivatives](https://shrinerb.com/docs/plugins/derivatives) you can use the `style` option with the name of the derivative like the example below. In this case you would need to have a derivative created with the `'jpg_small'` name. +```ruby +index do + image_column :photo, style: :jpg_small +end +``` + + diff --git a/docs/paperclip_images.md b/docs/paperclip_images.md deleted file mode 100644 index 84a26649..00000000 --- a/docs/paperclip_images.md +++ /dev/null @@ -1,25 +0,0 @@ -# Paperclip Integration - -## Image Row - -```ruby -show do - attributes_table do - image_row :photo - end -end -``` - - - -## Image Column - -```ruby -index do - image_column :photo, style: :thumb -end -``` - - - -> You can pass `style` attribute matching paperclip's style definition From 98c8c00ce0ebccd0e8b197876a4d2eee7b9e7f73 Mon Sep 17 00:00:00 2001 From: Gabriel Lyon Date: Fri, 8 Apr 2022 17:34:19 -0400 Subject: [PATCH 10/10] feat(readme): update images implementation instructions --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b56d193e..7cc9fe81 100644 --- a/README.md +++ b/README.md @@ -78,13 +78,13 @@ Displays a paperclip link with attachment related icon into index and show views [Read more!](docs/paperclip_attachment.md) -#### Paperclip Image +#### Images -Displays a paperclip image into index and show views +Display images in the index and show views. This implementation supports [Shrine](https://github.com/shrinerb/shrine) and [Paperclip](https://github.com/thoughtbot/paperclip). -[Read more!](docs/paperclip_images.md) +[Read more!](docs/images.md) #### AASM Integration