2012-01-18 2 views
2

У меня есть модель базы данных с несколькими таблицами, которые выглядят так:Использование around_destroy сделать обновление вместо того, чтобы удалить в базе данных в Rails 3

date  value_1 value_2 value_3 
---------------------------------- 
-infinity 5  6  7 
12-01-2012 4  6  7 
15-01-2012 4  7  8 
16-01-2012 7  7  8 

В приложении данные (в основном), используемые в качестве отдельных значений; отчетливые значения в столбцах имеют важное значение:

date  value_1 date  value_2 date  value_3 
------------------ ------------------ ------------------ 
-infinity 5  -infinity 6  -infinity 7 
12-01-2012 4  15-01-2012 7  15-01-2012 8 
16-01-2012 7  

Эта конструкция приносит некоторые проблемы: я не могу просто «вставить„обновление“и„удалить“какое-то значение для value_2 псевдо-таблицы, так как это может повлиять на значения в других столбцах: если я удалить value_2 для 15.01.2012, удаляя все записи будет изменять как value_2 и value_3 псевдо стол

очевидное решение этой проблемы (для меня) является использование обратных вызовов. чтобы улучшить действия по созданию, обновлению и уничтожению с правильным поведением, используя обратные вызовы around_.Я создал класс для этих callbac кс:

class TemporalCallbacks 
    def self.around_destroy(record) 
     # modify the record: replace it with the values from the previous entry 
     ... 
     # do an update instead of the destroy 
     record.save 
     record.logger.debug "end of destroy callback" 
    end 

    def self.around_update(record) 
     ... 
    end 
end 

class SomeModel < ActiveRecord::Base 

    ... 

    around_update TemporalCallbacks 
    around_destroy TemporalCallbacks 

    ... 

end 

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

class SomeController < ApplicationController 
    def destroy 
    @some_model = SomeModel.find(params[:id]) 
    @some_model.destroy 
    logger.debug "destroyed!" 

    # respond to the end user 
    ... 
    end 

end 

К сожалению, откат транзакции после around_destroy обратного вызова, как показано в журналах:

... some successful sql update queries 
end of destroy callback 
    (0.2ms) ROLLBACK 
destroyed! 

Я пытался опустошить around_destroy обратного вызова, но это приводит к такое же поведение: срабатывает откат, где-то после обратного вызова around_destroy.

Почему этот откат срабатывает и как я могу это исправить?

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

ответ

6

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

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

Есть 2 способа использования around_destroy:

(1) Используйте класс:

class TemporalCallbacks 
    def self.around_destroy(model) 
    puts "TemporalCallbacks::around_destroy" 
    yield model 
    end 
end 

class SomeModel 
    around_destroy TemporalCallbacks 
end 

(2) Используйте локальный метод в модели

class SomeModel 
    around_destroy :do_something 

    def do_something 
    puts "do_something" 
    yield 
    end 
end 

С либо раствором вам также необходимо изменить метод уничтожения в модели, если вы не хотите удалять запись:

class SomeModel 
    def destroy 
    _run_destroy_callbacks { puts "do nothing" } 
    end 

Обычно уничтожить это делает:

def destroy 
    _run_destroy_callbacks { delete } 
end 
+0

Спасибо , Я закончил с этим решением. – Scharrels

+0

Добро пожаловать. Было здорово понять это. – tee

1

Когда вы добавляете обратный вызов around_destroy к модели, вам нужно уступить, что дает обратные вызовы before_ и after_, а также метод destroy. С before_ и after_ вам не нужно уступать. При добавлении этого к модели:

around_destroy { puts "in around"; yield; puts "out around" } 
before_destroy { puts "before" } 
after_destroy { puts "after" } 

$ model.destroy 
=> before 
=> in around 
=> (actual destroy happens here) 
=> out around 
=> after 

Чтобы изменить фактическое уничтожить/удалить поведение модели, посмотрите на Paranoid, какие архивы записей вместо того, чтобы уничтожить их.

Вы могли бы сделать что-то вроде параноидально делает, чтобы изменить уничтожить & УДАЛИТЬ поведения:

def destroy 
    _run_destroy_callbacks { delete } 
end 

def delete  
    self.update_attribute(:deleted_at, Time.now) if !deleted? && persisted? 
    freeze 
end 

Вот еще проще вариант: https://gist.github.com/1474640/3571c53159d3b3ae3506d4e625e7cd8fb5e3f9d6

Кроме того, увидеть этот вопрос: What is the best way to override Rails ActiveRecord destroy behavior?

+0

Есть ли у вас какие-либо идеи, почему этот выбор был сделан? Поведение создания и обновления может быть полностью изменено описанным методом, что позволяет мне сделать модели осведомленными о моем несколько странном представлении о данных: around_create полностью изменяет поведение create. Почему разработчики размещают around_destroy после after_destroy и почему у него не наблюдается одинаковое (заменяющее) поведение? – Scharrels

+0

На самом деле вы правы - around_destroy заменяет поведение разрушения. Я уточню свой ответ. – tee

+0

Могу ли я поместить модель в это «разрушенное» состояние, не выполнив уничтожение в базе данных? Если это возможно, это будет решением моей проблемы. – Scharrels