Ошибка при сохранении с использованием активных записей

Я пытаюсь сохранить записи, используя .rake файл. Но я получаю сообщение об ошибке при попытке сохранить изменения.

сообщение об ошибке

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

2 ответа

Решение

Это проблемная строка:

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)

Эта линия является проблемой

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
Другие вопросы по тегам