Чтение текста из PDF работает в консоли Rails, но не в приложении Rails

У меня есть простой одностраничный PDF-файл с возможностью поиска, который загружается в модель приложения Rails 6 (Car) с помощью Active Storage. Я могу извлечь текст из PDF с помощью гемов tempfile и pdf-reader в консоли Rails:

> @car.creport.attached?
=> true
> f = Tempfile.new(['file', '.pdf'])
> f.binmode
> f.write(@car.creport.blob.download)
> r = PDF::Reader.new(f.path.to_s)
> r.pages[1].text
=> "Welcome to the ABC Car Report for January 16, 20...

Но если я попробую то же самое в методе create моего cars_controller.rb, это не сработает:

# cars_controller.rb
...
  def create
    @car = Car.new(car_params)
    @car.filetext = ""
    f = Tempfile.new(['file', '.pdf'])
    f.binmode
    f.write(@car.creport.blob.download)
    r = PDF::Reader.new(f.path.to_s)
    @car.filetext = r.pages[1].text
    ...
  end

Когда я запускаю приложение Rails, я могу создать новый автомобиль и выбрать файл PDF для прикрепления. Но когда я нажимаю «Отправить», я получаю FileNotFoundError в cars_controller.rb в строке f.write ().

Мой инстинкт подсказывает, что контроллер пытается прочитать большой двоичный объект, чтобы записать его во временный файл слишком рано (то есть еще до того, как этот большой двоичный объект был записан). Я попытался вставить sleep(2), чтобы дать время, но получаю ту же ошибку FileNotFoundError.

Любые идеи?

Спасибо!


person Clint Laskowski    schedule 04.10.2020    source источник


Ответы (2)


Я не понимаю, почему ты прыгаешь через столько обручей. А использование .download без блока загружает весь файл в память (yikes). Если @car.creport является вложением ActiveStorage, вы можете просто использовать открытый метод вместо этого:

@car.creport.blob.open do |file|
  file.binmode
  r = PDF::Reader.new(file) # just pass the IO object
  @car.filetext = r.pages[1].text
end if @car.creport

Вместо этого файл будет записан на диск (как временный файл).

Если вы просто вводите файл через обычный старый ввод файла, вы получите ActionDispatch :: Http :: UploadedFile в параметрах, которые также очень легко открыть:

params[:file].open do |file|
  file.binmode
  r = PDF::Reader.new(file) # just pass the IO object
  @car.filetext = r.pages[1].text
end if params[:file].respond_to?(:open)
person max    schedule 04.10.2020
comment
Я все еще новичок, и я не совсем уверен, что делаю, поэтому у меня было так много шагов ... Я пытался увидеть, где это ломается. Я не мог заставить работать верхнюю часть кода. Сломался там же с тем же FileNotFoundError. Чтобы было ясно, у меня есть форма, которую я использую для загрузки вложения PDF в запись автомобиля. Прямо над вашим блоком кода у меня есть: `` def create @car = Car.new (review_params) `` (Я не уверен, почему этот комментарий неправильно форматируется?) - person Clint Laskowski; 04.10.2020
comment
Оказывается, дьявол кроется в деталях с ActiveStorage. Вложение фактически недоступно до тех пор, пока родительская модель не будет сохранена, это вызывает обновление таблицы BLOB-объектов ActiveStorage, которая устанавливает столбцы resource_id и type. Это утверждает загрузку. - person max; 05.10.2020

Похоже, разница связана с вашей переменной @car.

В консоли у вас есть прикрепленный blob (@car.creport.attached? => true). В вашем контроллере вы инициализируете новый экземпляр класса Car, поэтому, если у вас нет какой-либо инициализации, которая прикрепляет что-то в фоновом режиме, это будет ноль.

Почему это вернет ошибку «файл не найден», я не уверен, но из того, что я вижу, это единственное различие между примерами кода. Вы пытаетесь написать @car.creport.blob.download, который присутствует на @car в консоли, но ноль в вашем контроллере.

person Mark    schedule 04.10.2020