4

私が取り組んでいる Rails アプリに少し問題があります。Carrierwave、Nested_form、Simple_form、および Jquery-file-upload gem を利用しています。

データを除いて、ほとんどすべてが正常に機能しています。

プロジェクト モデルと添付ファイル モデルの 2 つのモデルがあります。

プロジェクト フォームが送信されると、すべてのファイルが必要に応じてアップロードされ、添付ファイル モデルのレコードが必要に応じて作成されます (ファイルごとに 1 つ)。しかし、プロジェクト モデルに関しては、ファイルごとにレコードも作成されます。

プロジェクトのレコードを 1 つだけ取得し、添付ファイルのレコードを複数取得する方法を (単一のフォームで、単一の送信で) 理解できないようです。

以下にコードの概要を示します。できれば 2 段階のプロセスは避けたいのですが、誰かが私を正しい方向に向けてくれれば助かります。

プロジェクトモデル

class Project < ActiveRecord::Base
  has_many :attachments, :dependent => :destroy

  accepts_nested_attributes_for :attachments, :allow_destroy => true

  def generate_token
    self.token = loop do
      random_token = SecureRandom.urlsafe_base64
      break random_token unless Project.where(token: random_token).exists?
    end
  end
end

アタッチメントモデル

class Attachment < ActiveRecord::Base
  belongs_to :project, :polymorphic => true

  include Rails.application.routes.url_helpers

  mount_uploader :file, AttachmentUploader

  def to_jq_upload
  {
    "name" => read_attribute(file),
    "url" => file.url,
    "size" => file.size,
    "delete_url" => attachment_path(:id => id),
    "delete_type" => "DELETE"
  }
  end
end

プロジェクト管理者

class ProjectsController < ApplicationController
  def index
  @projects = Project.all

  respond_to do |format|
    format.html
    format.json { render json: @projects }
  end
end

def new
  @project = Project.new
  @project.token = @project.generate_token
  @attachments = @project.attachments.build
end

def create
  @project = Project.new(project_params)
  respond_to do |format|
    if @project.save
      format.html { redirect_to projects_url, notice: 'Project was successfully created.' }
      format.json { render json: @project, status: :created, location: @project }
    else
      format.html {}
      format.json {}
    end
  end
end

def destroy
  @project = Project.find(params[:id])
  @project.destroy

  respond_to do |format|
    format.html { redirect_to projects_url }
    format.json { head :no_content }
  end
end

private
  def project_params
    params.require(:project).permit(:name, :token, :number_of_pages, :number_of_copies, :flat_page_size, :trim_page_size, :purchase_order_number, :preferred_delivery_date, :delivery_method, :delivery_instructions, :project_instructions, attachments_attributes: [:id, :attachment, :name, :filename, :file, :project_token, :branch])
  end
end

アタッチメントコントローラー

class AttachmentsController < ApplicationController
before_filter :the_project

def index
  @attachments = Attachment.where("project_id = ?", the_project)
  render :json => @attachments.collect { |p| p.to_jq_upload }.to_json
end

def create
  @project = Project.find(params[:project_id])
  @attachment = Attachment.new(attachment_params)

  if @attachment.save
    respond_to do |format|
      format.html { render :json => [@attachment.to_jq_upload].to_json, :content_type => 'text/html', :layout => false }
      format.json { render :json => {files: [@attachment.to_jq_upload]}.to_json }
    end
  else
    render :json => [{ :error => "custom_failure "}], :status => 304
  end
end

def destroy
  @attachment = Attachment.find(params[:id])
  @attachment.destroy

  render :json => true
end

private

  def the_project
    @project = Project.find(params["project_id"])
  end

end

新しいプロジェクト フォーム (app/views/projects/new.html.erb)

<h2>New Project</h2>
<br />

<%= simple_nested_form_for @project, :defaults => { :wrapper_html => {:class => 'form-group'}, :input_html => { :class => 'form-control' } }, :html => { :multipart => true,  :id => "fileupload", :class => 'horizontal-form', :role => "form" } do |f| %>

<div class="row">
  <div class="col-lg-12">
    <%= f.input :name, :label => "Project Name / Description", :class => 'col-lg-12' %>
    <%= f.hidden_field :token %>
  </div>
</div>
<div class="row">
  <div class="col-lg-6">
    <%= f.input :number_of_pages %>
    <%= f.input :flat_page_size %>
    <%= f.input :purchase_order_number %>
  </div>

  <div class="col-lg-6">
    <%= f.input :number_of_copies %>
    <%= f.input :trim_page_size, :label => 'Finished Size <em><small>(If Different from Flat Page Size)</small></em>' %>
    <%= f.input :preferred_delivery_date, :as => :text %>
  </div>
</div>

<div class="row">
  <div class="col-lg-6">
    <%= f.input :delivery_method %>
  </div>

  <div class="col-lg-6">
    <%= f.input :project_instructions %>
  </div>
</div>

<div class="row">
  <div class="col-lg-6">
    <select id="branches">
      <option>Calgary Downtown</option>
      <option>Calgary South</option>
      <option>Edmonton</option>
      <option>Kelowna</option>
    </select>
  </div>
</div>
<br />
<div class="row fileupload-buttonbar">
  <div class="col-lg-7">
    <%= fields_for :attachments do |a| %>
      <span class="btn btn-success fileinput-button">
        <i class="glyphicon glyphicon-plus"></i>
        <span>Add files...</span>
        <%= a.file_field :file, :name => 'project[attachments_attributes][0][file]', :multiple => true %>      
      </span>

      <button type="submit" class="btn btn-primary start">
        <i class="glyphicon glyphicon-upload"></i>
        <span>Start Upload</span>
      </button>

      <button type="reset" class="btn btn-warning cancel">
        <i class="glyphicon glyphicon-ban-circle"></i>
        <span>Cancel Upload</span>
      </button>

      <button type="button" class="btn btn-danger delete">
        <i class="glyphicon glyphicon-trash"></i>
        <span>Delete Upload</span>
      </button>

       <%= a.hidden_field :branch, :value => "Calgary Downtown" %>
       <%= a.hidden_field :project_token, :value => @project.token %>
      <% end %>
    </div>

    <div class="col-lg-5">
      <div class="progress progress-success progress-striped active fade">
      <div class="bar" style="width:0%"></div>
    </div>
  </div>

</div>

<div class="row fileupload-loading"></div>

  <div class="row">
    <table class="table table-striped">
      <tbody class="files" data-toggle="modal-gallery" data-target="#modal-gallery">
      </tbody>
    </table>
  </div>
<% end %>

<script>
  var fileUploadErrors = {
    maxFileSize: 'File is too big',
    minFileSize: 'File is too small',
    acceptFileTypes: 'Filetype not allowed',
    maxNumberOfFiles: 'Max number of files exceeded',
    uploadedBytes: 'Uploaded bytes exceed file size',
    emptyResult: 'Empty file upload result'
  }; 
</script>

<!-- The template to display files available for upload -->
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
  <tr class="template-upload fade">
      <td class="preview"><span class="fade"></span></td>
      <td class="name"><span>{%=file.name%}</span></td>
      <td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
        {% if (file.error) { %}
          <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
        {% } else if (o.files.valid && !i) { %}
          <td>
              <div class="progress progress-success progress-striped active"><div class="bar" style="width:0%;"></div></div>
          </td>
          <td class="start">{% if (!o.options.autoUpload) { %}
              <button class="btn btn-primary">
                  <i class="icon-upload icon-white"></i>
                  <span>{%=locale.fileupload.start%}</span>
              </button>
          {% } %}</td>
      {% } else { %}
          <td colspan="2"></td>
      {% } %}
      <td class="cancel">{% if (!i) { %}
          <button class="btn btn-warning">
              <i class="icon-ban-circle icon-white"></i>
              <span>{%=locale.fileupload.cancel%}</span>
          </button>
      {% } %}</td>
  </tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
  {% for (var i=0, file; file=o.files[i]; i++) { %}
  <tr class="template-download fade">
    {% if (file.error) { %}
      <td></td>
      <td class="name"><span>{%=file.name%}</span></td>
      <td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
      <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
      {% } else { %}
          <td class="preview">{% if (file.thumbnail_url) { %}
              <a href="{%=file.url%}" title="{%=file.name%}" rel="gallery" download="{%=file.name%}"><img src="{%=file.thumbnail_url%}"></a>
          {% } %}</td>
          <td class="name">
              <a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&&'gallery'%}" download="{%=file.name%}">{%=file.name%}</a>
          </td>
          <td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
          <td colspan="2"></td>
      {% } %}
      <td class="delete">
          <button class="btn btn-danger" data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}">
              <i class="icon-trash icon-white"></i>
              <span>{%=locale.fileupload.destroy%}</span>
          </button>
          <input type="checkbox" name="delete" value="1">
      </td>
  </tr>
{% } %}
</script>

<script type="text/javascript" charset="utf-8">
  $(function () {
    var num_added = 0;
    var added = 0;
    var all_data = {};

    $('#branches').change(function() {

        var test = $("option:selected",this).text();
        $('#project_attachments_attributes_0_branch').val(test);

     });

    // Initialize the jQuery File Upload widget:
    $('#fileupload').fileupload({
      sequentialUploads: true,
    });

   });
 </script>
4

2 に答える 2

-1

I believe you need to include the index of the 'parent' instance in the input, in this case, Project. So:

 <%= a.file_field :file, :name => 'project[*index*][attachments_attributes][0][file]', :multiple => true %> 
于 2014-12-03T22:58:11.163 に答える