$30 off During Our Annual Pro Sale. View Details »

ActiveStorage

 ActiveStorage

Radoslav Stankov

March 13, 2018
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

  1. ActiveStorage
    Radoslav Stankov 13/03/2018

    View Slide

  2. Radoslav Stankov
    @rstankov

    http://rstankov.com

    http://github.com/rstankov

    View Slide

  3. View Slide


  4. http://react-not-a-conf.com

    28th April

    View Slide

  5. View Slide


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


    View Slide

  7. # == 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

    View Slide

  8. # == 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

    View Slide

  9. # == 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
    !

    View Slide

  10. # == 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

    View Slide

  11. # == 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

    View Slide

  12. # == 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

    View Slide

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

    View Slide

  14. speaker.photo.nil?

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

    View Slide

  15. speaker.photo.purge
    speaker.photo.purge_later

    View Slide

  16. View Slide

  17. # == 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

    View Slide

  18. run rails active_storage:install
    run rails db:migrate

    View Slide

  19. 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

    View Slide

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

    View Slide

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

    View Slide

  22. speaker.photo.service_url

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  28. ↳ 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]]

    View Slide

  29. View Slide

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

    View Slide

  31. View Slide

  32. View Slide

  33. View Slide

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

    View Slide

  35. ActiveStorage
    BlobsController
    ActiveStorage
    DiskController

    View Slide

  36. ActiveStorage
    BlobsController
    AWS

    View Slide

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

    View Slide

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

    View Slide

  39. View Slide

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

    View Slide

  41. View Slide


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


    View Slide


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


    View Slide

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

    View Slide

  45. 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
    #

    View Slide

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

    View Slide

  47. View Slide

  48. View Slide

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

    View Slide

  50. <%= form.file_field :photos, multiple: true %>

    http://edgeguides.rubyonrails.org/active_storage_overview.html#has-many-attached


    View Slide

  51. image_tag talk.video.preview(resize: '100x100')
    image_tag talk.slides.preview(resize: '100x100')

    http://edgeguides.rubyonrails.org/active_storage_overview.html#previewing-files


    View Slide


  52. http://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads

    Form Rails AWS
    <%= form.file_field :photos %>

    View Slide


  53. http://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads

    Form AWS
    <%= form.file_field :photos, direct_upload: true %>

    View Slide

  54. View Slide

  55. View Slide

  56. Thanks )

    View Slide

  57. https://speakerdeck.com/rstankov/activestorage

    View Slide