面试题答案
一键面试1. 在视图中创建文件上传表单
在Rails视图文件(例如app/views/your_controller/new.html.erb
或edit.html.erb
)中:
<%= form_with(model: your_model, local: true, multipart: true) do |form| %>
<%= form.file_field :image %>
<%= form.submit %>
<% end %>
这里model
指定对应的模型,multipart: true
是关键,用于支持文件上传。:image
是自定义的字段名,对应模型中用于存储图片相关信息的属性。
2. 控制器接收和处理上传的文件
在对应的控制器(app/controllers/your_controller.rb
)中:
class YourController < ApplicationController
def create
@your_model = YourModel.new(your_model_params)
if @your_model.save
redirect_to @your_model, notice: 'File uploaded successfully'
else
render :new
end
end
private
def your_model_params
params.require(:your_model).permit(:image)
end
end
在your_model_params
方法中,使用permit
允许image
字段通过强参数检查,create
方法负责接收表单数据并尝试保存模型。
3. 将文件保存到服务器指定目录并确保文件安全性
首先,确保模型有对应的属性来关联文件。假设使用ActiveStorage
(Rails内置文件管理系统):
- 在模型中(
app/models/your_model.rb
)添加:
class YourModel < ApplicationRecord
has_one_attached :image
end
- 保存文件时,
ActiveStorage
会自动处理文件保存及安全性:
class YourController < ApplicationController
def create
@your_model = YourModel.new(your_model_params)
if @your_model.save
redirect_to @your_model, notice: 'File uploaded successfully'
else
render :new
end
end
private
def your_model_params
params.require(:your_model).permit(:image)
end
end
如果不使用ActiveStorage
,可以手动保存文件:
- 在控制器中:
class YourController < ApplicationController
def create
file = params[:your_model][:image]
if file
file_name = SecureRandom.uuid + '.' + file.original_filename.split('.').last
file_path = Rails.root.join('public', 'uploads', file_name)
File.open(file_path, 'wb') do |f|
f.write(file.read)
end
@your_model = YourModel.new(your_model_params.merge(image_path: '/uploads/' + file_name))
if @your_model.save
redirect_to @your_model, notice: 'File uploaded successfully'
else
File.delete(file_path) if File.exist?(file_path)
render :new
end
else
@your_model = YourModel.new(your_model_params)
if @your_model.save
redirect_to @your_model, notice: 'File uploaded successfully'
else
render :new
end
end
end
private
def your_model_params
params.require(:your_model).permit
end
end
这里使用SecureRandom.uuid
生成唯一文件名,防止文件名冲突,并且保存文件到public/uploads
目录。同时在保存失败时,删除已上传的文件以保证文件一致性。 并在模型中添加image_path
字段来存储文件路径。
对于安全性,除了生成唯一文件名外:
- 验证文件类型:
def validate_image_type
return if image.blank?
valid_types = ['image/jpeg', 'image/png', 'image/gif']
errors.add(:image, 'is not a valid image type') unless valid_types.include?(image.content_type)
end
在模型中定义上述方法,并在validates
中调用,确保上传的文件是图片类型。
- 限制文件大小:
def validate_image_size
return if image.blank?
max_size = 5.megabytes
errors.add(:image, 'is too large') if image.byte_size > max_size
end
同样在模型中定义并使用validates
调用,防止过大文件上传。