ruby on rails file download binary files from the database and provide a link

1k views Asked by At

I have 3 files in my mysql database. 2 of them is of type 'text' and 1 is 'longblob'.

|username| |pem      | |key       | |cert              |

|test1   | |some text| |Some text | | Some binary text |

|test2   | |some text| |Some text | | Some binary text |

I can query them and have an array ActiveRecord Relation object in the @user_files variable.

Now, I want to create the 3 files filename1.pem, filename1.key, filename1.cert for each user and provide them as a link for download.

Something like:

<%- @user_files.each do |user_info| %>
  <tr>
    <td><%= link_to 'Download Files', download_path(user_info) %></td>
  </tr>
<% end %>

Here is what I had in my mind so far in my controller:

 def download(user_file)
    temp = Tempfile.new("temp-filename-#{Time.now}")
    Zip::ZipOutputStream.open(temp.path) do |z|
      z.put_next_entry("some_name.pem")
      z.print IO.read(user_file.pem)
      z.put_next_entry("some_name.key")
      z.print IO.read(user_file.key)
      z.put_next_entry("some_name.cert")
      z.print IO.read(user_file.cert)
     end
     send_file temp.path, :type => 'application/octet-stream', :filename => "some_name.zip"
    temp.close  
 end

I am getting the following error:

wrong number of arguments (0 for 1)
app/controllers/my_controller.rb:16:in `download'

My routes is as follows:

get 'download' => 'my_controller#download', as: :download

My first question is if this is the right approach and will it even work? I would appreciate it if someone could guide me to a cleaner approach for my requirement.

EDIT: I updated to use params

<%= link_to 'Download Files, download_path(user_info) %>

def download
  user_info = params[:id]
  #remaining code
end

Also get this error now afte rthe route update suggested in the answer:

No route matches [GET] "/download/415"
1

There are 1 answers

9
blelump On BEST ANSWER

Controller action must not have any arguments. Everything you would like to pass to your controller action is accessed by params variable which is a Hash (HashWithIndifferentAccess actually). So that, your download action might look like:

 def download
    user_file = params[:id]
    temp = Tempfile.new("temp-filename-#{Time.now}")
    Zip::ZipOutputStream.open(temp.path) do |z|
      z.put_next_entry("some_name.pem")
      z.print IO.read(user_file.pem)
      z.put_next_entry("some_name.key")
      z.print IO.read(user_file.key)
      z.put_next_entry("some_name.cert")
      z.print IO.read(user_file.cert)
     end
     send_file temp.path, :type => 'application/octet-stream', :filename => "some_name.zip"
    temp.close  
 end

Also, change your route into:

get 'download/:id' => 'my_controller#download', as: :download