视图不打印数据库列值(Ruby on Rails)

View does not print database column value (Ruby on Rails)

标题也可以是:update_column 语句没有在数据库中保存值,尽管日志表明发生了这种情况。

我想将 PDF 文件上传到 Google 云存储,为了开始,我下载了 Google 的示例 Rails 应用程序,我可以完美地工作(上传和下载) 然后我将代码复制到我自己的应用程序中(请参阅下面的相关文件)并且文件 UPloading 也能正常工作。

但是,由于某些原因,在 upload.rb 模型文件中,当 file 数据库列更新为 pdf_file 的正确 url 时 Google 云,该值未保存在数据库中。 日志表明它已保存,如您在行 SQL (0.3ms) UPDATE "uploads" SET "file" = 'https://pdf-uploads.storage.googleapis.com/uploads/2/Selection_002.png' WHERE "uploads"."id" = ? [["id", 2]] 中所见。当我尝试在我的视图中检索 link 以显示它时,文件列似乎是空的。

Web 服务器日志

 begin transaction
   SQL (0.3ms)  INSERT INTO "uploads" ("songname", "artist", "album", "level", "video", "user_id", "genre_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)  [["songname", "Hello"], ["artist", "Adele"], ["album", "Hello - Single"], ["level", 1], ["video", ""], ["user_id", 1], ["genre_id", 5], ["created_at", "2015-12-25 05:19:42.601108"], ["updated_at", "2015-12-25 05:19:42.601108"]]
   SQL (0.3ms)  UPDATE "uploads" SET "file" = 'https://pdf-uploads.storage.googleapis.com/uploads/2/Selection_002.png' WHERE "uploads"."id" = ?  [["id", 2]]
   (3.6ms)  commit transaction

upload.rb 模型文件

attr_accessor :file

private

after_create :upload_file, if: :file

def upload_file
  file_object = StorageBucket.files.new(
      key: "uploads/#{id}/#{file.original_filename}",
      body: file.read,
      public: true
  )

  file_object.save

# this is what is causing the problem
  update_columns file: file_object.public_url

end

uploads_controller.rb

def create
@upload = current_user.uploads.build(upload_params)
if params[:genre_id].blank?
    @upload.genre = Genre.find_by_name('Uncategorized')
else
    @upload.genre = Genre.find_by_id(params[:genre_id])
end
if @upload.level.blank?
    @upload.level = 3
end

  respond_to do |format|
    if @upload.save
      format.html { redirect_to @upload, notice: 'Upload was successfully created.' }
      format.json { render :show, status: :created, location: @upload }
    else
      format.html { render :new }
      format.json { render json: @upload.errors, status: :unprocessable_entity }
    end
  end
end

从 rails 控制台检查新条目

Upload.last
Upload Load (0.6ms)  SELECT  "uploads".* FROM "uploads"  ORDER BY "uploads"."id" DESC LIMIT 1
=> #<Upload id: 2, songname: "Hello", artist: "Adele", album: "Hello - Single", level: 1, video: "", file: "https://pdf-uploads.storage.googleapis.com/uploads...", downloads: 0, views: 2, user_id: 1, genre_id: 5, created_at: "2015-12-25 05:19:42", updated_at: "2015-12-25 05:20:07">

如您所见,它在文件列中插入了一个值(由于某种原因被截断了……不确定这是否只是为了保持输出简短,或者截断的值是否实际存储在数据库中。 file: "https://pdf-uploads.storage.googleapis.com/uploads..." 现在,这就是问题的开始。 在我看来,我有这行代码 Upload URL: <%= @upload.file.to_s %> 来打印数据库文件列,但它什么也不打印(比如文件属性为空)。就像我解释的那样,我检查过该列绝对不是空白

我使用 table_print gem 从 rails 控制台打印数据库 table,它显示文件列为空白列(同样,没有知道为什么会那样做。Rails 记录打印机显示 截断的 url 存储在数据库中)

同样,我昨晚花了好几个小时弄明白了,但我自己弄不明白。预先感谢您的帮助。

attr_accessor 给你制造麻烦。

你为什么要用它?您的字段已经在数据库中。

如果 rails3 使用 attr_accessible rails4 strong_params.

编辑:

移除attr_accessor :file

在您的 uploads_controller 中,将 file 字段添加到 upload_params 方法。

确保您允许所有相关的上传参数,包括 :file

# app/controllers/uploads_controller.rb
class UploadsController < ApplicationController
  def create
    ...
  end

  private

  def upload_params
    params.require(:some_required_param).permit(:genre_id, :file)
  end
end

然后确保你的表单上有 :multipart => true

# some_view.html.erb
<%= form_tag({:action => "create"}, :method => :post, :multipart => true do %>

处的注释是由于变量 'file' 是一个字符串。如果你要 file.is_a? String Ruby 会证实这一点。我假设文件是​​ URL:

=> #<Upload id: 2, songname: "Hello", 
   artist: "Adele", album: "Hello - Single",
   level: 1, video: "", 
   file: "https://pdf-uploads.storage.googleapis.com/uploads...", 
   downloads: 0, views: 2, user_id: 1, genre_id: 5, 
   created_at: "2015-12-25 05:19:42", updated_at: "2015-12-25 05:20:07">

新的错误是因为String中没有方法original_filename。 attr_accessor 文件覆盖模型中的行为以允许将对象作为文件传递,该文件使用参数中传递的文件对象的实例更新列文件。

删除 attr_accessor 将允许从数据库中检索字符串(因此您可以 <%= @upload.file.to_s %>)。然而,如果你有 attr_accesor 在那里,你的空实例变量 returns。

那么当你覆盖 getter 时,你如何获得在视图上显示的路径?

  1. 重命名 attr_accessor file
  2. attr_accessor 更改为 attr_writter 以通过在参数中传递临时文件但返回字符串来维护更新文件
  3. attributes[:file]
  4. 的 getter 创建一个实例方法

我认为第 2 种方法最简单,但可能会对下游产生一些严重的影响。实施#3 看起来像:

# app/models/upload.rb
  def file_path
    attributes['file']
  end

# app/views/uploads/index.html.erb
  <%= @upload.file_path %>