Как использовать миграцию Rails ActiveRecord для вставки первичного ключа в базу данных MySQL? - PullRequest
2 голосов
/ 08 апреля 2009

Мне нужно создать миграцию AR для таблицы файлов изображений. Изображения проверяются в исходном дереве и должны работать как файлы attachment_fu. В таком случае я создаю для них иерархию в /public/system.

Из-за того, что attachment_fu генерирует ссылки, мне нужно использовать соглашение об именах каталогов для вставки значений первичного ключа. Как мне переопределить автоинкремент в MySQL, а также любую магию Rails, чтобы я мог сделать что-то вроде этого:

image = Image.create(:id => 42, :filename => "foo.jpg")
image.id #=> 42

Ответы [ 6 ]

2 голосов
/ 08 апреля 2009

Yikes, проблема не из приятных. Наименее хитрый способ, который я могу придумать, - это иметь в своей миграции некоторый код, который фактически «загружает» все файлы через attachment-fu, и поэтому позволяет плагину создавать идентификаторы и размещать файлы.

Примерно так:

Dir.glob("/images/to/import/*.{jpg,png,gif}").each do |path|

  # simulate uploading the image
  tempfile = Tempfile.new(path)
  tempfile.set_encoding(Encoding::BINARY) if tempfile.respond_to?(:set_encoding)
  tempfile.binmode
  FileUtils.copy_file(path, tempfile.path)

  # create as you do in the controller - may need other metadata here
  image = Image.create({:uploaded_data => tempfile})
  unless image.save
    logger.info "Failed to save image #{path} in migration: #{image.errors.full_messages}"
  end

  tempfile.close!
end

Может пригодиться анализ тестов attachment-fu.

1 голос
/ 11 июня 2010
image = Image.create(:filename => "foo.jpg") { |r| r.id = 42 }
1 голос
/ 08 апреля 2009

В отличие, скажем, от Sybase, в MySQL, если вы укажете столбец id в списке столбцов оператора вставки, вы можете вставить любое допустимое, неповторяющееся значение в идентификатор. Не нужно делать что-то особенное.

Я подозреваю, что магия рельсов состоит в том, чтобы просто не сообщать рельсам, что идентификатор автоматически увеличивается. Если это единственный способ, которым вы будете вставлять в эту таблицу, тогда не делает идентификатор auto_increment. Просто введите в int ненулевой первичный ключ.

Хотя, честно говоря, это использует ключ в качестве данных, и поэтому меня это беспокоит. Если attachment_fu просто ищет столбец с именем "id", сделайте столбец с именем id, который действительно является данными, и сделайте столбец с именем "actual_id" фактическим синтетическим ключом auto_incremented.

0 голосов
/ 20 апреля 2009

Я согласен с AdminMyServer, хотя считаю, что вы все еще можете выполнить эту задачу непосредственно на объекте:

image = Image.new :filename => "foo.jpg"<br/> image.id = 42<br/> image.save<br/>

Вам также необходимо убедиться, что ваше автоинкрементное идентификатор обновляется в конце процесса, чтобы избежать столкновений в будущем.

newValue = Images.find(:first, :order => 'id DESC').id + 1<br/> execute("ALTER TABLE images AUTO_INCREMENT = #{newValue}")

Надеюсь, это поможет.

0 голосов
/ 09 апреля 2009

Я не совсем уверен, что понимаю, почему вам нужно это сделать, но если вам нужно сделать это только один раз, для миграции, просто используйте execute в миграции, чтобы установить идентификатор (если он не уже взято, что я не могу себе представить, это будет):

выполнить «ВСТАВИТЬ В изображения (идентификатор, имя файла) ЗНАЧЕНИЯ (42, 'foo.jpg')»

0 голосов
/ 08 апреля 2009

Вот мой клуге:

class AddImages < ActiveRecord::Migration
  def self.up
    Image.destroy_all

    execute("ALTER TABLE images AUTO_INCREMENT = 1")

    image = Image.create(:filename => "foo.jpg")
    image.id #=> 1
  end

  def self.down
  end
end
...