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
Sidekiq vs Solid Queue
willnet
14
12k
どうしてこうなった?から理解するActive Recordの関連の裏側
willnet
6
1.5k
Exceptional Rails
willnet
6
7.6k
Breaking the Flaky Test Cycle
willnet
2
2.2k
mrskで広がるインフラの選択肢
willnet
1
1.1k
アプリケーションを長期にわたって無理なく運用するためのたったひとつの方法
willnet
2
2.2k
HotwireからDHHが考えるこれからのRailsとJSの付き合い方を知る
willnet
14
14k
Rails6.1で新しく入る機能について
willnet
12
16k
Concerns about Concerns
willnet
11
35k
Other Decks in Programming
See All in Programming
Infer入門
riru
4
1.1k
物語を動かす行動"量" #エンジニアニメ
konifar
12
3.2k
Claude Code で Astro blog を Pages から Workers へ移行してみた
codehex
0
180
What's new in Adaptive Android development
fornewid
0
140
ワープロって実は計算機で
pepepper
2
1.1k
Amazon Q CLI開発で学んだAIコーディングツールの使い方
licux
3
180
「リーダーは意思決定する人」って本当?~ 学びを現場で活かす、リーダー4ヶ月目の試行錯誤 ~
marina1017
0
150
Scale out your Claude Code ~自社専用Agentで10xする開発プロセス~
yukukotani
8
1.5k
Flutterと Vibe Coding で個人開発!
hyshu
1
230
STUNMESH-go: Wireguard NAT穿隧工具的源起與介紹
tjjh89017
0
110
AIのメモリー
watany
13
1.3k
Workers を定期実行する方法は一つじゃない
rokuosan
0
140
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.4k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
Adopting Sorbet at Scale
ufuk
77
9.5k
Making Projects Easy
brettharned
117
6.3k
YesSQL, Process and Tooling at Scale
rocio
173
14k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
30
2.2k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
21
1.4k
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 !"⬆!