TIL from the Rocketship

TILJanuary 16, 2019by Dmitry Voronov

Use image files from S3 in WickedPdf

If you need to use image files from S3 in your generated pdf file using WickedPdf, then you need first to download the image. You can create method that does this and add it to the helper.


require 'open-uri'



module PdfHelper

  def embed_remote_image(url, content_type)

    asset = open(url, "r:UTF-8", &:read)

    base64 = Base64.encode64(asset.to_s).gsub(/\s+/, "")

    "data:#{content_type};base64,#{Rack::Utils.escape(base64)}"

  end

end

And use image_tag instead of wicked_pdf_image_tag


= image_tag embed_remote_image(file.logo_url, 'image/jpeg')

TILJanuary 07, 2019by Dmitry Voronov

How to create zip files on the fly w/o Tempfile

There are many articles about how to archive files from the server and send a zip-file to a client without persisting it on the server. But usually they don't literally do it, because they use temporary files.

There is a simple way to do it without creating any file though. You just have to put files directly to Zip::OutputStream and then read from it. Btw pay attention: you must rewind the stream before reading it.


# some files objects

def download(files)

  zip_stream = Zip::OutputStream.write_buffer do |zip|

    files.each.with_index(1) do |file, index|

     # file name must be uniq in archive

      zip.put_next_entry("#{file.name}--#{index}.#{file.extension}")

      zip.write(file.read.force_encoding('utf-8'))

    end

  end

  # important - rewind the steam

  zip_stream.rewind

  send_data zip_stream.read, 

            type: 'application/zip', 

            disposition: 'attachment', 

            filename: 'files-archive.zip'

end

TILDecember 28, 2018by Alexander Spitsyn

How to implement inheritance in Grape resources?

Grape uses specific DSL to define endpoints in API, that’s why you can’t use base class’ instance methods in descendant resources. But there’s one trick:

There’s an #inherited class method in Ruby which is triggered every time some class inherits from ancestor class. It passes one argument - descendant class. Calling descendant’s #instance_eval method we can place any useful stuff inside a block: methods, helpers, before-do’s, etc, in this way evaluating it in context of subclass.


class Base < Grape::API

  def self.inherited(subclass)

    super



    subclass.instance_eval do

      helpers do

        def current_user

          @current_user ||= User.find(params[:user_id])

        end

      end

      # ...

    end 

  end

end



class DocumentsResource < Base

  post '/documents' do

    @document = current_user.documents.build

    # ...

  end

end

Note that it’s not real inheritance because Base class has not methods defined inside subclass#instance_eval block.