如何从现有Rails资源中选择字段,而不是从数据库中选择?

时间:2015-06-05 12:34:14

标签: ruby-on-rails

我有一个现有的模型对象,我想"瘦下来"只是几个领域。用例包括从一个服务接收一个项目,然后将其传递给另一个服务,或者在测试中使用fixture。

以下适用于数据库查询:

User.select([:firstname,:lastname]).first

仅使用firstnamelastname获取记录。如果我已经u = User.first,那么我现在u所有字段。

如何将u转换为仅包含上述两个字段的对象,而不会进行另一个低效的数据库查询?

u.select([:firstname,:lastname])

不起作用。

澄清一下:如果我已经拥有User.select(:firstname,:lastname).first的输出(后SQL),我希望得到等效的User.first。我的下一步是什么?

2 个答案:

答案 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类的一部分。

http://api.rubyonrails.org/classes/Hash.html#method-i-slice

答案 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)