带有Neo4j的Carrierwave没有将图像关联保存到数据库

时间:2015-11-19 15:58:42

标签: ruby-on-rails amazon-s3 neo4j carrierwave

使用neo4j的Rails 4应用程序和使用neo4j.rb gemcarrierwave-neo4j将图像附加到Report对象。

2.0.0-p353 :001 > r = Report.find_by(name: 'my new report')
 => #<Report avatar: #<AvatarUploader:0x0000000643d950 @model=#<Report avatar: #<AvatarUploader:0x0000000643d950 ...>, created_at: Thu, 19 Nov 2015 14:25:58 +0000, created_by: nil, description: nil, embedJSON: nil, gridsize: nil, name: "my new report", tableau_link: nil, thumbnail_uri: nil, timestamp: nil, type: nil, updated_at: Thu, 19 Nov 2015 15:01:18 +0000, updated_by: nil>, @mounted_as=:avatar>, created_at: Thu, 19 Nov 2015 14:25:58 +0000, created_by: nil, description: nil, embedJSON: nil, gridsize: nil, name: "my new report", tableau_link: nil, thumbnail_uri: nil, timestamp: nil, type: nil, updated_at: Thu, 19 Nov 2015 15:01:18 +0000, updated_by: nil>
2.0.0-p353 :002 > File.open('app/assets/images/nd-gray.png') { |f| r.avatar = f }
 => #<File:app/assets/images/nd-gray.png (closed)>
2.0.0-p353 :003 > r.avatar.url
 => "/vagrant/fenrir/tmp/uploads/1447945541-17455-0224/nd-gray.png"
2.0.0-p353 :004 > r.save
 => true
2.0.0-p353 :005 > r.avatar.url
 => "/uploads/development/Report/nd-gray.png"

此时一切正常。但是当我尝试重新加载Report对象时,关联就像它从未发生过一样。

2.0.0-p353 :006 > r = Report.find_by(name: 'my new report')
 => #<Report avatar: #<AvatarUploader:0x00000004205108 @model=#<Report avatar: #<AvatarUploader:0x00000004205108 ...>, created_at: Thu, 19 Nov 2015 14:25:58 +0000, created_by: nil, description: nil, embedJSON: nil, gridsize: nil, name: "my new report", tableau_link: nil, thumbnail_uri: nil, timestamp: nil, type: nil, updated_at: Thu, 19 Nov 2015 15:05:53 +0000, updated_by: nil>, @mounted_as=:avatar>, created_at: Thu, 19 Nov 2015 14:25:58 +0000, created_by: nil, description: nil, embedJSON: nil, gridsize: nil, name: "my new report", tableau_link: nil, thumbnail_uri: nil, timestamp: nil, type: nil, updated_at: Thu, 19 Nov 2015 15:05:53 +0000, updated_by: nil>
2.0.0-p353 :007 > r.avatar.url
 => nil
2.0.0-p353 :007 > r.avatar.path
 => nil

切换到:aws upload而不是:file可以正常上传,但同样缺少关联。

这是我的carrierwave类对象。

#app/uploaders/avatar_uploader.rb
class AvatarUploader < CarrierWave::Uploader::Base
  # Choose what kind of storage to use for this uploader:
  storage :file

  # Override the directory where uploaded files will be stored.
  def store_dir
    "uploads/#{Rails.env}/#{model.class}/"
  end

  # Add a white list of extensions which are allowed to be uploaded.
  def extension_white_list
    %w(jpg jpeg gif png)
  end
end

载波初始化器

#config/initializers/carrierwave.rb
CarrierWave.configure do |config|
  config.storage    = :file
  config.aws_bucket = ENV['S3_BUCKET_NAME']
  config.aws_acl  = 'private'

  config.aws_credentials = {
    access_key_id:     ENV['S3_KEY'],
    secret_access_key: ENV['S3_SECRET'],
    region:            ENV['S3_REGION'] # Required
  }

  # The maximum period for authenticated_urls is only 10 minutes.
  # config.aws_authenticated_url_expiration = 60 * 60 * 24 * 7

  # # Set custom options such as cache control to leverage browser caching
  # config.aws_attributes = {
  #   expires: 7.days.from_now.httpdate,
  #   cache_control: 'max-age=60480'
  # }

  config.cache_dir = "#{Rails.root}/tmp/uploads/" # To let CarrierWave work on heroku

  # config.fog_directory    = ENV['S3_BUCKET_NAME']
  #config.s3_access_policy = :public_read   # Generate http:// urls. Defaults to :authenticated_read (https://)
  #config.fog_host         = "#{ENV['S3_ASSET_URL']}/#{ENV['S3_BUCKET_NAME']}"
end

最后,报告模型本身

#app/models/report.rb
class Report
  include Neo4j::ActiveNode
  searchkick word_start: [:name], autocomplete: [:name]
  validates_presence_of :name
  validates_uniqueness_of :name, case_sensitive: false

  property :avatar, type: String
  mount_uploader :avatar, AvatarUploader

  def search_data
    {
      name: name,
      description: description
    }
  end

  property              :name
  property              :description
  property              :tableau_link
  property              :type
  property              :thumbnail_uri
  property              :gridsize
  property              :timestamp
  property              :embedJSON
  property              :created_at
  property              :updated_at
  property              :created_by
  property              :updated_by
  has_many :in,         :terms
  has_one  :in,         :office

  def selectable_terms
    @selectable_terms = []
    self.terms.each do |t|
      @selectable_terms << { id: t.id, text: t.name }
    end
    @selectable_terms.to_json
  end

  def update_terms(param_terms)
    param_terms ||= []
    term_instances = []
    param_terms.each do |t|
      term_instances << Term.find_by(name: t)
    end
    term_instances
  end
  def aggro_extro
    embedJSON.present? ? JSON.parse(embedJSON) : Hash.new
  end
end

我能想到的一个原因是我们使用:name字段作为我们的唯一标识符。也许carrierwave正在寻找UUID?

另一种可能性是载波正在缓存关联。

2 个答案:

答案 0 :(得分:2)

我只是尝试过它似乎有效。我猜测你正在使用neo4j / neo4j-core宝石的旧版本,因为当我尝试使用你的模型时,它指出你还没有指定一个type选项。从版本5.0.0开始,这是必需的。您是否可以更新到5.2.0系列,看看是否能解决问题?另请注意,6.0.0很快就会推出(候选版本已经发布)。

我要提到的其他一些事情是您应该为模型中的name属性指定索引。这应该有助于查询名称。由于您正在执行validates_uniqueness_of,您甚至可能希望指定约束。约束不会以不区分大小写的方式确保值是唯一的,但它会在数据库级别为您做一些唯一性约束。您仍然希望validates_uniqueness_ofcase_sensitive: false。请参阅以下文档:

http://neo4jrb.readthedocs.org/en/5.2.x/ActiveNode.html#indexes http://neo4jrb.readthedocs.org/en/5.2.x/ActiveNode.html#constraints

另请注意,约束会自动创建索引,因此您不需要同时指定两者(事实上在6.0.0中我们不允许您再这样做)。

答案 1 :(得分:1)

我最终取消了Carrierwave并继续Paperclip。我们用回形针使用的宝石如下所示,其他任何人都无法使用neo4j.rb进行图片上传。回形针的连接器宝石是neo4j.rb团队的paperclip-fork

gem 'rails', '4.0.2'

gem 'neo4j', '~> 4.1.1'

gem 'neo4jrb-paperclip', github: 'subvertallchris/neo4jrb-paperclip', require: 'neo4jrb_paperclip'
gem 'aws-sdk-v1'

新的报告模型 -

class Report
  include Neo4j::ActiveNode
  include Neo4jrb::Paperclip

  has_neo4jrb_attached_file :avatar,
                            storage: :s3,
                            s3_permissions: :private,
                            default_url: '/assets/images/reports-icon-white.svg',
                            s3_credentials:
                              Proc.new { |a| a.instance.s3_credentials }
  validates_attachment_content_type :avatar, 
                                    content_type: ['image/jpg',
                                                   'image/jpeg',
                                                   'image/png',
                                                   'image/gif']
  # Rather than rename our variables in our secrets file, just rename them here
  def s3_credentials
    {
      bucket: ENV['S3_BUCKET_NAME'],
      access_key_id: ENV['S3_KEY'],
      secret_access_key: ENV['S3_SECRET']
    }
  end