Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
File Upload 2017
Search
Shinichi Maeshima
August 19, 2017
Programming
7
9.4k
File Upload 2017
RejectKaigi 2017で発表した資料です。ActiveStorageの機能を紹介する過程で、ファイルアップロードを実装するのに必要な要件と選択肢について解説しています。
Shinichi Maeshima
August 19, 2017
Tweet
Share
More Decks by Shinichi Maeshima
See All by Shinichi Maeshima
メタプログラミングRuby問題集の活用
willnet
2
600
rails g authenticationから学ぶRails8.0時代の認証
willnet
5
3.6k
What's a well-behaved Rails extension gem?
willnet
0
570
Sidekiq vs Solid Queue
willnet
14
13k
どうしてこうなった?から理解するActive Recordの関連の裏側
willnet
6
1.5k
Exceptional Rails
willnet
6
7.8k
Breaking the Flaky Test Cycle
willnet
2
2.3k
mrskで広がるインフラの選択肢
willnet
1
1.1k
アプリケーションを長期にわたって無理なく運用するためのたったひとつの方法
willnet
2
2.2k
Other Decks in Programming
See All in Programming
Vueのバリデーション、結局どれを選べばいい? ― 自作バリデーションの限界と、脱却までの道のり ― / Which Vue Validation Library Should We Really Use? The Limits of Self-Made Validation and How I Finally Moved On
neginasu
3
1.8k
なんでRustの環境構築してないのにRust製のツールが動くの? / Why Do Rust-Based Tools Run Without a Rust Environment?
ssssota
14
47k
React Nativeならぬ"Vue Native"が実現するかも?_新世代マルチプラットフォーム開発フレームワークのLynxとLynxのVue.js対応を追ってみよう_Vue Lynx
yut0naga1_fa
2
2k
エンジニアに事業やプロダクトを理解してもらうためにやってること
murabayashi
0
140
Node-REDのノードの開発・活用事例とコミュニティとの関わり(Node-RED Con Nagoya 2025)
404background
0
120
チームのテスト力を総合的に鍛えてシフトレフトを推進する/Shifting Left with Software Testing Improvements
goyoki
4
2.2k
Dive into Triton Internals
appleparan
0
460
Webサーバーサイド言語としてのRustについて
kouyuume
1
5.1k
Researchlyの開発で参考にしたデザイン
adsholoko
0
110
alien-signals と自作 OSS で実現する フレームワーク非依存な ロジック共通化の探求 / Exploring Framework-Agnostic Logic Sharing with alien-signals and Custom OSS
aoseyuu
3
5.8k
Blazing Fast UI Development with Compose Hot Reload (Bangladesh KUG, October 2025)
zsmb
2
480
ボトムアップの生成AI活用を推進する社内AIエージェント開発
aku11i
0
1.5k
Featured
See All Featured
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.7k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
9
960
Product Roadmaps are Hard
iamctodd
PRO
55
11k
Raft: Consensus for Rubyists
vanstee
140
7.2k
Git: the NoSQL Database
bkeepers
PRO
431
66k
Stop Working from a Prison Cell
hatefulcrawdad
272
21k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.2k
Imperfection Machines: The Place of Print at Facebook
scottboms
269
13k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.3k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
116
20k
BBQ
matthewcrist
89
9.9k
Transcript
File Upload 2017 @willnet
RejectKaigi • ;ͭ͏ͷRailsΤϯδχΞͩͱMRI͍ͬͨ͡Γ͠ͳ͍ͷͰͳ͔ͳ ͔CFPͩͤͳ͍ • ͔͠͠Α͘Α͘ߟ͑ΔͱRESTAPIɺΞϓϦέʔγϣϯαʔό ͳͲͷςʔϚ࠾͞ΕͯΔ • ॲཧܥҎ֎ͷͰ௨Δͱࢥ͏Μ͚ͩͲԿ͔͔͋ͬͨͳ…
RubyKaigiͱࢲ • File UploadͳΒݟ͋Δ͍͚͠ΔͷͰʁ • ؾ͍ͮͨͷ͕ఏग़ظݶޙ !
RejectKaigiͰͦ͏
ࣗݾհ • લౡਅҰ aka @willnet or @netwillnet • ginza.rb ͔Βདྷ·ͨ͠
• ϑϦʔϥϯεRailsٕज़ސ • https://github.com/willnet • https://twitter.com/netwillnet • http://blog.willnet.in
ؔ࿈ॻ੶ WEB+DB PRESS Vol.95 ͰϑΝΠϧΞοϓϩʔυͷΛॻ͖·ͨ͠
File Upload
File Upload͍ͬͯ͠ΜͰ͢Α…! • ϑΝΠϧΛͲ͜Ͱม͢Δ͔ • Ͳ͜ʹอଘ͢Δ͔ • όϦσʔγϣϯΛͲ͏͢Δ͔ • ηΩϡϦςΟΛͲ͏୲อ͢Δ͔
• շదʹϑΝΠϧΛΞοϓϩʔυ͢ΔʹͲ͏͢Δ͔ • Ξοϓϩʔυͨ͠ϑΝΠϧͷΞΫηεݖݶ
ϑΝΠϧΞοϓϩʔυػೳ • ଟ͘ͷߟྀ͖͢ཁૉ͕͋Δ • εΫϥονͰ࣮͢Δͷ͍ͨΜ
gemΛ͓͏ !
RubyͷओͳϑΝΠϧΞοϓϩʔυϥΠϒϥϦ • paperclip • carrierwave • dragonfly • refile •
shrine • attache • active_storage(new!)
ͲͷϥΠϒϥϦΛ͏ͱ͍͍ΜͰ͢ ͔ʙʁ ! ✋
ཁ ݅ ࣍ ୈ
ͱ͍ͬͯԿΛͲ͏બΜͩΒ͍͍ͷ͔… ϑΝΠϧΞοϓϩʔυͷ • ߟྀ͖͢ཁૉ • ͦͷબࢶ ͱϥΠϒϥϦͷػೳΛѲ͢ΔͱબΔͷͰ
શ෦͢ͷແཧ
ͦ͜Ͱࠓ (RailsͷͰڪॖͰ͕͢)ΈΜͳؾʹͳΔActive Storageͷػೳհ Λ௨ͯ͡ϑΝΠϧΞοϓϩʔυશൠʹ͍ͭͯ͠·͢
ͦͦActive Storageͱʁ • Rails 5.2ͰೖΔ༧ఆͷػೳ • mountable engineͱͯ͠࡞ΒΕͨ • ͭ·ΓಠࣗͷϧʔςΟϯάɺίϯτϩʔϥɺϞσϧ͕͋Δ
Active Storageͷಛ • ϙϦϞʔϑΟοΫؔ࿈ • ΞΫηε࣌ม • ੍࣌ؒݶ͖ͷURLΛ؆୯ʹѻ͑Δ • μΠϨΫτΞοϓϩʔυରԠ
• ϛϥʔػೳ
Active Storage Λ͏લͷ४උ AttachmentͱBlob༻ͷςʔϒϧΛ࡞Δ ./bin/rails active_storage:install ./bin/rails db:migrate
ϙϦϞʔϑΟοΫؔ࿈ • ϑΝΠϧཧ༻ͷϞσϧ͕༻ҙ͞Ε͍ͯΔ • Attachment (தؒςʔϒϧ) • Blob (ϑΝΠϧͷϝλใ) •
UserͳͲͷϞσϧʹϑΝΠϧ༻ͷΧϥϜΛՃ͠ͳ͍ܗࣜ • ͯ͢ͷϑΝΠϧΛˢͷ2ͭͰཧ͢Δ
ϝϦοτ • εΩʔϚͷมߋʹॊೈ
ϝϦοτͷྫ • 1Ϣʔβ1ΞόλʔͰӡ༻͍͕ͯͨ͠ɺ1ϢʔβෳΞόλʔʹ ༷มߋ͕͋ͬͨ • ଞϥΠϒϥϦͩͱςʔϒϧͷՃ͕ඞཁʹͳΔ • Active StorageͩͱεΩʔϚใͷมߋ͕ඞཁͳ͍
σϝϦοτ ͯ͢ͷछྨͷϑΝΠϧใ͕Blobʹ֨ೲ͞ΕΔ • Ξόλʔ • ը૾Ξοϓϩʔυ • ϑΝΠϧڞ༗
Ϟσϧ class User < ApplicationRecord has_one_attached :avatar end class Gallery
< ApplicationRecord has_many_attached :photos end
Ϗϡʔ(ϑΥʔϜ) <%= form.file_field :avatar %>
ίϯτϩʔϥ def create @user = User.new(user_params) if @user.save @user.avatar.attach( io:
params[:user][:avatar], filename: 'avatar.jpeg' ) redirect_to @user, notice: 'User was successfully created.' else render :new end end
ը૾ͷදࣔ <%= image_tag user.avatar.variant(resize: "100x100") %>
Active StorageΞΫηε࣌มܗࣜ • dragonfly, refile, attacheͳͲ͕࠾༻͍ͯ͠Δܗࣜ • มͷܗࣜΛؚΊͨURLͰΞΫηε • มܗࣜΛ૿͢ͱ͖ͷࣄલ४උ͕ෆཁͰָ
• ΞϓϦέʔγϣϯαʔόʹෛՙ͕͔͔Δ߹͕͋Δ
ෛՙ͕͔͔Δྫ 1. ը૾ΛҰʹͨ͘͞ΜΞοϓϩʔυ 2. ը૾ҰཡϖʔδʹભҠ 3. ͨ͘͞Μͷը૾ͷม͕ಉ࣌ʹ࣮ߦ͞ΕΔ
ෛՙΛࢄ͠Α͏ͱ͢ΔϥΠϒϥϦ͋Δ • attache͕࠾༻͍ͯ͠ΔΓํ • (·ͩࣄͰ͔ͭ͑Δײ͡Ͱͳ͍Ͱ͢) • ΞϓϦέʔγϣϯͱಠཱͨ͠ը૾༻ͷαʔόΛཱͯͯɺAPIͰ ΓͱΓ͢Δ • CloudinaryΈ͍ͨͳPaasΛࣗલͰӡ༻͢ΔΠϝʔδ
• microservice
Active StorageͳΒͰͷಛ • ॳճΞΫηε࣌ʹมͨ͠ͷΛΫϥυʹΞοϓϩʔυ • ΫϥυͷURLϦμΠϨΫτ • σϑΥϧτ5ͷظݶ͖URL • ύʔϚωϯτͳURLΞϓϦέʔγϣϯαʔόͷURL
ϑΝΠϧͷΞΫηεڐՄ • Active Storageظݶ͖ͷURLΛ࠾༻ • ΊͣΒ͍͠ • େྨਪͷ͍͠URLͰOKͱ͢Δ͜ͱ͕ଟ͍ • ݫີʹݖݶΛνΣοΫ͢ΔͱΞϓϦέʔγϣϯαʔόʹෛՙ
͕͔͔Δ • Active Storage ↑ͷΛ͏·͘ղܾ͍ͯ͠Δ
ଞͷมܗࣜ • Ξοϓϩʔυ࣌ʹม • όοΫάϥϯυͰม
Ξοϓϩʔυ࣌ʹม • paperclip, carrierwaveͳͲ͕࠾༻ • ࣮తʹҰ൪ૉͰཧղ͍͢͠ • ϑΝΠϧม͢Δ࣌ؒɺϢʔβΛͨͤΔ͜ͱʹͳΔ • ΞϓϦέʔγϣϯαʔόʹෛՙ͕͔͔Δ
• ม͢Δछྨ͕ଟ͍ • ϑΝΠϧΞοϓϩʔυ͕ूத͢Δ࣌ؒଳ
όοΫάϥϯυͰม • shrine͕࠾༻ • ΞοϓϩʔυͷλΠϛϯάͰΩϡʔʹมλεΫΛ٧ΊΔ • όοΫάϥϯυϫʔΧʔ͕ॱ൪ʹม͍ͯ͘͠ͷͰෛՙͷ ΛܰݮͰ͖Δ • ม͕ऴΘΔલʹը૾͕ඞཁʹͳΔέʔεͰࠔΔ
μΠϨΫτΞοϓϩʔυ • ΞϓϦέʔγϣϯαʔόΛܦ༝ͤͣΫϥυʹΞοϓϩʔ υ • ΞϓϦέʔγϣϯαʔόͷෛՙݮ • ͍͔ͭ͘ͷϥΠϒϥϦͰαϙʔτ͍ͯ͠Δ • ϑΥʔϜͷsubmit࣌ʹΞοϓϩʔυ
μΠϨΫτΞοϓϩʔυ application.js //= require activestorage _form.html.erb <%= form.filefield :avatar, direct_upload:
true %>
Ξοϓϩʔυઌͷઃఆ(Ұ෦) config/storage.yml test: service: Disk root: <%= Rails.root.join("tmp/storage") %> local:
service: Disk root: <%= Rails.root.join("storage") %> # amazon: # service: S3 # access_key_id: <%= Rails.application.secrets.dig(:aws, :access_key_id) %> # secret_access_key: <%= Rails.application.secrets.dig(:aws, :secret_access_key) %> # region: us-east-1 # bucket: your_own_bucket
config/environments/development.rbͳͲ config.active_storage.service = :local
ϛϥʔͷઃఆ ಉ࣌ʹෳͷΫϥυετϨʔδʹΞοϓϩʔυͯ͠όοΫΞο ϓͰ͖Δ config/storage.yml mirror: service: Mirror primary: amazon mirrors:
[ google, microsoft ]
Ұ௨Γಛͨ͠
Կ͔Γͯͳ͍ͷ͋ΔΑ͏ͳ!
Active Storegeʹݱঢ়Γ͍ͯͳ͍Α͏ʹΈ͑ Δͷ • όϦσʔγϣϯ • cache
όϦσʔγϣϯ େͷϥΠϒϥϦʹόϦσʔγϣϯͷαϙʔτ͕͋Δ͕ɺݱঢ় ͷActive Storegeʹͳ͔ͥଘࡏ͠ͳ͍
όϦσʔγϣϯྫ • ϑΝΠϧܗࣜͷ֬ೝ • ֦ுࢠ • Content Type
όϦσʔγϣϯྫ • ϑΝΠϧͷେ͖͞ • ༰ྔ • ը૾ͷॎ෯ԣ෯: Biggest image in
the smallest space
όϦσʔγϣϯ • PRνϟϯε? • ͔͠͠Ϟσϧ͕ڞ༗ͳͷͰ࣮ͮ͠Β͍ • ྫ: Ξόλʔ5MB͚ͩͲͦΕҎ֎ͷࣸਅ10MB·ͰOK
cache • ଞͷϥΠϒϥϦͰ΄΅αϙʔτ͞Ε͍ͯΔ • όϦσʔγϣϯΤϥʔ࣌ͷϑΝΠϧஔ͖
cacheͷྫ 1. ը૾ͱίϝϯτΛϑΥʔϜ͔Βૹ৴ 2. ίϝϯτ͕όϦσʔγϣϯΤϥʔ 3. ը૾cacheྖҬʹอଘ͍ͯ͠ΔͷͰίϝϯτ͚ͩमਖ਼ͯ͠࠶ ૹ৴ 4. ը૾cacheྖҬ͔Βຊ൪ྖҬʹҠಈ͢Δ
cache αϯϓϧίʔυ͕͜͏ͳͷͰɺຖճΞοϓϩʔυ͠Ζͱ͍͏ׂΓ Γʹݟ͑Δ class MessagesController < ApplicationController # ུ def
create message = Message.create! params.require(:message).permit(:title, :content) message.images.attach(params[:message][:images]) redirect_to message end # ུ end
·ͱΊ Active StorageͷػೳհΛ௨ͯ͡ɺϑΝΠϧΞοϓϩʔυͷ • ߟྀ͖͢ཁૉ • ͦͷબࢶ ͷҰ෦Λհ͠·ͨ͠
·ͱΊ • ϑΝΠϧΞοϓϩʔυͷ͠͞ɺΘΓ·͔ͨ͠ʁ • ສೳͳϥΠϒϥϦͳ͍ͷͰɺཁ݅ݟ͍͚ͯ·͠ΐ͏
Happy File Uploading !"⬆!