ruby-on-rails - 如何编写用于正确下载和下载文件的控制器
问题描述
我有 Rails 作为后端和前端 Angular 5。如何在 Rails 上正确编写控制器和路由,以便将来可以使用 Angular 上传和下载文件?我正在使用的常规控制器不工作:
class FilesController < ApplicationController
before_action :set_file, only: [:show, :update, :destroy]
def index
@files = File.all
render json: @files
end
def show
render json: @file
end
def create
@file = File.new(files_params)
if @file.save
render json: @file, status: :created, location: @file
else
render json: @file.errors, status: :unprocessable_entity
end
end
def update
if @file.update(files_params)
render json: @file
else
render json: @file.errors, status: :unprocessable_entity
end
end
def destroy
@file.destroy
end
private
def set_file
@file = File.find(params[:id])
end
def files_params
params.require(:file).permit!
end
end
文件:
ID: NUMBER
NAME: VARCHAR2
FILE_NAME: VARCHAR2
CONTENT: BLOB
FILE_TYPE: VARCHAR2
解决方案
TL;博士:
除非您真的打算将文件数据包含在 JSON 响应中,否则我将使用解决方案 2 而不是解决方案 1。
解决方案 1:JSON 包含文件的 Base64 编码字符串
应用程序/模型/file.rb:
class File < ApplicationRecord
def as_json(options = nil)
super(
except: [:content],
methods: [:content_encoded]
)
end
def content_encoded
Base64.strict_encode64(content)
end
end
然后,在你的 JS 中:
// do AJAX call to FilesController#index...
// sample JSON response:
// [
// { "id": 1, "name": "...", "file_name": "...", "file_type": "...", "content_encoded": "SGVsbG8gCiB3b3JsZCBoYWhhaGE=", "created_at": "...", "updated_at": "..." },
// { "id": 2, "name": "...", "file_name": "...", "file_type": "...", "content_encoded": "WW93cyB5b3dzIHlvd3Mh", "created_at": "...", "updated_at": "..." }
// ]
// then, say we now have this response body Object (named `data`)
Object.forEach(data, function(file) {
// atob decodes Base64-encoded-string into Binary-string
var fileContent = atob(file.content_encoded)
});
解决方案 2:JSON 包含文件的 URL 字符串
应用程序/控制器/files_controller.rb:
class FilesController < ApplicationController
before_action :set_file, only: [:show, :update, :destroy, :content]
def index
@files = File.all
json_response = @files.collect do |file|
file.as_json(
except: :content
).merge(
content_url: content_file_url(file)
)
end
render json: json_response
end
def content
send_data @file.content
end
# ...
end
应用程序/配置/路由.rb
Rails.application.routes.draw do
resources :files do
# will generate a route: GET /files/:id/content as `content_file_url`
get :content, on: :member
end
end
然后,在你的 JS
// do AJAX call to FilesController#index...
// sample JSON response:
// [
// { "id": 1, "name": "...", "file_name": "...", "file_type": "...", "content_url": "http://localhost:3000/files/1/content", "created_at": "...", "updated_at": "..." },
// { "id": 2, "name": "...", "file_name": "...", "file_type": "...", "content_url": "http://localhost:3000/files/2/content", "created_at": "...", "updated_at": "..." }
// ]
// then, say we now have the response body Object (named `data`)
Object.forEach(data, function(file) {
console.log(file.content_url)
});
推荐阅读
- r - 在 Ggplot 中添加一个不与先前参数重叠的图层
- javascript - 通过检查响应来处理 Promise 中的错误
- javascript - 从 JS 到 PHP 的 POST 请求:错误的 JSON
- python-3.x - 从 MongoDB 集合中的一组文档中创建一个列表
- scientific-computing - 使用 nextflow 创建奇点容器
- javascript - 如何在html中使用滚动条来动态分配按钮?
- java - JDBC 查找旧表名
- docker - Docker - dockerfile 中的多个卷
- sql-server - 我可以在 Azure Sql 数据库和 Sql Server 2012(本地服务器)之间创建复制吗?
- c# - 我怎样才能做出正确的 if/else if/else 语句?