Dmitry Tonkushin
Dmitry Tonkushin

Reputation: 3

Rails 3: upload file to public and save path in database using multi-model form

I stuck with file uploading. I'm use a complex form. Here is a model:

class Project < ActiveRecord::Base
  has_one :task
  accepts_nested_attributes_for :task
end

class Task < ActiveRecord::Base
  has_one :project
  accepts_nested_attributes_for :project
end

Here is a view:

<%= form_for(@project) do |f| %>

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

  <%= f.fields_for :task_attributes do |a| %>
    <div class="field">
        <%= a.label :name %><br />
        <%= a.text_field :name %>
        <%= form_tag 'project/upload', :multipart => true do %>
            <label for="file">Upload text File</label><%= a.file_field :path %>
        <% end %>
     </div>
  <% end %>

<% end %>

Here is a controller:

class ProjectsController < ApplicationController
  def new
    @project = Project.new
    @project.build_task

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @project }
    end
  end

  def upload
    uploaded_io = params[:upload][:path]
    File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'w') do |file|
      file.write(uploaded_io.read)
    end
  end

  def create
    @project = Project.new(params[:project])

    respond_to do |format|
      if @project.save
        format.html { redirect_to(@project, :notice => 'Project was successfully created.') }
        format.xml  { render :xml => @project, :status => :created, :location => @project }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @project.errors, :status => :unprocessable_entity }
      end
    end
  end
end

Migration:

class CreateProjects < ActiveRecord::Migration
  def self.up
    create_table :projects do |t|
      t.integer :id
      t.string :name

      t.timestamps
    end
  end

  def self.down
    drop_table :projects
  end
end

class CreateTasks < ActiveRecord::Migration
  def self.up
    create_table :tasks do |t|
      t.string :name
      t.integer :project_id
      t.string :path

      t.timestamps
    end
  end

  def self.down
    drop_table :tasks
  end
end

When I create new project with task via form, I have both records in database. I see task file path in database. But I can't see file in my public directory. I can not figure out how to save the file to public directory.

Please, help me to solve this problem!

Upvotes: 0

Views: 889

Answers (1)

manoj
manoj

Reputation: 1675

You cannot have a nested form in html. You have nested forms. On submitting a form, it will send the data to server as one request and one action within a controller will be called. In your case on submit of the form the create action will be called and not the upload action wont be called.

Get rid of the inner form and add multipart to the outer form. It would suffice for your case.

It is an overhead to handle file uploads manually. I would suggest you to use paperclip or carrierwave. Anyways that is not your problem here.

Upvotes: 1

Related Questions