需求是这样的:Rails 需要访问另外的数据库来查询资料,为了保证安全,希望可以设置数据库只读,但是同时在一些特殊情况下要可以更新部分数据。
连接数据库的用户可以设置成只读用户,但是这样不能在有需要的时候写入数据了。数据库 Adapter 也没有设置成只读的功能。
有一个思路,就是 hack adapter,设置只能够发送 select 语句,其他的都过滤报错,只有在手动开启开关的时候才可以发送其他语句。
不知道大家怎么看?
这个是否可以考虑用数据库的 master slave 来做呢?不知道 activerecord 有没有类似的扩展。 https://github.com/tchandy/octopus https://github.com/bdurand/seamless_database_pool 这两个 gem 应该都可以实现
ActvieRecord 里可以把 model 设置成 readonly 的,参考代码:
# Make model readonly
module ModelReadonly
extend ActiveSupport::Concern
included do
before_destroy :can_not_destroy
end
def readonly?
true
end
def can_not_destroy
raise ActiveRecord::ReadOnlyRecord, 'data is readonly.'
end
end
class MyModel < ActiveRecord::Base
include ModelReadonly
end
需要 打开写的时候,建立一个新的 model,写操作用这个新 WriteModel
class WriteModel < MyModel
self.table_name = "my_models"
def readonly?
false
end
def can_not_destroy
end
end
上面的方法不够好,用来设置 readonly 没有问题,但是想临时禁用 readonly,可以用下面的方法,直接上代码吧。
module ModelReadonly
extend ActiveSupport::Concern
included do
enable_readonly
before_destroy :can_not_destroy
end
def readonly?
self.class.model_readonly?
end
def can_not_destroy
if self.class.model_readonly?
raise ActiveRecord::ReadOnlyRecord, 'data is readonly.'
end
end
module ClassMethods
def enable_readonly
@readonly = true
end
def disable_readonly
@readonly = false
end
def model_readonly?
@readonly
end
def without_readonly
old_value = @readonly
@readonly = false
begin
yield
ensure
@readonly = old_value
end
end
end
end
class MyModel < ActiveRecord::Base
include ModelReadonly
end
MyModel.without_readonly do
# do something writing my_models table
end
cookpad 自己开发了switch_point
插件来做读写分离 https://github.com/eagletmt/switch_point