SlideShare ist ein Scribd-Unternehmen logo
1 von 94
Downloaden Sie, um offline zu lesen
File Upload 2015
@choonkeat

choonkeat.com
jollygoodcode.com
How’s that predefined styles
doing for you?
has_attached_file :asset, styles: {
thumb: "100x100#"
}
How’s that predefined styles
doing for you?
has_attached_file :asset, styles: {
thumb: "100x100#",
medium: "320x>"
}
How’s that predefined styles
doing for you?
has_attached_file :asset, styles: {
thumb: "100x100#",
medium: "320x>",
large: "1024x>"
}
How’s that predefined styles
doing for you?
has_attached_file :asset, styles: {
thumb: "100x100#",
medium: "320x>",

big: "640x>",
large: "1024x>"
}
Names starting to lose
meaning…
How’s that predefined styles
doing for you?
has_attached_file :asset, styles: {
thumb: "100x100#", thumb2x: "200x200#",
medium: "320x>", medium2x: "640x>",

big: "640x>", big2x: "1280x>",
large: "1024x>", large2x: "2048x>"
}
How’s that predefined styles
doing for you?
has_attached_file :asset, styles: {
thumb: "100x100#", thumb2x: "200x200#",
medium: "320x>", medium2x: "640x>",

big: "640x>", big2x: "1280x>",
large: "1024x>", large2x: "2048x>"
}
Reprocess all the production files, each
time, we make changes.
404 while rake runs or do at midnight?
How’s that transformation
juggling doing for you?
How’s that transformation
juggling doing for you?
class MyUploader < CarrierWave::Uploader::Base
version :thumb do
process resize_to_fill: [280, 280]
end
version :small_thumb, from_version: :thumb do
process resize_to_fill: [20, 20]
end
end
How’s that transformation
juggling doing for you?
class MyUploader < CarrierWave::Uploader::Base
version :thumb do
process resize_to_fill: [280, 280]
end
version :small_thumb, from_version: :thumb do
process resize_to_fill: [20, 20]
end
end
Did your users wait in the foreground
or background?
How’s that file path config
doing for you?
How’s that file path config
doing for you?
class Avatar < ActiveRecord::Base
has_attached_file :image,

url: '/system/:class/:attachment/:id/:hash-:style.:extension',
hash_secret: Rails.application.secrets.paperclip
end
How’s that file path config
doing for you?
class Avatar < ActiveRecord::Base
has_attached_file :image,

url: '/system/:class/:attachment/:id/:hash-:style.:extension',
hash_secret: Rails.application.secrets.paperclip
end
You sure this is the format?
Or will they need to change?
How’s that file path config
doing for you?
class Avatar < ActiveRecord::Base
has_attached_file :image,

url: '/system/:class/:attachment/:id/:hash-:style.:extension',
hash_secret: Rails.application.secrets.paperclip
end
How’s that file path config
doing for you?
class Avatar < ActiveRecord::Base
has_attached_file :image,

url: '/system/:class/:attachment/:id/:hash-:style.:extension',
hash_secret: Rails.application.secrets.paperclip
end
How’s that file path config
doing for you?
CarrierWave.configure do |config|
config.permissions = 0666
config.directory_permissions = 0777
config.storage = :file
end
How’s that file path config
doing for you?
CarrierWave.configure do |config|
config.permissions = 0666
config.directory_permissions = 0777
config.storage = :file
end
Did you configure your MySQL
data file in your app too?
How’s that file path config
doing for you?
class Avatar < ActiveRecord::Base
self.table = {
name: "avatars",
data: "/var/lib/mysql/data/avatars.MYD",
index: "/var/lib/mysql/data/avatars.MYI"
}
end
Did you configure your MySQL
data file in your app too?
How’s that form validation
error dance doing for you?
How’s that form validation
error dance doing for you?
• User chooses a file
• Submit & wait for file to upload ⌛…
• Validation error: “Username is already taken!”
• Re-render form
How’s that form validation
error dance doing for you?
• User chooses a file
• Submit & wait for file to upload ⌛…
• Validation error: “Username is already taken!”
• Re-render form
Where dat file go?
How’s that form validation
error dance doing for you?
http://stackoverflow.com/questions/5198602/not-losing-paperclip-attachment-when-model-cannot-be-saved-due-to-validation-err
Closed: Won’t Fix
How’s that form validation
error dance doing for you?
http://stackoverflow.com/questions/5198602/not-losing-paperclip-attachment-when-model-cannot-be-saved-due-to-validation-err
How’s that form validation
error dance doing for you?
http://stackoverflow.com/questions/5198602/not-losing-paperclip-attachment-when-model-cannot-be-saved-due-to-validation-err
Answer: use CarrierWave
How’s that form validation
error dance doing for you?
How’s that form validation
error dance doing for you?
“Is there a standard
approach? This seems like
a very common use case.”
How’s the schema pollution
doing for you?
How’s the schema pollution
doing for you?
class StoreMetadata < ActiveRecord::Migration
def change
add_column :users, :profile_image_filename, :string
add_column :users, :profile_image_size, :integer
add_column :users, :profile_image_content_type, :string
end
end
How’s the schema pollution
doing for you?
class StoreMetadata < ActiveRecord::Migration
def change
add_column :users, :profile_image_filename, :string
add_column :users, :profile_image_size, :integer
add_column :users, :profile_image_content_type, :string
end
end
How’s that multiple files
doing for you?
How’s that multiple files
doing for you?
class Post < ActiveRecord::Base
has_many :images, dependent: :destroy
end
How’s that multiple files
doing for you?
class Post < ActiveRecord::Base
has_many :images, dependent: :destroy
end
class Image < ActiveRecord::Base
belongs_to :post
attachment :file
end
How’s that multiple files
doing for you?
class Post < ActiveRecord::Base
has_many :images, dependent: :destroy
end
class Image < ActiveRecord::Base
belongs_to :post
attachment :file
end
How’s that multiple files
doing for you?
class Post < ActiveRecord::Base
has_many :images, dependent: :destroy
end
class Image < ActiveRecord::Base
belongs_to :post
attachment :file
end
Is this what you want or just
what you’re accustomed to?
How’s Amazon Lambda
doing for you?
• User chooses a file
• Submit & wait for file to upload ⌛…
• Success!
• Render page with thumbnail…
How many thumbnails -
404?
How’s Amazon Lambda
doing for you?
• User chooses a file
• Submit & wait for file to upload ⌛…
• Success!
• Render page with thumbnail…
Direct upload to AWS?
Cancel form submit -
delete files & thumbnails?
Deep integration &
assumption
How’s Dragonfly
doing for you?
http://markevans.github.io/dragonfly/
How’s refile
doing for you?
https://github.com/refile/refile
http://thecooperreview.com/10-tricks-appear-smart-meetings/
10 Tricks to Appear Smart
During Meetings
Take a step back
Take a step back
• We want to store a bunch of attributes in a model
• e.g. Title, Body, Tags, Photo















Take a step back
{photo}
{title}
{body}
Take a step back
<img src={photo}>
<h1>{title}</h1>
{body}
Take a step back
• Why should photo be a disproportionately
complicated attribute in my Article model?
• stored file path
• conversion
• background job
• aws config
• clean up on delete
Take a step back
• Why should photo be a disproportionately
complicated attribute in my Article model?
• stored file path
• conversion
• background job
• validation error dance
• aws config
Take a step back
• Frankly photo_url is best; least intrusive



















Take a step back
• Frankly photo_url is best; least intrusive
• Problems
• Remote url 404? (not exclusive to your app)
• Asking users to give us a URL is a hard sell
• Need to render other sizes
• Filter by meta data
Take a step back
• Frankly photo_url is best; least intrusive
• Problems
• Remote url 404? (not exclusive to your app)
• Asking users to give us a URL is a hard sell
• Need to render other sizes
• Filter by meta data
Take a step back
• Frankly photo_url is best; least intrusive
• Problems
• Remote url 404? (not exclusive to your app)
• Asking users to give us a URL is a hard sell
• Need to render other sizes
• Filter by meta data
Take a step back
• Frankly photo_url is best; least intrusive
• Solutions
• Exclusive server for your app
• Upload to that server
• On-the-fly resize based on URL
• Store url with meta data: photo_json instead?
Just add server
• PostgreSQL, MySQL
• Redis
• Memcached
• SMTP server (Mail)







You are already
Generic server to do
specialised work
Not specific to your
business logic
• Not a new pattern
• Mostly commercial services









• Maybe it has to be Free & Open Source to become
a default pattern
Image server
Want
• Move the “concern” out of my app
• photo is a regular attribute
• configure my app & forget it exist







Want
• Move the “concern” out of my app
• photo is a regular attribute
• configure my app & forget it exist






 What would my app look
like in a better world?
My app: Bare minimum
create_table "users" do |t|
t.string "name"
t.json "avatar"
t.json "photos"
end
My app: Bare minimum
create_table "users" do |t|
t.string "name"
t.json "avatar"
t.json "photos" # multiple files in a column
end
My app: Bare minimum
Image serverRails appBrowser
{ avatar: #<File..> }
My app: Bare minimum
Image serverRails appBrowser
{ avatar: #<File..> }
{“path”:“x.jpg”,
“geometry”:“200x600”}
#<File..>
My app: Bare minimum
Image serverRails appBrowser
{“path”:“x.jpg”,
“geometry”:“200x600”}
#<File..>
user.avatar={“path”: “x.jpg”…}
user.save
<img src=“x.jpg”>
{ avatar: #<File..> }
My app: Bare minimum
Image serverRails appBrowser
{“path”:“x.jpg”,
“geometry”:“200x600”}
<img src=“x.jpg”>
#<File..>
GET x.jpg
#<File..>
user.avatar={“path”: “x.jpg”…}
user.save
{ avatar: #<File..> }
My app: Bare minimum
• Browser render <file> field; regular form submit
• Receive binary param, uploads to attache server
and stores the json response instead
• Your app render <img src> requesting for image in
certain size, e.g. http://example/200x/
file.png





Image serverRails appBrowser
#<File..>
{“path”:“x.jpg”,
“geometry”:“200x600”}
Progressive Enhancement
Image serverRails appBrowser
#<File..>
{“path”:“x.jpg”,
“geometry”:“200x600”}
Progressive Enhancement
{ avatar: {“path”:“x.jpg”, … }
{ avatar: {“path”:“x.jpg”, … }
Image serverRails appBrowser
#<File..>
{“path”:“x.jpg”,
“geometry”:“200x600”}
user.avatar={“path”: “x.jpg”…}
user.save
<img src=“x.jpg”>
Progressive Enhancement
• Browser render <file> field; regular form submit
• Receive binary param, uploads to attache server
and stores the json response instead
• Your app render <img src> requesting for image in
certain size, e.g. http://example/200x/
file.png





Progressive Enhancement
• Browser render <file> field; regular form submit
• Receive binary param, uploads to attache server
and stores the json response instead
• Your app render <img src> requesting for image in
certain size, e.g. http://example/200x/
file.png





• JS upload directly to attache server; “Direct upload” in
AWS parlance
• No binary in params; receive and store json attribute
Progressive Enhancement
• When after_update & after_destroy
removes obsolete file from attache via delete API
• Just use Ruby; just use your framework
• Pre-render multiple sizes
• fetch the urls, server will generate and cache
• Validation
• validating a regular json attribute
How do I…
• Move the “concern” out of my app
• photo is a regular attribute
• configure my app & forget it exist







Want (cont’d)
Want (cont’d)
• Move the “concern” out of my app
• photo is a regular attribute
• configure my app & forget it exist
• Separate, standalone server
• Minimal / zero ongoing administration
Want (cont’d)
• Move the “concern” out of my app
• photo is a regular attribute
• configure my app & forget it exist
• Separate, standalone server
• Minimal / zero ongoing administration
How does this
server work?
Attache File Server
• HTTP server with simple APIs
• upload
• download
• delete
• Rack app + ImageMagick
• Go? Node? C++? PHP?
• GraphicsMagick? MyResizer.bash?
• Uploaded files are stored locally
• Resize local file on-the-fly
• configurable pool size to limit concurrent resizing
• Sync upload to cloud storage
• 2 hop problem vs complexity
• Fixed local storage, purge LRU (zero maintenance)
• Spin up new fresh servers anytime… 

Attache File Server
• When requested file does not exist locally
• fetch from cloud storage & write locally
• resume operations











Attache File Server
• Remove obsolete file is “best effort”
• If photo delete failed, do you Error 500 or stop the
world?







• OCDs can schedule rake task remove dangling files?
Attache File Server
• Caching in production
• Browser → CDN → Varnish → Disk → Cloud













Attache File Server
Demo
https://attache-demo.herokuapp.com/
https://github.com/choonkeat/attache_api
ATTACHE_URL=http://localhost:9292
ATTACHE_SECRET_KEY=topsecret
rake
Compatibility Check
tus.io
• Open protocol for resumable uploads built on HTTP
• Perfect for mobile apps
• Rack middleware implemented in choonkeat/
attache#10
Responsive Images with
Client Hints
http://blog.imgix.com/2015/10/13/next-generation-responsive-images-with-client.html
SmartCrop
https://github.com/jwagner/smartcrop.js/
Dragonfly & refile
Dragonfly & refile
• tldr: we can fuss over implementation, but it is
mostly about architecture
Dragonfly & refile
• Rack middleware in your Rails app by default
• performing on-the-fly image resize 😱
• Rack standalone end point
• Dragonfly.app - upload, download, delete
• Refile::App - upload, download, delete
• Downloads are unthrottled
Dragonfly & refile
• BEFORE: Rails integrate with AWS
• AFTER: Rails integrate with AWS + Rack app
• Maintain identical AWS config in both apps
• Rails app couldn’t shed the “concern”
• Multiple images still require multiple models
refile
class Post < ActiveRecord::Base
has_many :images, dependent: :destroy
accepts_attachments_for :images, attachment: :file
end
class Image < ActiveRecord::Base
belongs_to :post
attachment :file
end
refile
class Post < ActiveRecord::Base
has_many :images, dependent: :destroy
accepts_attachments_for :images, attachment: :file
end
class Image < ActiveRecord::Base
belongs_to :post
attachment :file
end
“Note it must be possible to persist images
given only the associated post and a file. There
must not be any other validations or constraints
which prevent images from being saved”
i.e. Must be pure dummy wrapper; no
validations here
refile download
https://github.com/refile/refile/blob/master/lib/refile/app.rb
get "/:token/:backend/:processor/:id/:filename" do
halt 404 unless download_allowed?
stream_file processor.call(file)
end
refile download
https://github.com/refile/refile/blob/master/lib/refile/app.rb
get "/:token/:backend/:processor/:id/:filename" do
halt 404 unless download_allowed?
stream_file processor.call(file)
end
How many ImageMagick can
you run in parallel?
has_many :images?
refile upload
https://github.com/refile/refile/blob/master/lib/refile/app.rb
post "/:backend" do
halt 404 unless upload_allowed?
tempfile = request.params.fetch("file").fetch(:tempfile)
file = backend.upload(tempfile)
content_type :json
{ id: file.id }.to_json
end
def file
file = backend.get(params[:id])
unless file.exists?
log_error("Could not find attachment by id: #{params[:id]}")
halt 404
end
file.download
end
post "/:backend" do
halt 404 unless upload_allowed?
tempfile = request.params.fetch("file").fetch(:tempfile)
file = backend.upload(tempfile)
content_type :json
{ id: file.id }.to_json
end
def file
file = backend.get(params[:id])
unless file.exists?
log_error("Could not find attachment by id: #{params[:id]}")
halt 404
end
file.download
end
refile upload
https://github.com/refile/refile/blob/master/lib/refile/app.rb
2 hops problem when
uploading and downloading
• 3mb file becomes 6mb each
way
• #create and #show
becomes 12mb process
• has_many :images?
refile
• CarrierWave-styled named processors (e.g. :fill, :thumb) vs
passing through syntax to underlying ImageMagick
• personally prefer leveraging off existing knowledge
• instead of manually configured syntax sugar
• “2 hop problem” however provide higher consistency
when running multiple refile servers
• upload-here-download-there problem
• (considering to perform 2-hop upload instead of async)
refile
• Can upload to S3 direct and/or upload to refile
• Redundancy interesting, but prefer less concern in Rails
app
• Concept of cache and store to manage “dangling file
problem” is worth considering
• Download urls are signed-only (this practice should be
adopted)
• can partly counter motivation to abuse “dangling file
problem” (aka free file hosting, whee!)
Questions?
Attache server

https://github.com/choonkeat/attache
Gem for Rails

https://github.com/choonkeat/attache_rails
Demo

https://attache-demo.herokuapp.com/

Weitere ähnliche Inhalte

Was ist angesagt?

Code & Design your first website 4/18
Code & Design your first website 4/18Code & Design your first website 4/18
Code & Design your first website 4/18TJ Stalcup
 
Code &amp; design your first website (3:16)
Code &amp; design your first website (3:16)Code &amp; design your first website (3:16)
Code &amp; design your first website (3:16)Thinkful
 
Designing your API Server for mobile apps
Designing your API Server for mobile appsDesigning your API Server for mobile apps
Designing your API Server for mobile appsMugunth Kumar
 
Accessibility Hacks version 2
Accessibility Hacks version 2Accessibility Hacks version 2
Accessibility Hacks version 2Graham Armfield
 
WordCamp Greenville 2018 - Beware the Dark Side, or an Intro to Development
WordCamp Greenville 2018 - Beware the Dark Side, or an Intro to DevelopmentWordCamp Greenville 2018 - Beware the Dark Side, or an Intro to Development
WordCamp Greenville 2018 - Beware the Dark Side, or an Intro to DevelopmentEvan Mullins
 
Things you should know about WordPress (but were always too afraid to ask): W...
Things you should know about WordPress (but were always too afraid to ask): W...Things you should know about WordPress (but were always too afraid to ask): W...
Things you should know about WordPress (but were always too afraid to ask): W...Michael McNeill
 
Front End page speed performance improvements for Drupal
Front End page speed performance improvements for DrupalFront End page speed performance improvements for Drupal
Front End page speed performance improvements for DrupalAndy Kucharski
 
Accessibility Hacks Wordcamp Manchester October 2018
Accessibility Hacks Wordcamp Manchester October 2018Accessibility Hacks Wordcamp Manchester October 2018
Accessibility Hacks Wordcamp Manchester October 2018Graham Armfield
 
JSLink for ITPros - SharePoint Saturday Jersey
JSLink for ITPros - SharePoint Saturday JerseyJSLink for ITPros - SharePoint Saturday Jersey
JSLink for ITPros - SharePoint Saturday JerseyPaul Hunt
 
Theming Wordpress with Adobe
Theming Wordpress with AdobeTheming Wordpress with Adobe
Theming Wordpress with AdobeGrace Solivan
 
SUGUK Cambridge - Display Templates & JSLink for IT Pros
SUGUK Cambridge - Display Templates & JSLink for IT ProsSUGUK Cambridge - Display Templates & JSLink for IT Pros
SUGUK Cambridge - Display Templates & JSLink for IT ProsPaul Hunt
 
11 Amazing things I Learnt At Word Camp Sydney 2014
11 Amazing things I Learnt At Word Camp Sydney 201411 Amazing things I Learnt At Word Camp Sydney 2014
11 Amazing things I Learnt At Word Camp Sydney 2014WordPressBrisbane
 
Why & How to Create a WordPress Plugin
Why & How to Create a WordPress PluginWhy & How to Create a WordPress Plugin
Why & How to Create a WordPress PluginJoe Querin
 
jQuery Conference Austin Sept 2013
jQuery Conference Austin Sept 2013jQuery Conference Austin Sept 2013
jQuery Conference Austin Sept 2013dmethvin
 
jQuery Conference Boston 2011 CouchApps
jQuery Conference Boston 2011 CouchAppsjQuery Conference Boston 2011 CouchApps
jQuery Conference Boston 2011 CouchAppsBradley Holt
 
jQuery Chicago 2014 - Next-generation JavaScript Testing
jQuery Chicago 2014 - Next-generation JavaScript TestingjQuery Chicago 2014 - Next-generation JavaScript Testing
jQuery Chicago 2014 - Next-generation JavaScript TestingVlad Filippov
 

Was ist angesagt? (20)

Code & Design your first website 4/18
Code & Design your first website 4/18Code & Design your first website 4/18
Code & Design your first website 4/18
 
Code &amp; design your first website (3:16)
Code &amp; design your first website (3:16)Code &amp; design your first website (3:16)
Code &amp; design your first website (3:16)
 
Designing your API Server for mobile apps
Designing your API Server for mobile appsDesigning your API Server for mobile apps
Designing your API Server for mobile apps
 
Accessibility Hacks version 2
Accessibility Hacks version 2Accessibility Hacks version 2
Accessibility Hacks version 2
 
WordCamp Greenville 2018 - Beware the Dark Side, or an Intro to Development
WordCamp Greenville 2018 - Beware the Dark Side, or an Intro to DevelopmentWordCamp Greenville 2018 - Beware the Dark Side, or an Intro to Development
WordCamp Greenville 2018 - Beware the Dark Side, or an Intro to Development
 
Things you should know about WordPress (but were always too afraid to ask): W...
Things you should know about WordPress (but were always too afraid to ask): W...Things you should know about WordPress (but were always too afraid to ask): W...
Things you should know about WordPress (but were always too afraid to ask): W...
 
Front End page speed performance improvements for Drupal
Front End page speed performance improvements for DrupalFront End page speed performance improvements for Drupal
Front End page speed performance improvements for Drupal
 
WordPress plugins
WordPress pluginsWordPress plugins
WordPress plugins
 
Accessibility Hacks Wordcamp Manchester October 2018
Accessibility Hacks Wordcamp Manchester October 2018Accessibility Hacks Wordcamp Manchester October 2018
Accessibility Hacks Wordcamp Manchester October 2018
 
JSLink for ITPros - SharePoint Saturday Jersey
JSLink for ITPros - SharePoint Saturday JerseyJSLink for ITPros - SharePoint Saturday Jersey
JSLink for ITPros - SharePoint Saturday Jersey
 
Theming Wordpress with Adobe
Theming Wordpress with AdobeTheming Wordpress with Adobe
Theming Wordpress with Adobe
 
WPD Training
WPD TrainingWPD Training
WPD Training
 
Computer Science and Information Science 6th semester(2010 December) Questio...
 Computer Science and Information Science 6th semester(2010 December) Questio... Computer Science and Information Science 6th semester(2010 December) Questio...
Computer Science and Information Science 6th semester(2010 December) Questio...
 
SUGUK Cambridge - Display Templates & JSLink for IT Pros
SUGUK Cambridge - Display Templates & JSLink for IT ProsSUGUK Cambridge - Display Templates & JSLink for IT Pros
SUGUK Cambridge - Display Templates & JSLink for IT Pros
 
11 Amazing things I Learnt At Word Camp Sydney 2014
11 Amazing things I Learnt At Word Camp Sydney 201411 Amazing things I Learnt At Word Camp Sydney 2014
11 Amazing things I Learnt At Word Camp Sydney 2014
 
Why & How to Create a WordPress Plugin
Why & How to Create a WordPress PluginWhy & How to Create a WordPress Plugin
Why & How to Create a WordPress Plugin
 
jQuery Conference Austin Sept 2013
jQuery Conference Austin Sept 2013jQuery Conference Austin Sept 2013
jQuery Conference Austin Sept 2013
 
Is Your (Client's) Website Ready for 2017?
Is Your (Client's) Website Ready for 2017?Is Your (Client's) Website Ready for 2017?
Is Your (Client's) Website Ready for 2017?
 
jQuery Conference Boston 2011 CouchApps
jQuery Conference Boston 2011 CouchAppsjQuery Conference Boston 2011 CouchApps
jQuery Conference Boston 2011 CouchApps
 
jQuery Chicago 2014 - Next-generation JavaScript Testing
jQuery Chicago 2014 - Next-generation JavaScript TestingjQuery Chicago 2014 - Next-generation JavaScript Testing
jQuery Chicago 2014 - Next-generation JavaScript Testing
 

Andere mochten auch

How to upload a file
How to upload a fileHow to upload a file
How to upload a fileTom Greenwell
 
Key board interface
Key board interface Key board interface
Key board interface sree deepika
 
FTP - File Transfer Protocol
FTP - File Transfer ProtocolFTP - File Transfer Protocol
FTP - File Transfer ProtocolPeter R. Egli
 
Barcode presentation 2013
Barcode presentation 2013Barcode presentation 2013
Barcode presentation 2013JASON WOODHOUSE
 
Barcode integration erp
Barcode integration   erpBarcode integration   erp
Barcode integration erpmadhappan
 
MicroService Architecture
MicroService ArchitectureMicroService Architecture
MicroService ArchitectureFred George
 
Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...Chris Richardson
 
Introduction to EDI Basics
Introduction to EDI BasicsIntroduction to EDI Basics
Introduction to EDI BasicsGXS
 

Andere mochten auch (12)

Input Devices Maprang.
Input Devices Maprang.Input Devices Maprang.
Input Devices Maprang.
 
How to upload a file
How to upload a fileHow to upload a file
How to upload a file
 
Key board interface
Key board interface Key board interface
Key board interface
 
FTP - File Transfer Protocol
FTP - File Transfer ProtocolFTP - File Transfer Protocol
FTP - File Transfer Protocol
 
Barcode presentation 2013
Barcode presentation 2013Barcode presentation 2013
Barcode presentation 2013
 
Barcode integration erp
Barcode integration   erpBarcode integration   erp
Barcode integration erp
 
MicroService Architecture
MicroService ArchitectureMicroService Architecture
MicroService Architecture
 
Bitrix24 crm
Bitrix24 crmBitrix24 crm
Bitrix24 crm
 
Barcode technology
Barcode technologyBarcode technology
Barcode technology
 
Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...
 
Introduction to EDI Basics
Introduction to EDI BasicsIntroduction to EDI Basics
Introduction to EDI Basics
 
Bitrix24 crm review
Bitrix24 crm reviewBitrix24 crm review
Bitrix24 crm review
 

Ähnlich wie File Upload 2015

2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事
2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事
2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事Ronald Hsu
 
CSS3: Are you experienced?
CSS3: Are you experienced?CSS3: Are you experienced?
CSS3: Are you experienced?Denise Jacobs
 
About Best friends - HTML, CSS and JS
About Best friends - HTML, CSS and JSAbout Best friends - HTML, CSS and JS
About Best friends - HTML, CSS and JSNaga Harish M
 
Practical tipsmakemobilefaster oscon2016
Practical tipsmakemobilefaster oscon2016Practical tipsmakemobilefaster oscon2016
Practical tipsmakemobilefaster oscon2016Doris Chen
 
Grown-up javascript with AngularJS
Grown-up javascript with AngularJSGrown-up javascript with AngularJS
Grown-up javascript with AngularJSMykhailo Kotsur
 
Deep dive on amazon rekognition architectures for image analysis - MCL318 - ...
Deep dive on amazon rekognition architectures for image analysis - MCL318  - ...Deep dive on amazon rekognition architectures for image analysis - MCL318  - ...
Deep dive on amazon rekognition architectures for image analysis - MCL318 - ...Amazon Web Services
 
APIs for modern web apps
APIs for modern web appsAPIs for modern web apps
APIs for modern web appsChris Mills
 
The things we found in your website
The things we found in your websiteThe things we found in your website
The things we found in your websitehernanibf
 
Riding the Edge with Ember.js
Riding the Edge with Ember.jsRiding the Edge with Ember.js
Riding the Edge with Ember.jsaortbals
 
Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]
Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]
Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]David Wesst
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)Doris Chen
 
Curtin University Frontend Web Development
Curtin University Frontend Web DevelopmentCurtin University Frontend Web Development
Curtin University Frontend Web DevelopmentDaryll Chu
 
Web Development using Ruby on Rails
Web Development using Ruby on RailsWeb Development using Ruby on Rails
Web Development using Ruby on RailsAvi Kedar
 
Responsive Web Design: Clever Tips and Techniques
Responsive Web Design: Clever Tips and TechniquesResponsive Web Design: Clever Tips and Techniques
Responsive Web Design: Clever Tips and TechniquesVitaly Friedman
 
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...Amazon Web Services
 
Progressively Enhancing WordPress Themes
Progressively Enhancing WordPress ThemesProgressively Enhancing WordPress Themes
Progressively Enhancing WordPress ThemesDigitally
 
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...cehwitham
 
Javascript Libraries
Javascript LibrariesJavascript Libraries
Javascript Librarieselliando dias
 

Ähnlich wie File Upload 2015 (20)

2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事
2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事
2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事
 
CSS3: Are you experienced?
CSS3: Are you experienced?CSS3: Are you experienced?
CSS3: Are you experienced?
 
About Best friends - HTML, CSS and JS
About Best friends - HTML, CSS and JSAbout Best friends - HTML, CSS and JS
About Best friends - HTML, CSS and JS
 
Practical tipsmakemobilefaster oscon2016
Practical tipsmakemobilefaster oscon2016Practical tipsmakemobilefaster oscon2016
Practical tipsmakemobilefaster oscon2016
 
Grown-up javascript with AngularJS
Grown-up javascript with AngularJSGrown-up javascript with AngularJS
Grown-up javascript with AngularJS
 
Deep dive on amazon rekognition architectures for image analysis - MCL318 - ...
Deep dive on amazon rekognition architectures for image analysis - MCL318  - ...Deep dive on amazon rekognition architectures for image analysis - MCL318  - ...
Deep dive on amazon rekognition architectures for image analysis - MCL318 - ...
 
APIs for modern web apps
APIs for modern web appsAPIs for modern web apps
APIs for modern web apps
 
The things we found in your website
The things we found in your websiteThe things we found in your website
The things we found in your website
 
Riding the Edge with Ember.js
Riding the Edge with Ember.jsRiding the Edge with Ember.js
Riding the Edge with Ember.js
 
Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]
Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]
Rich and Beautiful: Making Attractive Apps in HTML5 [Wpg 2013]
 
Word Press As A Cms
Word Press As A CmsWord Press As A Cms
Word Press As A Cms
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
 
Curtin University Frontend Web Development
Curtin University Frontend Web DevelopmentCurtin University Frontend Web Development
Curtin University Frontend Web Development
 
Web Development using Ruby on Rails
Web Development using Ruby on RailsWeb Development using Ruby on Rails
Web Development using Ruby on Rails
 
Seven deadly theming sins
Seven deadly theming sinsSeven deadly theming sins
Seven deadly theming sins
 
Responsive Web Design: Clever Tips and Techniques
Responsive Web Design: Clever Tips and TechniquesResponsive Web Design: Clever Tips and Techniques
Responsive Web Design: Clever Tips and Techniques
 
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
(BDT402) Performance Profiling in Production: Analyzing Web Requests at Scale...
 
Progressively Enhancing WordPress Themes
Progressively Enhancing WordPress ThemesProgressively Enhancing WordPress Themes
Progressively Enhancing WordPress Themes
 
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
 
Javascript Libraries
Javascript LibrariesJavascript Libraries
Javascript Libraries
 

Kürzlich hochgeladen

IA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeIA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeNeo4j
 
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...OnePlan Solutions
 
Streamlining Your Application Builds with Cloud Native Buildpacks
Streamlining Your Application Builds  with Cloud Native BuildpacksStreamlining Your Application Builds  with Cloud Native Buildpacks
Streamlining Your Application Builds with Cloud Native BuildpacksVish Abrams
 
Introduction-to-Software-Development-Outsourcing.pptx
Introduction-to-Software-Development-Outsourcing.pptxIntroduction-to-Software-Development-Outsourcing.pptx
Introduction-to-Software-Development-Outsourcing.pptxIntelliSource Technologies
 
online pdf editor software solutions.pdf
online pdf editor software solutions.pdfonline pdf editor software solutions.pdf
online pdf editor software solutions.pdfMeon Technology
 
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine HarmonyLeveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmonyelliciumsolutionspun
 
Kawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies
 
Watermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security ChallengesWatermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security ChallengesShyamsundar Das
 
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageSales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageDista
 
AI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human BeautyAI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human BeautyRaymond Okyere-Forson
 
Why Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdfWhy Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdfBrain Inventory
 
Deep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - DatacampDeep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - DatacampVICTOR MAESTRE RAMIREZ
 
eAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionseAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionsNirav Modi
 
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/MLBig Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/MLAlluxio, Inc.
 
ERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptxERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptxAutus Cyber Tech
 
Generative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-CouncilGenerative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-CouncilVICTOR MAESTRE RAMIREZ
 
Cybersecurity Challenges with Generative AI - for Good and Bad
Cybersecurity Challenges with Generative AI - for Good and BadCybersecurity Challenges with Generative AI - for Good and Bad
Cybersecurity Challenges with Generative AI - for Good and BadIvo Andreev
 
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.Sharon Liu
 
Growing Oxen: channel operators and retries
Growing Oxen: channel operators and retriesGrowing Oxen: channel operators and retries
Growing Oxen: channel operators and retriesSoftwareMill
 
Webinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptWebinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptkinjal48
 

Kürzlich hochgeladen (20)

IA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeIA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG time
 
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
 
Streamlining Your Application Builds with Cloud Native Buildpacks
Streamlining Your Application Builds  with Cloud Native BuildpacksStreamlining Your Application Builds  with Cloud Native Buildpacks
Streamlining Your Application Builds with Cloud Native Buildpacks
 
Introduction-to-Software-Development-Outsourcing.pptx
Introduction-to-Software-Development-Outsourcing.pptxIntroduction-to-Software-Development-Outsourcing.pptx
Introduction-to-Software-Development-Outsourcing.pptx
 
online pdf editor software solutions.pdf
online pdf editor software solutions.pdfonline pdf editor software solutions.pdf
online pdf editor software solutions.pdf
 
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine HarmonyLeveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
 
Kawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in Trivandrum
 
Watermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security ChallengesWatermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security Challenges
 
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageSales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
 
AI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human BeautyAI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human Beauty
 
Why Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdfWhy Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdf
 
Deep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - DatacampDeep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - Datacamp
 
eAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionseAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspections
 
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/MLBig Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
 
ERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptxERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptx
 
Generative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-CouncilGenerative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-Council
 
Cybersecurity Challenges with Generative AI - for Good and Bad
Cybersecurity Challenges with Generative AI - for Good and BadCybersecurity Challenges with Generative AI - for Good and Bad
Cybersecurity Challenges with Generative AI - for Good and Bad
 
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
 
Growing Oxen: channel operators and retries
Growing Oxen: channel operators and retriesGrowing Oxen: channel operators and retries
Growing Oxen: channel operators and retries
 
Webinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptWebinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.ppt
 

File Upload 2015

  • 2. How’s that predefined styles doing for you? has_attached_file :asset, styles: { thumb: "100x100#" }
  • 3. How’s that predefined styles doing for you? has_attached_file :asset, styles: { thumb: "100x100#", medium: "320x>" }
  • 4. How’s that predefined styles doing for you? has_attached_file :asset, styles: { thumb: "100x100#", medium: "320x>", large: "1024x>" }
  • 5. How’s that predefined styles doing for you? has_attached_file :asset, styles: { thumb: "100x100#", medium: "320x>",
 big: "640x>", large: "1024x>" } Names starting to lose meaning…
  • 6. How’s that predefined styles doing for you? has_attached_file :asset, styles: { thumb: "100x100#", thumb2x: "200x200#", medium: "320x>", medium2x: "640x>",
 big: "640x>", big2x: "1280x>", large: "1024x>", large2x: "2048x>" }
  • 7. How’s that predefined styles doing for you? has_attached_file :asset, styles: { thumb: "100x100#", thumb2x: "200x200#", medium: "320x>", medium2x: "640x>",
 big: "640x>", big2x: "1280x>", large: "1024x>", large2x: "2048x>" } Reprocess all the production files, each time, we make changes. 404 while rake runs or do at midnight?
  • 9. How’s that transformation juggling doing for you? class MyUploader < CarrierWave::Uploader::Base version :thumb do process resize_to_fill: [280, 280] end version :small_thumb, from_version: :thumb do process resize_to_fill: [20, 20] end end
  • 10. How’s that transformation juggling doing for you? class MyUploader < CarrierWave::Uploader::Base version :thumb do process resize_to_fill: [280, 280] end version :small_thumb, from_version: :thumb do process resize_to_fill: [20, 20] end end Did your users wait in the foreground or background?
  • 11. How’s that file path config doing for you?
  • 12. How’s that file path config doing for you? class Avatar < ActiveRecord::Base has_attached_file :image,
 url: '/system/:class/:attachment/:id/:hash-:style.:extension', hash_secret: Rails.application.secrets.paperclip end
  • 13. How’s that file path config doing for you? class Avatar < ActiveRecord::Base has_attached_file :image,
 url: '/system/:class/:attachment/:id/:hash-:style.:extension', hash_secret: Rails.application.secrets.paperclip end You sure this is the format? Or will they need to change?
  • 14. How’s that file path config doing for you? class Avatar < ActiveRecord::Base has_attached_file :image,
 url: '/system/:class/:attachment/:id/:hash-:style.:extension', hash_secret: Rails.application.secrets.paperclip end
  • 15. How’s that file path config doing for you? class Avatar < ActiveRecord::Base has_attached_file :image,
 url: '/system/:class/:attachment/:id/:hash-:style.:extension', hash_secret: Rails.application.secrets.paperclip end
  • 16. How’s that file path config doing for you? CarrierWave.configure do |config| config.permissions = 0666 config.directory_permissions = 0777 config.storage = :file end
  • 17. How’s that file path config doing for you? CarrierWave.configure do |config| config.permissions = 0666 config.directory_permissions = 0777 config.storage = :file end Did you configure your MySQL data file in your app too?
  • 18. How’s that file path config doing for you? class Avatar < ActiveRecord::Base self.table = { name: "avatars", data: "/var/lib/mysql/data/avatars.MYD", index: "/var/lib/mysql/data/avatars.MYI" } end Did you configure your MySQL data file in your app too?
  • 19. How’s that form validation error dance doing for you?
  • 20. How’s that form validation error dance doing for you? • User chooses a file • Submit & wait for file to upload ⌛… • Validation error: “Username is already taken!” • Re-render form
  • 21. How’s that form validation error dance doing for you? • User chooses a file • Submit & wait for file to upload ⌛… • Validation error: “Username is already taken!” • Re-render form Where dat file go?
  • 22. How’s that form validation error dance doing for you? http://stackoverflow.com/questions/5198602/not-losing-paperclip-attachment-when-model-cannot-be-saved-due-to-validation-err Closed: Won’t Fix
  • 23. How’s that form validation error dance doing for you? http://stackoverflow.com/questions/5198602/not-losing-paperclip-attachment-when-model-cannot-be-saved-due-to-validation-err
  • 24. How’s that form validation error dance doing for you? http://stackoverflow.com/questions/5198602/not-losing-paperclip-attachment-when-model-cannot-be-saved-due-to-validation-err Answer: use CarrierWave
  • 25. How’s that form validation error dance doing for you?
  • 26. How’s that form validation error dance doing for you? “Is there a standard approach? This seems like a very common use case.”
  • 27. How’s the schema pollution doing for you?
  • 28. How’s the schema pollution doing for you? class StoreMetadata < ActiveRecord::Migration def change add_column :users, :profile_image_filename, :string add_column :users, :profile_image_size, :integer add_column :users, :profile_image_content_type, :string end end
  • 29. How’s the schema pollution doing for you? class StoreMetadata < ActiveRecord::Migration def change add_column :users, :profile_image_filename, :string add_column :users, :profile_image_size, :integer add_column :users, :profile_image_content_type, :string end end
  • 30. How’s that multiple files doing for you?
  • 31. How’s that multiple files doing for you? class Post < ActiveRecord::Base has_many :images, dependent: :destroy end
  • 32. How’s that multiple files doing for you? class Post < ActiveRecord::Base has_many :images, dependent: :destroy end class Image < ActiveRecord::Base belongs_to :post attachment :file end
  • 33. How’s that multiple files doing for you? class Post < ActiveRecord::Base has_many :images, dependent: :destroy end class Image < ActiveRecord::Base belongs_to :post attachment :file end
  • 34. How’s that multiple files doing for you? class Post < ActiveRecord::Base has_many :images, dependent: :destroy end class Image < ActiveRecord::Base belongs_to :post attachment :file end Is this what you want or just what you’re accustomed to?
  • 35. How’s Amazon Lambda doing for you? • User chooses a file • Submit & wait for file to upload ⌛… • Success! • Render page with thumbnail… How many thumbnails - 404?
  • 36. How’s Amazon Lambda doing for you? • User chooses a file • Submit & wait for file to upload ⌛… • Success! • Render page with thumbnail… Direct upload to AWS? Cancel form submit - delete files & thumbnails? Deep integration & assumption
  • 37. How’s Dragonfly doing for you? http://markevans.github.io/dragonfly/
  • 38. How’s refile doing for you? https://github.com/refile/refile
  • 40. Take a step back
  • 41. Take a step back • We want to store a bunch of attributes in a model • e.g. Title, Body, Tags, Photo
 
 
 
 
 
 
 

  • 42. Take a step back {photo} {title} {body}
  • 43. Take a step back <img src={photo}> <h1>{title}</h1> {body}
  • 44. Take a step back • Why should photo be a disproportionately complicated attribute in my Article model? • stored file path • conversion • background job • aws config • clean up on delete
  • 45. Take a step back • Why should photo be a disproportionately complicated attribute in my Article model? • stored file path • conversion • background job • validation error dance • aws config
  • 46. Take a step back • Frankly photo_url is best; least intrusive
 
 
 
 
 
 
 
 
 

  • 47. Take a step back • Frankly photo_url is best; least intrusive • Problems • Remote url 404? (not exclusive to your app) • Asking users to give us a URL is a hard sell • Need to render other sizes • Filter by meta data
  • 48. Take a step back • Frankly photo_url is best; least intrusive • Problems • Remote url 404? (not exclusive to your app) • Asking users to give us a URL is a hard sell • Need to render other sizes • Filter by meta data
  • 49. Take a step back • Frankly photo_url is best; least intrusive • Problems • Remote url 404? (not exclusive to your app) • Asking users to give us a URL is a hard sell • Need to render other sizes • Filter by meta data
  • 50. Take a step back • Frankly photo_url is best; least intrusive • Solutions • Exclusive server for your app • Upload to that server • On-the-fly resize based on URL • Store url with meta data: photo_json instead?
  • 52. • PostgreSQL, MySQL • Redis • Memcached • SMTP server (Mail)
 
 
 
 You are already Generic server to do specialised work Not specific to your business logic
  • 53. • Not a new pattern • Mostly commercial services
 
 
 
 
 • Maybe it has to be Free & Open Source to become a default pattern Image server
  • 54. Want • Move the “concern” out of my app • photo is a regular attribute • configure my app & forget it exist
 
 
 

  • 55. Want • Move the “concern” out of my app • photo is a regular attribute • configure my app & forget it exist
 
 
 
 What would my app look like in a better world?
  • 56. My app: Bare minimum create_table "users" do |t| t.string "name" t.json "avatar" t.json "photos" end
  • 57. My app: Bare minimum create_table "users" do |t| t.string "name" t.json "avatar" t.json "photos" # multiple files in a column end
  • 58. My app: Bare minimum Image serverRails appBrowser { avatar: #<File..> }
  • 59. My app: Bare minimum Image serverRails appBrowser { avatar: #<File..> } {“path”:“x.jpg”, “geometry”:“200x600”} #<File..>
  • 60. My app: Bare minimum Image serverRails appBrowser {“path”:“x.jpg”, “geometry”:“200x600”} #<File..> user.avatar={“path”: “x.jpg”…} user.save <img src=“x.jpg”> { avatar: #<File..> }
  • 61. My app: Bare minimum Image serverRails appBrowser {“path”:“x.jpg”, “geometry”:“200x600”} <img src=“x.jpg”> #<File..> GET x.jpg #<File..> user.avatar={“path”: “x.jpg”…} user.save { avatar: #<File..> }
  • 62. My app: Bare minimum • Browser render <file> field; regular form submit • Receive binary param, uploads to attache server and stores the json response instead • Your app render <img src> requesting for image in certain size, e.g. http://example/200x/ file.png
 
 

  • 65. { avatar: {“path”:“x.jpg”, … } Image serverRails appBrowser #<File..> {“path”:“x.jpg”, “geometry”:“200x600”} user.avatar={“path”: “x.jpg”…} user.save <img src=“x.jpg”> Progressive Enhancement
  • 66. • Browser render <file> field; regular form submit • Receive binary param, uploads to attache server and stores the json response instead • Your app render <img src> requesting for image in certain size, e.g. http://example/200x/ file.png
 
 
 Progressive Enhancement
  • 67. • Browser render <file> field; regular form submit • Receive binary param, uploads to attache server and stores the json response instead • Your app render <img src> requesting for image in certain size, e.g. http://example/200x/ file.png
 
 
 • JS upload directly to attache server; “Direct upload” in AWS parlance • No binary in params; receive and store json attribute Progressive Enhancement • When after_update & after_destroy removes obsolete file from attache via delete API
  • 68. • Just use Ruby; just use your framework • Pre-render multiple sizes • fetch the urls, server will generate and cache • Validation • validating a regular json attribute How do I…
  • 69. • Move the “concern” out of my app • photo is a regular attribute • configure my app & forget it exist
 
 
 
 Want (cont’d)
  • 70. Want (cont’d) • Move the “concern” out of my app • photo is a regular attribute • configure my app & forget it exist • Separate, standalone server • Minimal / zero ongoing administration
  • 71. Want (cont’d) • Move the “concern” out of my app • photo is a regular attribute • configure my app & forget it exist • Separate, standalone server • Minimal / zero ongoing administration How does this server work?
  • 72. Attache File Server • HTTP server with simple APIs • upload • download • delete • Rack app + ImageMagick • Go? Node? C++? PHP? • GraphicsMagick? MyResizer.bash?
  • 73. • Uploaded files are stored locally • Resize local file on-the-fly • configurable pool size to limit concurrent resizing • Sync upload to cloud storage • 2 hop problem vs complexity • Fixed local storage, purge LRU (zero maintenance) • Spin up new fresh servers anytime… 
 Attache File Server
  • 74. • When requested file does not exist locally • fetch from cloud storage & write locally • resume operations
 
 
 
 
 
 Attache File Server
  • 75. • Remove obsolete file is “best effort” • If photo delete failed, do you Error 500 or stop the world?
 
 
 
 • OCDs can schedule rake task remove dangling files? Attache File Server
  • 76. • Caching in production • Browser → CDN → Varnish → Disk → Cloud
 
 
 
 
 
 
 Attache File Server
  • 79. tus.io • Open protocol for resumable uploads built on HTTP • Perfect for mobile apps • Rack middleware implemented in choonkeat/ attache#10
  • 80. Responsive Images with Client Hints http://blog.imgix.com/2015/10/13/next-generation-responsive-images-with-client.html
  • 83. Dragonfly & refile • tldr: we can fuss over implementation, but it is mostly about architecture
  • 84. Dragonfly & refile • Rack middleware in your Rails app by default • performing on-the-fly image resize 😱 • Rack standalone end point • Dragonfly.app - upload, download, delete • Refile::App - upload, download, delete • Downloads are unthrottled
  • 85. Dragonfly & refile • BEFORE: Rails integrate with AWS • AFTER: Rails integrate with AWS + Rack app • Maintain identical AWS config in both apps • Rails app couldn’t shed the “concern” • Multiple images still require multiple models
  • 86. refile class Post < ActiveRecord::Base has_many :images, dependent: :destroy accepts_attachments_for :images, attachment: :file end class Image < ActiveRecord::Base belongs_to :post attachment :file end
  • 87. refile class Post < ActiveRecord::Base has_many :images, dependent: :destroy accepts_attachments_for :images, attachment: :file end class Image < ActiveRecord::Base belongs_to :post attachment :file end “Note it must be possible to persist images given only the associated post and a file. There must not be any other validations or constraints which prevent images from being saved” i.e. Must be pure dummy wrapper; no validations here
  • 89. refile download https://github.com/refile/refile/blob/master/lib/refile/app.rb get "/:token/:backend/:processor/:id/:filename" do halt 404 unless download_allowed? stream_file processor.call(file) end How many ImageMagick can you run in parallel? has_many :images?
  • 90. refile upload https://github.com/refile/refile/blob/master/lib/refile/app.rb post "/:backend" do halt 404 unless upload_allowed? tempfile = request.params.fetch("file").fetch(:tempfile) file = backend.upload(tempfile) content_type :json { id: file.id }.to_json end def file file = backend.get(params[:id]) unless file.exists? log_error("Could not find attachment by id: #{params[:id]}") halt 404 end file.download end
  • 91. post "/:backend" do halt 404 unless upload_allowed? tempfile = request.params.fetch("file").fetch(:tempfile) file = backend.upload(tempfile) content_type :json { id: file.id }.to_json end def file file = backend.get(params[:id]) unless file.exists? log_error("Could not find attachment by id: #{params[:id]}") halt 404 end file.download end refile upload https://github.com/refile/refile/blob/master/lib/refile/app.rb 2 hops problem when uploading and downloading • 3mb file becomes 6mb each way • #create and #show becomes 12mb process • has_many :images?
  • 92. refile • CarrierWave-styled named processors (e.g. :fill, :thumb) vs passing through syntax to underlying ImageMagick • personally prefer leveraging off existing knowledge • instead of manually configured syntax sugar • “2 hop problem” however provide higher consistency when running multiple refile servers • upload-here-download-there problem • (considering to perform 2-hop upload instead of async)
  • 93. refile • Can upload to S3 direct and/or upload to refile • Redundancy interesting, but prefer less concern in Rails app • Concept of cache and store to manage “dangling file problem” is worth considering • Download urls are signed-only (this practice should be adopted) • can partly counter motivation to abuse “dangling file problem” (aka free file hosting, whee!)
  • 94. Questions? Attache server
 https://github.com/choonkeat/attache Gem for Rails
 https://github.com/choonkeat/attache_rails Demo
 https://attache-demo.herokuapp.com/