【发布时间】:2015-06-24 16:26:32
【问题描述】:
问题
是否有内置 API、第 3 方 Gem 或通用范式用于在 Rails 应用程序中对数据库进行数据转换?
注意:我不是在寻找助手、视图模型或标准的 before/after ActiveRecord 挂钩。我需要能够在通常的钩子“下方”默默地改变数据,以便该机制对应用程序的其余部分来说是解耦/隐藏/未知的。
换句话说,我希望在 ActiveRecord 中的正常钩子下方的某处插入一个垫片,并在每个属性的数据库适配器上方的某处插入一个垫片,这将允许我透明地处理数据,例如用于数据库适配器。
简单的例子
$ rails new test-app
$ cd test-app
$ bundle install
$ bundle exec rails g scaffold vehicle make model year:integer color
$ bundle exec rake db:migrate
在app/models/vehicle.rb 中,类似:
class Vehicle < ActiveRecord::Base
magic_shim :color, in: :color_upcase, out: :color_downcase
private
# Returns a modified value for storage but does not change the
# attribute value in the ActiveRecord object.
def color_upcase
self.color.upcase
end
# Accepts the stored value and returns an inversely modified version
# to be used by the ActiveRecord attribute.
def color_downcase(stored)
stored.downcase
end
end
在 Rails 控制台中(注意“Red”的大写):
irb> truck = Vehicle.create make: "Ford", model: "F150", year: 2015, color: "Red"
在 rails 数据库中(颜色在存储前被大写):
sqlite> SELECT * FROM `vehicles`;
1|Ford|F150|2015|RED|2015-06-24 16:07:33.176769|2015-06-24 16:07:33.176769
然后回到控制台(应用程序看到一个降级版本):
irb> truck = Vehicle.find 1
irb> truck.color
=> red
【问题讨论】:
-
覆盖默认访问器有什么问题? (api.rubyonrails.org/classes/ActiveRecord/…)
-
只是转换可能相对复杂,因此必须在每次访问属性时执行,而不仅仅是查询。我想我可以追求默认访问器覆盖并使用某种缓存,但我会担心意外的边缘情况(想想脏检查等)。
-
...但既然您已经让我深入思考了这一点,我想它只需要在属性更改时进行转换,这不是什么大问题。
-
@dimuch 发表答案,我会接受;你帮我解释了为什么访问器覆盖 是 正确的解决方案。
标签: ruby-on-rails database activerecord hook transform