我有一个现有的模型对象,我想"瘦下来"只是几个领域。用例包括从一个服务接收一个项目,然后将其传递给另一个服务,或者在测试中使用fixture。
以下适用于数据库查询:
User.select([:firstname,:lastname]).first
仅使用firstname
和lastname
获取记录。如果我已经u = User.first
,那么我现在u
有所有字段。
如何将u
转换为仅包含上述两个字段的对象,而不会进行另一个低效的数据库查询?
u.select([:firstname,:lastname])
不起作用。
澄清一下:如果我已经拥有User.select(:firstname,:lastname).first
的输出(后SQL),我希望得到等效的User.first
。我的下一步是什么?
答案 0 :(得分:1)
您可以使用attributes hash进行此操作。
user = User.find(187287)
user.attributes.slice("first_name", "last_name")
{
"first_name" => "Jacob",
"last_name" => "Elder"
}
请注意,Hash#slice是Rails添加的方法。它不是Ruby内置Hash类的一部分。
答案 1 :(得分:1)
Active Record pattern(Rails' ActiveRecord的核心)的本质是每个对象对应于数据库中的特定行。虽然不向后:可能有多个对象指向同一行。这在这里造成了一些麻烦。
在RDBMS中,确保两个对象对应同一行的唯一方法是比较对象'主键。如果两个对象中的一个没有主键,则您无法确定它们是否是同一行。
但ActiveRecord做了什么,对吗?
没什么好看的,实际上:
def ==(comparison_object)
super || # If it's one and the same Ruby object, the result is obvious
comparison_object.instance_of?(self.class) && # otherwise if same class
!id.nil? && # and there IS non-nil id
comparison_object.id == id # Then compare their ids
end
因此,如果对象没有id
,那么除了它本身之外,它不等于任何东西。
对于逐字段比较而言,这与您比较属性的哈希没有什么不同。
这有一个缺点,即即使对象是从不同的行构建,但在给定的属性中包含相同的值,条件也会通过。我不认为这是一个问题:在那个特定情况下你知道其中一个比较对象来自哪个(我想是一个装置),所以它的数据是可信的。因此,如果给定对象包含可信对象具有的相同数据,则测试足够可靠。
为此,您可以使用一个对象的整个属性哈希值,并将其与您的夹具切片进行比较:
assert_equal a.attributes, b.attributes.slice(:key1, :key2)