Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
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
1.2k
rails g authenticationから学ぶRails8.0時代の認証
willnet
5
4.1k
What's a well-behaved Rails extension gem?
willnet
0
710
Sidekiq vs Solid Queue
willnet
14
13k
どうしてこうなった?から理解するActive Recordの関連の裏側
willnet
6
1.6k
Exceptional Rails
willnet
6
7.9k
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
S3 VectorsとStrands Agentsを利用したAgentic RAGシステムの構築
tosuri13
6
310
チームをチームにするEM
hitode909
0
330
AIコーディングエージェント(Gemini)
kondai24
0
220
251126 TestState APIってなんだっけ?Step Functionsテストどう変わる?
east_takumi
0
320
AIコーディングエージェント(NotebookLM)
kondai24
0
190
新卒エンジニアのプルリクエスト with AI駆動
fukunaga2025
0
220
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
130
これだけで丸わかり!LangChain v1.0 アップデートまとめ
os1ma
6
1.8k
Building AI Agents with TypeScript #TSKaigiHokuriku
izumin5210
6
1.3k
dotfiles 式年遷宮 令和最新版
masawada
1
770
從冷知識到漏洞,你不懂的 Web,駭客懂 - Huli @ WebConf Taiwan 2025
aszx87410
2
2.6k
SwiftUIで本格音ゲー実装してみた
hypebeans
0
370
Featured
See All Featured
A designer walks into a library…
pauljervisheath
210
24k
Documentation Writing (for coders)
carmenintech
76
5.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.8k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.1k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
3k
Rails Girls Zürich Keynote
gr2m
95
14k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Scaling GitHub
holman
464
140k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.7k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
Navigating Team Friction
lara
191
16k
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 !"⬆!