Slide 1

Slide 1 text

ActiveStorage Radoslav Stankov 13/03/2018

Slide 2

Slide 2 text

Radoslav Stankov @rstankov http://rstankov.com http://github.com/rstankov

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text


 http://react-not-a-conf.com
 28th April

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text


 http://edgeguides.rubyonrails.org/active_storage_overview.html


Slide 7

Slide 7 text

# == Schema Information # # Table name: speakers # # id :integer not null, primary # name :string(255) not null # bio :text # created_at :datetime # updated_at :datetime # class Speaker < ApplicationRecord validates :name, presence: true end

Slide 8

Slide 8 text

# == Schema Information # # Table name: speakers # # id :integer not null, primary # name :string(255) not null # bio :text # created_at :datetime # updated_at :datetime # class Speaker < ApplicationRecord validates :name, presence: true end

Slide 9

Slide 9 text

# == Schema Information # # Table name: speakers # # id :integer not null, primary # name :string(255) not null # bio :text # created_at :datetime # updated_at :datetime # class Speaker < ApplicationRecord validates :name, presence: true end !

Slide 10

Slide 10 text

# == Schema Information # # Table name: speakers # # id :integer not null, primary # name :string(255) not null # bio :text # created_at :datetime # updated_at :datetime # class Speaker < ApplicationRecord validates :name, presence: true end https://rubygems.org/gems/annotate

Slide 11

Slide 11 text

# == Schema Information # # Table name: speakers # # id :integer not null, primary # name :string(255) not null # bio :text # created_at :datetime # updated_at :datetime # class Speaker < ApplicationRecord validates :name, presence: true end

Slide 12

Slide 12 text

# == Schema Information # # Table name: speakers # # id :integer not null, primary # name :string(255) not null # bio :text # created_at :datetime # updated_at :datetime # class Speaker < ApplicationRecord validates :name, presence: true has_one_attached :photo end

Slide 13

Slide 13 text

speaker.photo.attach(params[:photo])

Slide 14

Slide 14 text

speaker.photo.nil?
 speaker.photo.present? speaker.photo.attached?

Slide 15

Slide 15 text

speaker.photo.purge speaker.photo.purge_later

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

# == Schema Information # # Table name: speakers # # id :integer not null, primary # name :string(255) not null # bio :text # created_at :datetime # updated_at :datetime # class Speaker < ApplicationRecord validates :name, presence: true has_one_attached :photo end

Slide 18

Slide 18 text

run rails active_storage:install run rails db:migrate

Slide 19

Slide 19 text

create_table 'active_storage_attachments' do |t| t.string 'name', null: false t.string 'record_type', null: false t.bigint 'record_id', null: false t.bigint 'blob_id', null: false t.datetime 'created_at', null: false end create_table 'active_storage_blobs' do |t| t.string 'key', null: false t.string 'filename', null: false t.string 'content_type' t.text 'metadata' t.bigint 'byte_size', null: false t.string 'checksum', null: false t.datetime 'created_at', null: false end

Slide 20

Slide 20 text

speaker.photo.metadata { 'identified' => true, 'width' => 80, 'height' => 80, 'analyzed' => true }

Slide 21

Slide 21 text

speaker.photo.url #=> NoMethodError: undefined method `url' for #

Slide 22

Slide 22 text

speaker.photo.service_url

Slide 23

Slide 23 text

image_tag speaker.photo url_for speaker.photo link_to 'download', speaker.photo

Slide 24

Slide 24 text

<% Speaker.all do |speaker| %> <%= image_tag speaker.photo %> <% end %>

Slide 25

Slide 25 text

ArgumentError in Admin::Speakers#index Showing /Users/rstankov/Projects/ConferenceBox/app/views/admin/speakers/index.html.slim where line #18 raised:

Slide 26

Slide 26 text

ArgumentError in Admin::Speakers#index Showing /Users/rstankov/Projects/ConferenceBox/app/views/admin/speakers/index.html.slim where line #18 raised: "

Slide 27

Slide 27 text

<% Speaker.all do |speaker| %> <%= image_tag speaker.photo if speaker.photo.attached? %> <% end %>

Slide 28

Slide 28 text

↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.8ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 35], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.4ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 30], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.6ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 40], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Blob Load (1.3ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2 [["id", 16], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.0ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 23], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 18], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (2.0ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 49], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (2.0ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 7], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 21], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 11], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.1ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 10], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.4ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 50], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.0ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 52], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.2ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 17], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]] ↳ app/views/admin/speakers/index.html.slim:17 ActiveStorage::Attachment Load (1.8ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 38], ["record_type", "Speaker"], ["name", "photo"], ["LIMIT", 1]]

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

<% Speaker.with_attached_photo.all do |speaker| %> <%= image_tag speaker.photo if speaker.photo.attached? %> <% end %>

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

image_tag image.variant(resize: '100x100')

Slide 35

Slide 35 text

ActiveStorage BlobsController ActiveStorage DiskController

Slide 36

Slide 36 text

ActiveStorage BlobsController AWS

Slide 37

Slide 37 text

image_tag image.variant(resize: '100x100')

Slide 38

Slide 38 text

image_tag image.variant(resize: '100x100').service_url

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

speaker.photo.variant(resize:'100x100').processed.service_url

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text


 http://imagemagick.org/script/index.php


Slide 43

Slide 43 text


 https://www.imagemagick.org/script/command-line-options.php


Slide 44

Slide 44 text

def speaker_photo(speaker, size:) speaker.photo.variant( resize: "#{size}x#{size}^", gravity: 'center', crop: "#{size}x#{size}+0+0" ) end

Slide 45

Slide 45 text

module HasVariants def has_one_attached_with_variants(attribute_name, variants = {}) has_one_attached attribute_name define_method "#{attribute_name}_variant" do |variant_name| attachment = public_send(attribute_name) return unless attachment.attached? variant_options = variants.fetch(variant_name) do raise "UnknownVariant '#{variant_name}', not in #{variants.keys.join})" end attachment.variant(*variant_options) end end end #

Slide 46

Slide 46 text

class Speaker < ApplicationRecord extend HasVariants has_one_attached_with_variants :photo, { small: { resize: '100x100' }, medium: { resize: '200x200' } # ... } end speaker.photo_vartiant(:small) #

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

$ Disk Service % AWS Service & Azure Service ' Google Cloud Service ( Mirror Service Services

Slide 50

Slide 50 text

<%= form.file_field :photos, multiple: true %> 
 http://edgeguides.rubyonrails.org/active_storage_overview.html#has-many-attached


Slide 51

Slide 51 text

image_tag talk.video.preview(resize: '100x100') image_tag talk.slides.preview(resize: '100x100') 
 http://edgeguides.rubyonrails.org/active_storage_overview.html#previewing-files


Slide 52

Slide 52 text


 http://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads
 Form Rails AWS <%= form.file_field :photos %>

Slide 53

Slide 53 text


 http://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads
 Form AWS <%= form.file_field :photos, direct_upload: true %>

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

Thanks )

Slide 57

Slide 57 text

https://speakerdeck.com/rstankov/activestorage