{"id":199,"date":"2010-05-18T14:33:42","date_gmt":"2010-05-18T14:33:42","guid":{"rendered":"http:\/\/nicholshayes.myzen.co.uk\/blog\/?p=199"},"modified":"2010-05-18T14:41:00","modified_gmt":"2010-05-18T14:41:00","slug":"attachment_fu-working-with-database-file-storage","status":"publish","type":"post","link":"http:\/\/nicholshayes.co.uk\/blog\/?p=199","title":{"rendered":"attachment_fu &#8211; working with database file storage"},"content":{"rendered":"<p>Once I had attachment_fu working with files stored within the Rails application file system, I hit a problem as I wanted to be able to share files across three applications. The problem being that if the file was uploaded in one application, it would be stored within that application&#8217;s public folder. Without adding complication, this location wasn&#8217;t available to the other applications.<\/p>\n<p>The solution was to change over to storing the files within the database. This took a couple of small modifications:<\/p>\n<p><strong>model<\/strong><br \/>\nI changed the has_attachment declaration to:<\/p>\n<div class=\"codecolorer-container ruby default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"ruby codecolorer\">has_attachment <span class=\"re3\">:max_size<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"nu0\">50<\/span>.<span class=\"me1\">megabyte<\/span><\/div><\/div>\n<p>The default attachment_fu is to use the database to store files. So removing the :storage entry in this statement was enough to change over from file system storage to database storage.<\/p>\n<p><strong>database<\/strong><br \/>\nI has to add a new table and an additional column to my main model. The new table was created with:<\/p>\n<div class=\"codecolorer-container ruby default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"ruby codecolorer\">&nbsp; &nbsp; create_table <span class=\"re3\">:db_files<\/span> <span class=\"kw1\">do<\/span> <span class=\"sy0\">|<\/span>t<span class=\"sy0\">|<\/span><br \/>\n&nbsp; &nbsp; &nbsp; t.<span class=\"me1\">column<\/span> <span class=\"re3\">:data<\/span>, <span class=\"re3\">:binary<\/span>, <span class=\"re3\">:limit<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"nu0\">50<\/span>.<span class=\"me1\">megabyte<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">end<\/span><\/div><\/div>\n<p>Note that adding a :limit entry can alter the blob field type created in the database. Without it the standard MySQL behaviour is to create an ordinary blob field. If the :limit statement indicated that a blob isn&#8217;t big enough, the data field will be set as a LONGBLOB.<\/p>\n<p>The extra field added to my product_files table was &#8216;db_file_id&#8217; which is an integer field.<\/p>\n<p><b>public_filename<\/b><br \/>\nWhen working with database file storage, public_filename is no longer available. So I needed to come up with an alternative way to serve the file to the user. <\/p>\n<p><b>controller download action<\/b><br \/>\nTo do this I created a download action.<\/p>\n<div class=\"codecolorer-container ruby default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"ruby codecolorer\">&nbsp; <span class=\"kw1\">def<\/span> download<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> params<span class=\"br0\">&#91;<\/span><span class=\"re3\">:id<\/span><span class=\"br0\">&#93;<\/span> <span class=\"kw1\">and<\/span> ProductFile.<span class=\"me1\">exists<\/span>?<span class=\"br0\">&#40;<\/span>params<span class=\"br0\">&#91;<\/span><span class=\"re3\">:id<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; product_file = ProductFile.<span class=\"me1\">find<\/span><span class=\"br0\">&#40;<\/span>params<span class=\"br0\">&#91;<\/span><span class=\"re3\">:id<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; send_data<span class=\"br0\">&#40;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; product_file.<span class=\"me1\">current_data<\/span>,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"re3\">:type<\/span> <span class=\"sy0\">=&gt;<\/span> product_file.<span class=\"me1\">content_type<\/span>,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"re3\">:filename<\/span> <span class=\"sy0\">=&gt;<\/span> product_file.<span class=\"me1\">filename<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">else<\/span><br \/>\n&nbsp; &nbsp; &nbsp; flash<span class=\"br0\">&#91;<\/span><span class=\"re3\">:error<\/span><span class=\"br0\">&#93;<\/span> = <span class=\"st0\">&quot;Product file not found&quot;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; redirect_to <span class=\"re3\">:action<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"st0\">'index'<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">end<\/span><br \/>\n&nbsp; <span class=\"kw1\">end<\/span><\/div><\/div>\n<p>Note that send_data is a standard Rails method, so its use can be looked up in the <a href=\"http:\/\/api.rubyonrails.com\">Rails api<\/a>. I wasted a little time trying to find this in the attachment_fu code.<\/p>\n<p><b>helper<\/b><br \/>\nIt was then just a case of creating a helper that pointed at this action.<\/p>\n<div class=\"codecolorer-container ruby default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"ruby codecolorer\">&nbsp; <span class=\"kw1\">def<\/span> link_to_download<span class=\"br0\">&#40;<\/span>product_file<span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; link_to<span class=\"br0\">&#40;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"st0\">'Download'<\/span>,<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"re3\">:controller<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"st0\">'product_files'<\/span>,<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"re3\">:action<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"st0\">'download'<\/span>,<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"re3\">:id<\/span> <span class=\"sy0\">=&gt;<\/span> product_file.<span class=\"me1\">id<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; <span class=\"kw1\">end<\/span><\/div><\/div>\n<p><b>view<\/b><br \/>\nThis could then be used in a view, wherever I need a link to download a file I used it like this:<\/p>\n<div class=\"codecolorer-container ruby default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"ruby codecolorer\">&nbsp;<span class=\"sy0\">&lt;%<\/span>= link_to_download<span class=\"br0\">&#40;<\/span>@product_file<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">-%&gt;<\/span><\/div><\/div>\n<p>Job done (except writing the tests of course)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Once I had attachment_fu working with files stored within the Rails application file system, I hit a problem as I wanted to be able to share files across three applications. The problem being that if the file was uploaded in &hellip; <a href=\"http:\/\/nicholshayes.co.uk\/blog\/?p=199\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/199"}],"collection":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=199"}],"version-history":[{"count":9,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/199\/revisions"}],"predecessor-version":[{"id":207,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/199\/revisions\/207"}],"wp:attachment":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=199"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}