Rails ActiveStorage: how to avoid one redirect for each image?

前端 未结 2 901
梦毁少年i
梦毁少年i 2021-02-06 13:38

If you use ActiveStorage and you have a page with N images you get N additional requests to your Rails app (i.e. N redirects). That means wasting a lot of server resources if yo

相关标签:
2条回答
  • 2021-02-06 14:35

    After days of reasoning and tests, I am really excited of my final solution, which I explain below. This is an opinionated approach to images and may not represent the current Rails Way™️, however it has incredible advantages for websites that serve many public images, in particular:

    1. When you serve a page with N images you don't get 1 + N requests to your app server, instead you get only 1 request for the page
    2. The images are served through a CDN and this improves the loading time
    3. The bucket is not completely public, instead it is protected by Cloudflare
    4. The images are cached by Cloudflare, which greatly reduce your S3 bill
    5. You greatly reduce the number of API requests (i.e. exists) to S3
    6. This solution does not require large changes to Rails, and thus it is straightforward to switch back to Rails default behavior in case of problems

    Here's the solution:

    1. Create an s3 bucket and configure it to host a public website (i.e. call it storage.example.com) - you can even disable the public access at bucket level and allow access only to the Cloudflare ips using a bucket policy
    2. Go to Cloudflare and configure a CNAME for storage.example.com that points to your domain; you need to use Flexible SSL (you can use a page rule for the subdomain); use page rules to set heavy caching: set Cache Everything and set a very long value (e.g. 1 year) for Browser Cache TTL and Edge Cache TTL
    3. In you Rails application you can keep using private storage / acl, which is the default Rails behavior
    4. In your Rails application call @post.variant(...).processed after every update or creation of @post; then in your views use 'https://storage.example.com/' + @post.variant(...).key' (note that we don't call processed here in the views to avoid additional checks in s3); you can also have a rake task that calls processed on each object, in case you need to regenerate the variants; this is works perfectly if you have only a few variants (e.g. 1 image / variant per post) that are changed infrequently

    Most of the above steps are optional, so you can combine them based on your needs.

    0 讨论(0)
  • 2021-02-06 14:43

    You can use the service_url to create direct links to your resources.

    We don't use Rails views in our project so my knowledge about the view layer is rusty. I think you could put it in a dedicated helper and then use it from your views.

    0 讨论(0)
提交回复
热议问题