使用活动记录保存时出错

Error when saving using active records

我正在尝试使用 .rake 文件保存记录。但是我在尝试保存更改时遇到错误。

error.message

SQLite3::ConstraintException: UNIQUE constraint failed: versions.id: INSERT INTO "versions" ("app_id", "created_at", "icon_url", "id", "plist_url", "updated_at", "version_number") VALUES (?, ?, ?, ?, ?, ?, ?)

inbox.rake 文件

namespace :inbox do
  desc 'Check inbox for new app builds'
  task process_inbox: :environment do
    # initialize s3 client
    s3 = AWS::S3.new
    bucket = s3.buckets['my-bucket']
    s3_host = 'https://...s3.amazonaws.com/'

    exclude_inbox = bucket.objects.select do |s3_object|
      s3_object.key.exclude? '_inbox'
    end
    #find plist within the inbox
    plist_objects = exclude_inbox.select do |s3_object|
      s3_object.key.include? 'plist'
    end

    for plist_object in plist_objects
      plist = CFPropertyList::List.new(:data => plist_object.read)
      data = CFPropertyList.native_types(plist.value)

      name = data['items'][0]['metadata']['title']
      bundle_version = data['items'][0]['metadata']['bundle-version']
      plist_copy = plist_object.copy_to("#{name}/#{bundle_version}/#{name}.plist")
      kind = data['items'][0]['metadata']['kind']

      plist = CFPropertyList::List.new(:data => plist_copy.read)
      data = CFPropertyList.native_types(plist.value)
      icon_url = data['items'][0]['assets'][1]['url']
      full_url = plist_copy.url_for(:read)

      icon = bucket.objects[icon_url.gsub(s3_host, '')]

      #find app or create a new app based on its name and kind
      app = App.find_or_initialize_by(name: name, app_type: kind)
      #app.save unless app.id
      #find version or create new version base on app_id and bundle_version
      version = Version.find_or_initialize_by(app_id: app.id, id: bundle_version)
      version.plist_url =  full_url.scheme + '://' + full_url.host + full_url.path
      version.icon_url = icon.copy_to("#{name}/#{bundle_version}/#{icon_url.split('/').last.gsub('~','_')}").url_for(:read).to_s
      version.version_number = bundle_version
      version.app = app
      #update app version number
      app.version_number = version.version_number
      #save changes
      begin
        app.save
        version.save
        puts app.attributes , version.attributes
      rescue => error
        puts error.message
      end
    end

  end
end

这一行就是问题所在

Version.find_or_initialize_by(app_id: app.id, id: bundle_version)

我猜 id 是这里的主键。由于您正在对两个值执行 find_or_initialize,因此当数据库中存在给定 bundle_version 但不同 app_id

的版本时,您将获得一个新版本

你可能应该这样做,

version = Version.find_or_initialize_by(id: bundle_version)
version.app_id = app.id

这是有问题的行:

version = Version.find_or_initialize_by(app_id: app.id, id: bundle_version)

这更冗长,但可能更符合您的要求:

version = Version.find_by(id: bundle_version, app_id: app.id) || Version.new(app_id: app.id)