gpt4 book ai didi

ruby-on-rails-3 - Rails 3.2 HTML5多个文件上传,Carrierwave和没有Javascript

转载 作者:搜寻专家 更新时间:2023-10-31 08:08:14 24 4
gpt4 key购买 nike

目前使用Rails3.2和CarrierWave。
我有多个文件设置,但它需要多个文件字段,但我只需要一个文件字段。如果浏览器不支持html5 multiple属性,我将把它作为默认值提供。
控制器

def new
@ad = Ad.new
5.times { @ad.images.build } // provides multiple file fields in the view.
end

def create
ad = Ad.new(params[:ad])
user = User.find(session[:user_id])
if user.ads << ad
flash[:notice] = "Ad successfully saved."
redirect_to ad_listing_path(ad.id, ad.slug)
else
render :new, :alert => "Ad was not saved."
end
end

查看
<%= f.fields_for :images do |a| %>
<% if a.object.new_record? %>
<%= a.file_field :image, :multiple => true %><br>
<% end %>
<% end %>

如果 5.times { @ad.images.build }提供多个字段,那么显示一个接受多个字段的文件字段的正确方法是什么?

最佳答案

这似乎是一个很受欢迎的问题,没有好的答案,所以我将在这里完整地回答它。在我开始之前,我将提到代码可以在https://github.com/mdchaney/multi上使用,但是接下来看看如何以尽可能简单的方式实现这一点。
在此之前,在html 5中,文件输入字段可以设置“multiple”属性。如果设置了,则结果与具有多个同名文件输入相同。在rails中,为form builder构建的文件输入字段设置“multiple:true”将导致它作为文件数组上传。

<%= f.file_field :files, :multiple => true %>

变成
<input id="model_files" multiple="multiple" name="model[files][]" type="file" />

其中“model”是模型的名称。这个输入控件(至少在chrome中)的标签是“选择文件”,而不是“选择文件”。
卡里尔沃夫不能以本土的方式来处理这个问题。它使用单个文本字段来存储有关单个文件的信息,并使用一些内部逻辑来确定该文件(可能还有其派生文件)的存储位置。将多个文件的信息放在一个文本字段中,用一个设置的分隔符选择一种编码方式,这是可能的。这将需要大量的工作和对CarrierWave的黑客攻击。
不过,我不想攻击CarrierWave,所以问题变成了这样一个事实:一个项目附加多个文件实际上是一个一对多的关系,或者用Rails的术语来说是“有很多”。因此,可以使用一个简单的属性编写器将文件从文件输入字段添加到多个附加记录。
有了这个,我提出了最简单的方法,使用一个带有多个属性集的html 5文件输入字段。有很多方法可以用jquery和flash来实现,但是我在这里特别展示如何用纯html 5来实现。
在我们的示例中,我们将有一个简单的“上传”模型,每个模型都有一个名称和任意数量的链接文件,这些文件将存储在另一个称为“链接的文件”的模型中(这样做很容易,对吧?)。链接的_文件将保存原始文件名、提供的内容类型,当然还有CarrierWave存储其信息的字段。
我们先创建上传的脚手架,然后创建链接文件的模型:
rails g scaffold Upload name:string
rails g model LinkedFile upload:references filename:string mime_type:string file:string

完成后,如果希望对字段设置限制并添加“not null”约束:
class CreateUploads < ActiveRecord::Migration
def change
create_table :uploads do |t|
t.string :name, limit: 100, null: false

t.timestamps
end
end
end


class CreateLinkedFiles < ActiveRecord::Migration
def change
create_table :linked_files do |t|
t.references :upload, null: false
t.string :filename, limit: 255, null: false
t.string :mime_type, limit: 255, null: false
t.string :file, limit: 255, null: false

t.timestamps
end
add_index :linked_files, :upload_id
end
end

现在,让我们通过添加名为“files”的新属性编写器来修复上载模型:
class Upload < ActiveRecord::Base
has_many :linked_files, inverse_of: :upload, dependent: :destroy
accepts_nested_attributes_for :linked_files, reject_if: :all_blank, allow_destroy: true
validates_associated :linked_files

attr_accessible :name, :files, :linked_files_attributes

def files=(raw_files)
raw_files.each do |raw_file|
self.linked_files.build({filename: raw_file.original_filename, mime_type: raw_file.content_type, file: raw_file})
end
end

validates :name, presence: true, length: { maximum: 100 }
end

其中大部分是rails模型的常规声明。这里唯一真正添加的是“files=”方法,它在数组中获取一组上载的文件,并为每个文件创建一个“链接的”文件。
我们需要一个CarrierWave上传程序:
class FileUploader < CarrierWave::Uploader::Base

storage :file

def store_dir
"uploads/#{model.class.to_s.underscore}/#{model.id}/#{mounted_as}"
end

end

这是最简单的上传程序,您可能希望限制上传的文件类型或其他。现在,linkedfile模型:
class LinkedFile < ActiveRecord::Base
mount_uploader :file, FileUploader

belongs_to :upload, inverse_of: :linked_files

attr_accessible :file, :filename, :mime_type, :file_cache, :remove_file

validates :filename, presence: true, length: { maximum: 255 }
validates :mime_type, presence: true, length: { maximum: 255 }
end

这没有什么特别的,只添加了:file_cache和:remove_file作为文件上传程序的可访问属性。
除了风景,我们现在都结束了。我们实际上只需要更改表单,但我们还将更改“显示”以允许访问上载的文件。这是_form.html.erb文件:
<%= form_for(@upload, { multipart: true }) do |f| %>
<% if @upload.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@upload.errors.count, "error") %> prohibited this upload from being saved:</h2>

<ul>
<% @upload.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>

<% if f.object.linked_files.size == 0 -%>

<div class="field">
<%= f.label :files %><br />
<%= f.file_field :files, :multiple => true %>
</div>

<% else -%>

<fieldset>
<legend>Linked Files</legend>
<%= f.fields_for :linked_files do |lff| -%>
<div class="field">
<%= lff.label :filename %><br />
<%= lff.text_field :filename %>
</div>
<div class="field">
<%= lff.label :mime_type %><br />
<%= lff.text_field :mime_type %>
</div>
<div class="field">
<%= lff.label :file, 'File (replaces current selection)' %><br />
<%= lff.file_field :file %>
<%= lff.hidden_field :file_cache %>
</div>
<div class="field">
<%= lff.check_box :_destroy %>
Remove this file
</div>
<hr />
<% end -%>
</fieldset>

<% end -%>

<div class="actions">
<%= f.submit %>
</div>
<% end %>

我添加了两段代码。如果@upload对象没有与之关联的“链接的文件”,我只显示多个文件输入。否则,我将显示每个链接的文件及其所有信息。可以添加一个“files”方法来上传和处理它,但是这样做会在请求之间丢失mime类型。
您可以很容易地测试这一点,因为上传“名称”是一个必需字段。启动服务器并转到 http://127.0.0.1:3000/uploads查看应用程序。点击“新建”链接,选择一些文件,点击“创建上传”,不提供名称。下一页将显示所有正在等待的文件。当你添加一个名字时,一切都会被保存。让我们修改“show”操作以显示链接的文件:
<p id="notice"><%= notice %></p>

<p>
<b>Name:</b>
<%= @upload.name %>
</p>

<p>
<b>Files:</b><br />
</p>

<table>
<thead><tr><th>Original Filename</th><th>Content Type</th><th>Link</th></tr></thead>
<tbody>
<% @upload.linked_files.each do |linked_file| -%>
<tr>
<td><%= linked_file.filename %></td>
<td><%= linked_file.mime_type %></td>
<td><%= link_to linked_file.file.url, linked_file.file.url %></td>
</tr>
<% end -%>
</tbody>
</table>

<%= link_to 'Edit', edit_upload_path(@upload) %> |
<%= link_to 'Back', uploads_path %>

在这篇文章中,我只是为“文件”添加了一个标题和一个表,其中显示了所有文件并提供了一个查看链接。没什么好奇怪的,但很管用。
如果我把它变成一个真正的应用程序,我可能还会在uploads索引页上提供一个文件列表或最少的一个文件计数。
就这样。同样,如果您想下载整个测试应用程序,可以在github上找到它,但是我已经将生成语句和更改的全部rails放在本文中。

关于ruby-on-rails-3 - Rails 3.2 HTML5多个文件上传,Carrierwave和没有Javascript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11317419/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com