RejectKaigi 2017で発表した資料です。ActiveStorageの機能を紹介する過程で、ファイルアップロードを実装するのに必要な要件と選択肢について解説しています。
File Upload 2017@willnet
View Slide
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 < ApplicationRecordhas_one_attached :avatarendclass Gallery < ApplicationRecordhas_many_attached :photosend
Ϗϡʔ(ϑΥʔϜ)
ίϯτϩʔϥ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.'elserender :newendend
ը૾ͷදࣔ
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
Ξοϓϩʔυઌͷઃఆ(Ұ෦)config/storage.ymltest:service: Diskroot: local:service: Diskroot: # amazon:# service: S3# access_key_id: # secret_access_key: # region: us-east-1# bucket: your_own_bucket
config/environments/development.rbͳͲconfig.active_storage.service = :local
ϛϥʔͷઃఆಉ࣌ʹෳͷΫϥυετϨʔδʹΞοϓϩʔυͯ͠όοΫΞοϓͰ͖Δconfig/storage.ymlmirror:service: Mirrorprimary: amazonmirrors: [ 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 createmessage = Message.create! params.require(:message).permit(:title, :content)message.images.attach(params[:message][:images])redirect_to messageend# ུend
·ͱΊActive StorageͷػೳհΛ௨ͯ͡ɺϑΝΠϧΞοϓϩʔυͷ• ߟྀ͖͢ཁૉ• ͦͷબࢶͷҰ෦Λհ͠·ͨ͠
·ͱΊ• ϑΝΠϧΞοϓϩʔυͷ͠͞ɺΘΓ·͔ͨ͠ʁ• ສೳͳϥΠϒϥϦͳ͍ͷͰɺཁ݅ݟ͍͚ͯ·͠ΐ͏
Happy File Uploading !"⬆!