2016-01-14 7 views
0

Я занят написанием миграции, которая позволит нам перенести наш ямлер из Syck в Psych и, наконец, обновить наш проект до рубина 2. Эта миграция будет серьезно ресурсоемкой хотя я должен буду использовать chunking.Вычисление при использовании ActiveRecord :: Base.connection.execute

Я написал следующий метод, чтобы подтвердить, что результат переноса, который я планирую использовать, дает ожидаемый результат и может быть выполнен без простоя. Для того, чтобы избежать активной записи выполнения сериализации автоматически мне нужно использовать ActiveRecord::Base.connection.execute

Моего метода, который описывает преобразование следующего

def show_summary(table, column_name) 
    a = ActiveRecord::Base.connection.execute <<-SQL 
    SELECT id, #{column_name} FROM #{table} 
    SQL 
    all_rows = a.to_a; "" 
    problem_rows = all_rows.select do |row| 
    original_string = Syck.dump(Syck.load(row[1])) 
    orginal_object = Syck.load(original_string) 

    new_string = Psych.dump(orginal_object) 
    new_object = Syck.load(new_string) 

    Syck.dump(new_object) != original_string rescue true 
    end 

problem_rows.map do |row| 
    old_string = Syck.dump(Syck.load(row[1])) 
    new_string = Psych.dump(Syck.load(old_string)) rescue "Parse failure" 
    roundtrip_string = begin 
    Syck.dump(Syck.load(new_string)) 
    rescue => e 
    e.message 
    end 

    new_row = {} 
    new_row[:id] = row[0] 
    new_row[:original_encoding] = old_string 
    new_row[:new_encoding] = roundtrip_string 
    new_row 
    end 
end 

Как вы можете использовать пакетный при использовании ActiveRecord::Base.connection.execute?

Для полноты моя функция обновления заключается в следующем

# Migrate the given serialized YAML column from Syck to Psych 
    # (if any). 
    def migrate_to_psych(table, column) 
    table_name = ActiveRecord::Base.connection.quote_table_name(table) 

    column_name = ActiveRecord::Base.connection.quote_column_name(column) 

    fetch_data(table_name, column_name).each do |row| 
     transformed = ::Psych.dump(convert(Syck.load(row[column]))) 

     ActiveRecord::Base.connection.execute <<-SQL 
     UPDATE #{table_name} 
     SET #{column_name} = #{ActiveRecord::Base.connection.quote(transformed)} 
     WHERE id = #{row['id']}; 
     SQL 
    end 
    end 

    def fetch_data(table_name, column_name) 
    ActiveRecord::Base.connection.select_all <<-SQL 
     SELECT id, #{column_name} 
     FROM #{table_name} 
     WHERE #{column_name} LIKE '---%' 
    SQL 
    end 

который я получил от http://fossies.org/linux/openproject/db/migrate/migration_utils/legacy_yamler.rb

ответ

3

Вы можете легко создать что-то с LIMIT и OFFSET статей SQL,:

def fetch_data(table_name, column_name) 
    batch_size, offset = 1000, 0 
    begin 
    batch = ActiveRecord::Base.connection.select_all <<-SQL 
     SELECT id, #{column_name} 
     FROM #{table_name} 
     WHERE #{column_name} LIKE '---%' 
     LIMIT #{batch_size} 
     OFFSET #{offset} 
    SQL 
    batch.each do |row| 
     yield row 
    end 
    offset += batch_size 
    end until batch.empty? 
end 

, которые вы можете используйте почти то же самое, что и раньше, только без .each:

fetch_data(table_name, column_name) do |row| ... end 

HTH!

+1

Кстати, я всегда стараюсь избегать использования моделей ActiveRecord при миграции. Просто потому, что исходный код модели может быть изменен, но моя миграция еще может быть использована через год, чтобы настроить тестовые базы данных. – Raffael

+0

Спасибо за ваш ответ! Это действительно полезно! У меня была боль в начале этого года в моем проекте с изменением моделей, а затем с миграциями данных, в которых произошла авария с активной записью. –

+0

Это работает хорошо, только одна заметка [не использовать begin; конец до синтаксиса] (https://stackoverflow.com/questions/136793/is-there-a-do-while-loop-in-ruby) – fguillen

 Смежные вопросы

  • Нет связанных вопросов^_^