Невозможно передать загруженный файл в модель - PullRequest
0 голосов
/ 24 мая 2011

Я относительно новичок в rails, поэтому не могу заставить работать следующий код.Я пытаюсь загрузить файл данных (Excel или CSV), скопировать его во временную папку и создать запись в модели Datafiles, которая содержит основную информацию о файле, такую ​​как имя файла, тип и дата.Затем я хочу прочитать файл и использовать данные для создания или обновления записей в нескольких других моделях.Если все идет хорошо, переместите файл на постоянное место и запишите новый путь в записи файлов данных.

Контроллер:

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

def create
  @datafile = Datafile.new(params[:upload])
  @datafile.save!
  redirect_to datafile_path(@datafile), :notice => "Successfully imported datafile"

rescue => e
  logger.error( 'Upload failed. ' + e.to_s )
  flash[:error] = 'Upload failed. Please try again.'
  render :action => 'new'
end

Просмотр:

<%= form_for @datafile, :html => {:multipart => true} do |f| %>
  <p>
    <%= f.label(:upload, "Select File:") %>
    <%= f.file_field :upload %>
  </p>
  <p> <%= f.submit "Import" %> </p>
<% end %>

Модель:

require 'spreadsheet'

class Datafile < ActiveRecord::Base
  attr_accessor :upload
  attr_accessible :upload
  before_create :upload_file

  def upload_file
    begin
      File.open(Rails.root.join('uploads/temp', upload.original_filename), 'wb') do |file|
        file.write(upload.read)
        self.filename = upload.original_filename
        Spreadsheet.client_encoding = 'UTF-8'
        @book = Spreadsheet.open(file.path)
        self.import
      end          
    rescue => e
      @upload_path = Rails.root.join('uploads/temp', upload.original_filename)
      File.delete(@upload_path) if File::exists?(@upload_path)
      raise e
    end
  end

  def import
    case @book.worksheet(0).row(0)[0]

      when "WIP Report - Inception to Date"
      self.report_type = 'WIP'
      puts 'report_type assigned'
      self.import_wip

      else
      self.report_type = 'Unknown'
    end
  end  

  def import_wip
    self.end_date = @book.worksheet(0).row(0)[3]
    puts 'end_date assigned'
  end

  def formatted_end_date
   end_date.strftime("%d %b, %Y")
  end
end

Однако, это терпит неудачу, и окно сервера rails говорит:

Started POST "/datafiles" for 127.0.0.1 at 2011-05-24 16:05:25 +0200
  Processing by DatafilesController#create as HTML
  Parameters: {"utf8"=>"✓", "datafile"=>{"upload"=>#<ActionDispatch::Http::UploadedFile:0xa0282d0 @original_filename="wip.xls", @content_type="application/vnd.ms-excel", @headers="Content-Disposition: form-data; name=\"datafile[upload]\"; filename=\"wip.xls\"\r\nContent-Type: application/vnd.ms-excel\r\n", @tempfile=#<File:/tmp/RackMultipart20110524-14236-1kcu3hm>>}, "commit"=>"Import"}
Upload failed. undefined method `original_filename' for nil:NilClass
Rendered datafiles/new.html.erb within layouts/application (54.5ms)
Completed 200 OK in 131ms (Views: 56.3ms | ActiveRecord: 0.0ms)

У меня есть тесты модели rspec, которые проходят и тесты контроллера, которые не перенаправляют после сохранения.Я могу опубликовать их, если это будет полезно.

Я вставил рейз @ datafile.to_yaml и получил в терминале следующее:

ERROR RuntimeError: --- !ruby/object:Datafile 
attributes: 
  filename: 
  report_type: 
  import_successful: 
  project: 
  begin_date: 
  end_date: 
  created_at: 
  updated_at: 
attributes_cache: {}

changed_attributes: {}

destroyed: false
marked_for_destruction: false
persisted: false
previously_changed: {}

readonly: false

Я заметил, что: загрузка не указана.Могу ли я установить переменные экземпляра модели из формы?: upload - это переменная экземпляра, а не атрибут, потому что я не хочу сохранять загруженный файл в базе данных (только его путь к локальному каталогу).Если я не могу установить переменные экземпляра в форме представления, какие-либо предложения?Имеет ли смысл (с точки зрения MVC) загрузить файл во временную папку в контроллере, а затем создать запись модели, передав ей путь к временному файлу?

1 Ответ

1 голос
/ 14 июля 2011

Здравствуйте, я довольно новичок в Rails и тоже с этим боролся, я нашел решение, хотя оно, вероятно, не самое лучшее. Это работает, хотя.

в вашей модели сделайте публичную функцию import_upload

def import_upload( upload ) 
  @uploaded_file = upload
end

теперь в вашем контроллере вы можете явно передать его. Я не знаю, почему это не происходит автоматически, если вы создаете attr_accsessor с тем же именем, что и file_field, но это было решением, которое сработало для меня.

def new
  foo = Foo.new( params[:foo] )
  foo.import_upload( params[:foo][:uploaded_file] ) #This is were the majic happens
  #Do your saving stuff and call it a day
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...