ruby-on-rails - 为什么在活动记录模型中包含模块会导致模型被重新定义为普通的 ruby 类?
问题描述
我有一个 Active Record 模型(列表),它应该将一些属性存储在数据库中,而其他一些属性将存储在区块链(以太坊)中。
理想情况下,当开发人员这样做时model_record.save
,应该重写活动记录保存方法,首先将适当的属性保存在区块链中,然后再进行正常的活动记录保存。此过程适用于大多数其他方法,例如.update
, .destroy
, .create
。
通过在模型中添加宏级别声明来区分区块链属性和正常的活动记录列,实现了以下功能
class Listing < ApplicationRecord
include BlockchainRecord
self.table_name = "listings"
blockchain_properties :parcel_no,
:description
end
BlockchainRecord
模型中还包含一个模块,包括如下所示的方法
module BlockchainRecord
extend ActiveSupport::Concern
...............
class_methods do
def blockchain_properties(*props)
@@blockchain_attributes = props
define_method :blockchain_attributes do
props
end
props.each do |prop|
define_method prop do
if self.instance_variable_defined?("@#{prop}")
self.instance_variable_get("@#{prop}")
else
if self.address
val = self.contract.call.send("#{prop}")
self.instance_variable_set("@#{prop}", val)
val
else
nil
end
end
end
# Setter methods
define_method "#{prop}=" do |arg|
self.instance_variable_set("@#{prop}", arg)
end
end
end
def new(props = {})
model_record = super(props.except(blockchain_attributes))
blockchainProps = props.slice(*blockchain_attributes)
blockchainProps.each do |k, v|
model_record.send("#{k}=", v)
end
return model_record
end
end
def save
if self.address
blockchain_attributes.each do |prop|
self.contract.transact_and_wait.send("set_#{prop}", self.send("#{prop}"))
sleep(2)
end
super
else
# in case we call Class.new then Object.save
contract = Ethereum::Contract.create(file: self.class.contract_file_path)
key = Eth::Key.new(priv: ENV["PRIVATE_KEY"])
contract.key = key
self.address = contract.deploy_and_wait(*(self.attributes.slice(*blockchain_attributes).values))
super
end
end
end
当一个人完成保存一个 activerecord 对象,然后尝试类似Model.count
or的东西时,就会出现问题Model.all
。
例如,如果我这样做了,
l = Listing.new(parcel_no: 1234, description: "...", registration_section: "...")
然后保存了记录l.save
,它将正确存储区块链属性(parcel_no 和描述),然后调用.save
ActiveRecord 提供的将其余属性保存到数据库中。
但是,当我进行类似的后续调用Listing.count
时,失败并显示以下错误消息NoMethodError: undefined method count for Listing:Class,并且当我检查Listing
我得到的祖先时,[Listing, ActiveSupport::ToJsonWithActiveSupportEncoder, Object, PP::ObjectMixin, MakeMakefile, ActiveSupport::Dependencies::Loadable, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Tryable, Kernel, BasicObject]
这意味着它不再从活动记录库继承
为什么在模块中覆盖此 activerecord .save 方法会导致Listing
模型不再从 ActiveRecord::Base 继承,如何解决?
解决方案
推荐阅读
- javascript - 防止 TypeScript 公共函数调用私有函数
- visual-studio - 使用 Github Actions 构建多个 Visual Studio 解决方案
- gradle - gradle 7缺少传递依赖
- javascript - 仅在单击两次后才能激活菜单
- flutter - 接受类实例变量名作为参数
- php - 使用 RewriteRule 时参数上不需要的反斜杠
- awk - 如何在具有多行的两个方括号之间进行正则表达式?(grep|awk|python)
- javascript - TestCafe - 由于 my-local-ip 或代理的前缀,无法连接第 3 方 uri
- sql - 加速分区 ROW_NUMBER()
- ios - 使用 CarPlay 框架的 CarPlay 应用在 iOS 13 或更早版本上崩溃