2009-04-08 1 views
2

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

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

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

ответ

2

Хлоп, не приятная проблема есть. Меньше-глупый способ, который я могу придумать, состоит в том, чтобы иметь некоторый код в вашей миграции, который фактически «загружает» все файлы через вложение-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 

Взгляд на привязанности-фу тесты могли бы быть полезными.

+0

Я не делал этого, но я думаю, что это правильный способ сделать это ... пусть код сделает это и не попытается подорвать его. –

1

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

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

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

+0

К сожалению, у меня нет времени для замены attachment_fu. Я согласен с тем, что использование поля первичного ключа для создания пути к файлу немного мало. –

+0

Я думаю, что я бегу против магии Rails, а не магии MySQL. –

0

Вот мой Клюге:

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 
+0

Это похоже на то, что делает первичный ключ по умолчанию ... в чем разница в функциональности? –

+0

Метод create() не использует значение «: id => ##», если оно указано. Хотя я использовал kluge выше, я думаю, что правильный ответ - позволить классу AR работать, как предлагает @Sarah Mei. –

0

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

выполнить "INSERT INTO изображений (ID, имя файла) VALUES (42, 'foo.jpg')"

0

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

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

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

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

Надеется, что это помогает.

1
image = Image.create(:filename => "foo.jpg") { |r| r.id = 42 } 
Смежные вопросы