如何为存储在jsonb中的关系编写Rails 5.2关联?
我在一些地方使用PostgreSQL jsonb来灵活地存储与其他模型的关系。例如,我们结合使用STI和jsonb来创建灵活的事件日志。
class Event < ApplicationRecord
include HasJsonbAccessors
end
class Event::AddedUserToGroup < Event
jsonb_belongs_to :user
jsonb_belongs_to :group
end
class Event::UserPurchase < Event
jsonb_belongs_to :user
jsonb_belongs_to :order
end
借助jsonb_accessor
,我们成功地将访问器和验证功能结合在一起。
module HasJsonbAccessors
extend ActiveSupport::Concern
class_methods do
def jsonb_belongs_to(association, optional: false)
association_id_field = "#{association}_id".to_sym
association_class = association.to_s.classify.constantize
jsonb_accessor :data,
association_id_field => :integer
validates association, presence: true unless optional
define_method(association) do
association_class.where(id: self.send(association_id_field)).first
end
define_method("#{association}=".to_sym) do |object|
self.send("#{association_id_field}=".to_sym, object.id)
end
end
end
end
另一个示例是一组灵活的过滤规则,可以潜在地使用任何模型的列表。我已经了解了has_many
关系的基础。
class FilterRules < ApplicationRecord
jsonb_accessor :rules,
group_ids: [:integer, array: true],
other_rule: :string,
...
def groups
return [] if !group_ids
return Group.find(group_ids)
end
def groups=(groups)
self.group_ids = groups.try(:map, &:id)
end
end
但是,如果没有真正的联系,许多工具将无法在这些模型上使用。例如,ActiveAdmin和Formtastic需要一个真正的has_many关联。而且我们没有关系完整性或级联。
我看过activerecord-jsonb-associations,但它深入了Rails的胆量,被5.1-> 5.2超出我修复能力的更改所破坏。
是否有任何开始编写适当的自定义Rails关联的指针?