Question Utilisation de Send_File vers une source distante (Ruby on Rails)


Dans mon application, j'ai une exigence qui me frappe.

J'ai un fichier stocké dans S3, et quand un utilisateur clique sur un lien dans mon application, je me connecte à la base de données sur laquelle il a cliqué, diminue son allocation de téléchargement, puis je demande le fichier. Télécharger.

Je ne veux pas simplement rediriger l'utilisateur vers le fichier car il est stocké dans S3 et je ne veux pas qu'ils aient le lien du fichier source (pour que je puisse maintenir l'intégrité et l'accès)

Il semble que send_file () ne fonctionne pas avec un fichier source distant, quiconque recommande un gem ou un code approprié qui le fera?


11
2017-08-24 12:20


origine


Réponses:


Vous devez diffuser le contenu du fichier à l'utilisateur tout en le lisant depuis le compartiment / objet S3.

Si vous utilisez le AWS :: S3 quelque chose comme ceci peut fonctionner:

 send_file_headers!( :length=>S3Object.about(<s3 object>, <s3 bucket>)["content-length"], :filename=><the filename> )
 render :status => 200, :text => Proc.new { |response, output|
   S3Object.stream(<s3 object>, <s3 bucket>) do |chunk|
     output.write chunk
   end
 }

Ce code est principalement copié à partir du code send_file qui, à lui seul, ne fonctionne que pour les fichiers locaux ou les objets de type fichier.

N.B. Je conseillerais de toute façon de ne pas servir le fichier à partir du processus ferroviaire lui-même. Si possible / acceptable pour votre cas d'utilisation, j'utiliserais un authentifié GET pour servir les données privées du compartiment.

En utilisant un objet GET authentifié, vous pouvez garder le compartiment et ses objets privés, tout en autorisant une autorisation temporaire de lire un contenu d'objet spécifique en créant une URL qui inclut un jeton de signature d'authentification. L'utilisateur est simplement redirigé vers l'URL authentifiée et le jeton peut être validé pendant quelques minutes seulement.

En utilisant AWS :: S3 mentionné ci-dessus, vous pouvez obtenir une URL GET authentifiée de cette manière:

 time_of_exipry = Time.now + 2.minutes
 S3Object.url_for(<s3 object>, <s3 bucket>,
                  :expires => time_of_exipry)

9
2017-08-24 12:57



Vous pouvez lire le fichier depuis S3 et l'écrire localement dans un répertoire non public, puis utiliser X-Sendfile (apache) ou X-Accel-Redirect (nginx) pour diffuser le contenu.

Pour nginx, vous devez inclure ce qui suit dans votre configuration:


            location /private {
                                 internal;
                                 alias /path/to/private/directory/;
            }

Ensuite, dans votre contrôleur de rails, vous procédez comme suit:


   response.headers['Content-Type'] = your_content_type
   response.headers['Content-Disposition'] = "attachment; filename=#{your_file_name}"
   response.headers['Cache-Control'] =  "private"
   response.headers['X-Accel-Redirect'] = path_to_your_file
   render :nothing=>true

Une bonne rédaction du processus est ici


3
2017-08-24 18:57



Méthode de téléchargement d'images complètes utilisant un fichier temporaire (rails testés 3.2):

def download
  @image = Image.find(params[:image_id])

  open(@image.url) {|img|
    tmpfile = Tempfile.new("download.jpg")
    File.open(tmpfile.path, 'wb') do |f| 
      f.write img.read
    end 
    send_file tmpfile.path, :filename => "great-image.jpg"
  }   
end

3
2017-08-16 23:58