<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://illuminatedcomputing.com/">
  <id>https://illuminatedcomputing.com/</id>
  <title>Illuminated Computing</title>
  <updated>2015-04-28T00:00:00Z</updated>
  <link rel="alternate" href="https://illuminatedcomputing.com/" type="text/html"/>
  <link rel="self" href="https://illuminatedcomputing.com/tags/paperclip/atom.xml" type="application/atom+xml"/>
  <author>
    <name>Paul A. Jungwirth</name>
    <uri>https://illuminatedcommputing.com/</uri>
  </author>
  <entry>
    <id>tag:illuminatedcomputing.com,2015-04-28:/posts/2015/04/paperclip_expiring_url_and_request_has_expired/</id>
    <title type="html">Paperclip expiring_url and "Request has expired"</title>
    <published>2015-04-28T00:00:00Z</published>
    <updated>2015-04-28T00:00:00Z</updated>
    <link rel="alternate" href="https://illuminatedcomputing.com/posts/2015/04/paperclip_expiring_url_and_request_has_expired/" type="text/html"/>
    <content type="html">
&lt;p&gt;I hit a weird error today. My project stores user uploads on S3 with &lt;code&gt;private&lt;/code&gt; permissions, and we use the &lt;a href="https://github.com/thoughtbot/paperclip"&gt;Paperclip&lt;/a&gt; &lt;a href="https://github.com/thoughtbot/paperclip/wiki/Restricting-Access-to-Objects-Stored-on-Amazon-S3"&gt;&lt;code&gt;expiring_url&lt;/code&gt; method&lt;/a&gt; to let people download them. This started failing with a error like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;Error&amp;gt;
  &amp;lt;Code&amp;gt;AccessDenied&amp;lt;/Code&amp;gt;
  &amp;lt;Message&amp;gt;Request has expired&amp;lt;/Message&amp;gt;
  &amp;lt;Expires&amp;gt;2015-04-28T18:30:51Z&amp;lt;/Expires&amp;gt;
  &amp;lt;ServerTime&amp;gt;2015-04-28T18:32:52Z&amp;lt;/ServerTime&amp;gt;
  &amp;lt;RequestId&amp;gt;BLAHBLAHBLAHBLAH&amp;lt;/RequestId&amp;gt;
  &amp;lt;HostId&amp;gt;
    MOREBLAHMOREBLAHMOREBLAHMOREBLAHMOREBLAHMOREBLAHMOREBLAH
  &amp;lt;/HostId&amp;gt;
&amp;lt;/Error&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The problem was that this error occurred immediately, even though we were generating the URLs with a 10 minute expiration time. Well, it turns out S3 was living in the future by 7 minutes (according to &lt;code&gt;ServerTime&lt;/code&gt; above), and our own app was living in the past by another 5. So 5 + 7 = 12 and our URLs were expired before we even generated them. 10 minutes is the example time in the Paperclip documentation linked above, but I guess it’s too short. Watch out for clock skew out there folks!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:illuminatedcomputing.com,2013-06-07:/posts/2013/06/paperclip-with-server-side-files/</id>
    <title type="html">Paperclip with Server-Side Files</title>
    <published>2013-06-07T00:00:00Z</published>
    <updated>2013-06-07T00:00:00Z</updated>
    <link rel="alternate" href="https://illuminatedcomputing.com/posts/2013/06/paperclip-with-server-side-files/" type="text/html"/>
    <content type="html">
&lt;p&gt;Several times in the last few years I’ve built Rails sites that needed to store files via &lt;a href="https://github.com/thoughtbot/paperclip"&gt;Paperclip&lt;/a&gt; that were not uploaded by a user, but generated programmatically on the server side, for instance PDF or Excel reports built from something in the database. There’s not much documentation on this, and my first effort led to &lt;a href="http://stackoverflow.com/questions/7435917/paperclip-assign-an-image-programmatically-and-set-its-name"&gt;this StackOverflow question&lt;/a&gt;. The first solution is not perfect, but it sometimes works:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-ruby"&gt;user.photo = photo_bytes
user.photo.instance_write(&lt;span class="symbol"&gt;:file_name&lt;/span&gt;, photo_file_name)
user.save!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But sometimes that won’t do, because Paperclip uses the file name to determine what kind of file you’ve got. For instance, suppose you’re generating a spreadsheet with the &lt;a href="https://github.com/cxn03651/writeexcel"&gt;WriteExcel gem&lt;/a&gt;:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-ruby"&gt;io = &lt;span class="constant"&gt;StringIO&lt;/span&gt;.new
xls = &lt;span class="constant"&gt;WriteExcel&lt;/span&gt;.new(io)
&lt;span class="comment"&gt;# ...&lt;/span&gt;
xls.close
report.spreadsheet = io.string&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will raise a &lt;code&gt;NoHandlerError&lt;/code&gt; in the last line. The solution is to make sure you give Paperclip something with a filename, not just the raw binary string.&lt;/p&gt;

&lt;p&gt;The easy way out would be to write your spreadsheet to a temp file, then point Paperclip at it. But writing and reading a temp file adds risk of failure, increases disk IO, and slows things down. I’m stubborn, so I really wanted to keep everything in memory.&lt;/p&gt;

&lt;p&gt;My solution is based on the second answer to that StackOverflow question above. If we give Paperclip an &lt;code&gt;IO&lt;/code&gt; object with a method called &lt;code&gt;original_filename&lt;/code&gt;, it will do the right thing. So let’s define this class:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;span class="keyword"&gt;class&lt;/span&gt; &lt;span class="class"&gt;NamedStringIO&lt;/span&gt; &amp;lt; &lt;span class="constant"&gt;StringIO&lt;/span&gt;

  &lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function"&gt;initialize&lt;/span&gt;(data, filename, content_type=&lt;span class="predefined-constant"&gt;nil&lt;/span&gt;)
    &lt;span class="keyword"&gt;super&lt;/span&gt;(data)
    &lt;span class="instance-variable"&gt;@filename&lt;/span&gt; = filename
    &lt;span class="instance-variable"&gt;@content_type&lt;/span&gt; = content_type
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function"&gt;original_filename&lt;/span&gt;
    &lt;span class="instance-variable"&gt;@filename&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function"&gt;content_type&lt;/span&gt;
    &lt;span class="instance-variable"&gt;@content_type&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can change our Paperclip code to this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-ruby"&gt;io = &lt;span class="constant"&gt;StringIO&lt;/span&gt;.new
xls = &lt;span class="constant"&gt;WriteExcel&lt;/span&gt;.new(io)
&lt;span class="comment"&gt;# ...&lt;/span&gt;
xls.close
report.spreadsheet = &lt;span class="constant"&gt;NamedStringIO&lt;/span&gt;.new(
  io.string,
  xls_filename,
  &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;application/vnd.ms-excel&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That code makes Paperclip happy, and it lets us generate a named “file” that never hits the disk.&lt;/p&gt;

&lt;p&gt;Note I’m also adding a &lt;code&gt;content_type&lt;/code&gt; method. Paperclip will accept an instance without that, but if you are storing the files on S3, it will save the file with a generic content type like &lt;code&gt;application/octet-stream&lt;/code&gt;, and that can cause problems when serving the file to web browsers. If you provide a content type here, it will get stored on S3 correctly.&lt;/p&gt;

&lt;p&gt;It would be even better to create our &lt;code&gt;NamedStringIO&lt;/code&gt; at the top, so we don’t have that extra &lt;code&gt;StringIO&lt;/code&gt; we give to WriteExcel. For some reason I couldn’t get WriteExcel to accept my &lt;code&gt;NamedStringIO&lt;/code&gt;, so I had to copy things around a bit. Oh well, good enough for me!&lt;/p&gt;
</content>
  </entry>
</feed>

