Sch*_*els 2 activerecord callback ruby-on-rails-3.1
我有一个包含几个表的数据库模型,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
在应用程序中,数据(大部分)用作单独的值; 列中的不同值很重要:
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
Run Code Online (Sandbox Code Playgroud)
这个设计带来了一些问题:我不能只是"插入",更新"和"删除" value_2psuedo表的某些值,因为这可能会影响其他列中的值:如果我删除value_215-01-2012,删除整个记录将修改both value_2和value_3psuedo-table.
这个问题的明显解决方案(对我而言)是使用回调来使用回调增强使用正确行为创建,更新和销毁操作around_.我为这些回调创建了一个类:
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
Run Code Online (Sandbox Code Playgroud)
使用此方法,我的控制器可以非常干净,因为业务逻辑对此数据库模型一无所知.我的模型也可以是干净的,因为回调可以在多个模型上使用.控制器:
class SomeController < ApplicationController
def destroy
@some_model = SomeModel.find(params[:id])
@some_model.destroy
logger.debug "destroyed!"
# respond to the end user
...
end
end
Run Code Online (Sandbox Code Playgroud)
不幸的是,事务在around_destroy回调之后回滚,如日志中所示:
... some successful sql update queries
end of destroy callback
(0.2ms) ROLLBACK
destroyed!
Run Code Online (Sandbox Code Playgroud)
我试图清空around_destroy回调,但这会导致相同的行为:在around_destroy回调之后的某个地方触发回滚.
为什么会触发此回滚,如何解决此问题?
我真的想用回调来解决这个设计问题:如果我不需要在我的所有模型/控制器中构建更新 - 而不是破坏,它将节省大量工作.我怎么解决这个问题?
我终于想通了.我会留下另一个答案,因为它也可以,但不能直接回答你的问题.
您必须在around_destroy方法中生成,并且如果您不想删除记录,还必须将模型的销毁行为更改为不调用delete.
有两种方法可以使用around_destroy:
(1)使用课程:
class TemporalCallbacks
def self.around_destroy(model)
puts "TemporalCallbacks::around_destroy"
yield model
end
end
class SomeModel
around_destroy TemporalCallbacks
end
Run Code Online (Sandbox Code Playgroud)
(2)在模型中使用本地方法
class SomeModel
around_destroy :do_something
def do_something
puts "do_something"
yield
end
end
Run Code Online (Sandbox Code Playgroud)
使用任一解决方案,如果您不想删除记录,还需要更改模型中的destroy方法:
class SomeModel
def destroy
_run_destroy_callbacks { puts "do nothing" }
end
Run Code Online (Sandbox Code Playgroud)
通常毁灭这样做:
def destroy
_run_destroy_callbacks { delete }
end
Run Code Online (Sandbox Code Playgroud)