Rails使用file_field上传文件时如何正确获取上传文件的路径
你遇到的报错是三个核心问题导致的:
- 表单未开启文件上传的编码格式,后端无法正常接收文件参数
- 绑定模型的表单提交的参数是嵌套结构,你取值的路径不对
- HTTP请求无状态,表单提交的参数不会自动传递到跳转后的show动作,需要先在表单提交对应的动作中处理文件
步骤1:修改表单开启文件上传支持
form_with默认不会自动设置multipart编码格式,只要包含文件上传字段必须显式指定:
<%= form_with(model: friend, multipart: true) do |form| %> <!-- 原有表单内容保持不变 --> <% end %>
步骤2:调整控制器逻辑,在表单提交动作中处理文件
表单默认提交到对应模型的create(新增场景)或update(编辑场景)动作,你需要在这里接收文件参数,再把需要的路径传递到show页面:
2.1 添加强参数允许文件字段
在控制器底部的强参方法中新增file字段的放行:
private def friend_params params.require(:friend).permit(:file, # 补充其他你需要的业务字段即可) end
2.2 在create动作中接收文件获取路径
Rails接收到的上传文件是ActionDispatch::Http::UploadedFile对象,你可以直接调用path方法获取服务器上的临时文件路径,注意:出于浏览器安全限制,你无法获取用户本地的文件路径(也就是你提到的D盘路径),只能拿到文件上传到服务器后的临时存储路径
def create @friend = Friend.new(friend_params) uploaded_file = params[:friend][:file] if uploaded_file.present? # 获取服务器临时文件路径 temp_path = uploaded_file.path # 方式1:如果需要后续持久使用,建议给friend表新增file_path字段,存到数据库 @friend.file_path = temp_path # 方式2:如果只是临时在show页面展示一次,也可以存在session中(不推荐) # session[:uploaded_file_path] = temp_path end if @friend.save redirect_to @friend else render :new end end
步骤3:修改show动作的取值逻辑
直接从持久化的friend对象中读取路径即可:
def show @friend = Friend.find(params[:id]) @answer = @friend.file_path # 如果用了session存的方式就改成 @answer = session.delete(:uploaded_file_path) end
额外注意事项
- Rails的上传临时文件会在请求结束后自动清理,如果需要长期使用文件,不要只存临时路径,需要把文件转存到服务器的公共目录或者云存储中
- 如果需要读取CSV内容,不需要读取路径,直接调用
uploaded_file.read就可以拿到文件的文本内容直接解析
内容的提问来源于stack exchange,提问作者Diwanshu Tyagi
相关产品推荐
相关产品推荐

