我想将虚拟列添加到某些模型中,但希望通过诸如Product.first
之类的ActiveRecord语句返回它们的值,以便可以使用Product.first.to_json
之类的语句来输出产品,虚拟列,应API请求。
列的值取决于其他模型属性。我不希望这些列保留到数据库中。
我尝试过:
class Product < ApplicationRecord
def total
price + tax
end
end
但是Product.first
不包括总数。
class Product < ApplicationRecord
attribute :total, :decimal, default: -> { 0.0 }
end
向返回的对象添加total: 0.0
,但是
class Product < ApplicationRecord
attribute :total, :decimal, default: -> { price + tax }
end
出现诸如
之类的消息失败#<NameError: undefined local variable or method `price' for #<Class:0x0000557b51c2c960>>
和
class Product < ApplicationRecord
attribute :total, :decimal, default: -> { 0.0 }
def total
price + tax
end
end
仍然返回total: 0.0
。
我什至不确定attribute
是否是执行此操作的正确方法,因为文档似乎暗示它已绑定到列。
总结:
products
表中不应包含total
列。Product
应该返回一个Product
对象,该对象包括一个total
键,该键具有基于模型的其他属性的计算值。这有可能吗?
我真的不想用大量手动插入这些虚拟列的代码替换每个to_json
调用...
答案 0 :(得分:2)
您可以使用methods
选项
class Product < ApplicationRecord
def total
price + tax
end
end
Product.first.to_json(methods: :total)
答案 1 :(得分:1)
在模型中覆盖as_json
以包含您的方法。
这不会在您检索到的Product对象中包含total,但是在对该对象调用.to_json
时会包含total。
class Product < ApplicationRecord
attribute :total, :decimal, default: -> { 0.0 }
def total
price + tax
end
def as_json(options = {})
super(methods: [:total])
end
end
答案 2 :(得分:0)
数据库中的virtual/generated column(假设MySQL / MariaDB)可以解决您的需求。由于它是从其他列的数据生成的,因此您无法对其进行写入,并且只能在读取操作期间对其进行更新。可以选择保留数据,但这不是这里的问题。
在我的示例中,我想向People数据库中添加一个虚拟列“ age”,该列是person.birthday和curdate()之间的区别。 我生成列:
rails generate migration AddAgeToPeople age:virtual
然后我编辑迁移文件,以使add_column :people, :age, :virtual
变为
class AddAgeToPeople < ActiveRecord::Migration[5.2]
def change
add_column :people, :age, :int, as: "timestampdiff(year, birthday, curdate())"
end
end
最终结果将是如下所示的SQL:
ALTER TABLE people ADD COLUMN age GENERATED ALWAYS AS (timestampdiff(year, birthday, curdate()));
| Field | Type | Null | Key | Default | Extra |
| age | int(11) | YES | | NULL | VIRTUAL GENERATED |
最终结果是模型中可以正常交互的属性(尽管只读)