LoginSignup
2
4

More than 5 years have passed since last update.

paperclip の Interpolator を自作して URL生成を高速化した

Posted at

最近 ぼくが携わっているサービスで paperclipのURL生成におけるパフォーマンス改善を行ったので、知見を一般化して共有します。

paperclipのパフォーマンスにおける問題

paperclipのURL生成は難読化のために:hashを用いている状況下でとても遅くなります。これは、Paperclip::Interpolations::interpolatepaperclip/interpolations.rb)における計算量が大きくなることが原因のようでした。

Paperclip::Interpolations は URLパターンの一部である:booのような表現箇所を適切な値に置換する責務を持つモジュールであり、paperclipにおけるデフォルトのinterpolatorとして定義(paperclip/attachment.rb)されています。

「デフォルトのinterpolator」と述べた通り、これはオプションで変更可能です。ということで、Interpolator を自作することで高速化を試み、ベンチマークをとってみます。

作ったもの

# lib/paperclip/custom_interpolator.rb
# see: https://github.com/mizoR/paperclip-benchmark-app/blob/master/lib/paperclip/custom_interpolator.rb

module Paperclip
  class CustomInterpolator
    include Interpolations

    def interpolate pattern, *args
      pattern = args.first.instance.send(pattern) if pattern.kind_of? Symbol
      pattern.gsub(/:([a-z][a-z0-9_]+)/) do |match|
        method_name = $1
        respond_to?(method_name) ? send(method_name, *args) : match
      end
    end

    def plural_cache
      Interpolations.plural_cache
    end
  end
end

使い方

has_attached_file にオプションとして interpolator: CustomInterpolator.new を渡す。

# app/models/user.rb
class User < ActiveRecord::Base
  has_attached_file :avatar,
    styles: { medium: "300x300>", thumb: "100x100>" },
    default_url: "/images/:style/missing.png",
    url: "/system/:rails_env/:class/:attachment/:id/:hash.:extension",
    hash_secret: "785AFEE8C45E71086D262DB0B0A31442",
    interpolator: Paperclip::CustomInterpolator.new    # <-- こんな感じ

  validates_attachment_file_name :avatar,
    matches: [/png\Z/, /jpe?g\Z/]
end

ベンチマーク

Calculating -------------------------------------
Paperclip::Interpolations
                         9.000  i/100ms
Paperclip::CustomInterpolator
                        16.000  i/100ms
-------------------------------------------------
Paperclip::Interpolations
                        100.019  (± 3.0%) i/s -    999.000
Paperclip::CustomInterpolator
                        162.002  (± 3.1%) i/s -      1.632k

問題

作成した Paperclip::CustomInterpolatorは、オリジナルの Paperclip::Interpolations と比べると以下の挙動に違いが生まれています。たとえば、

url: '/files/:idwhat.:extension'

のようなURLパターンでは、

# Paperclip::Interpolations の場合 `:id`部分が置換される
/files/1234what.png

# Paperclip::CustomInterpolator の場合 (`#idwhat` というメソッドが定義されていないため)置換されない
/files/:idwhat.png

となってしまいます。ので、このようなパターンを利用しているサービスの場合はもうすこし工夫が必要になります。

まとめ

  • Paperclip::Interpolations::interpolate は結構遅い
  • Interpolator を自作することでパフォーマンスを改善できるかも

リンク

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4