伪造Active Record方法的数据库记录

时间:2016-04-25 08:25:32

标签: ruby-on-rails activerecord

我在关联中使用了find_by:

“sub”与“main”具有多对一的关系

@main.subs.find_by(x: 123)

在大多数情况下,我希望它使用常规选择从数据库中访问和检索与“main”相关的“子”记录:

select subs.* from subs where subs.main_id = 333 and subs.x = 123

但还有另一个场景,我希望它忽略数据库并访问我在“main”下创建的“subs”的存根:

stub_sub = Sub.new(id: 22, x: 123, main_id: 333)
@main.subs << stub_sub

@main也没有保存在数据库中,而是像sub:

一样创建
@main = Main.new(id: 333)

当我在调试时到达find_by行,并尝试访问@main.subs时,它看起来就像我从db查询得到的活动记录关系,但如果我做了像find_by / all这样的事情,它会尝试访问数据库并看到那里没有任何内容并返回空关系。

有没有办法阻止find_by(或任何活动的记录方法)访问数据库,只是处理我为它创建的存根关系?

1 个答案:

答案 0 :(得分:0)

I think there are a few misunderstandings in your question there. Firstly, the find_by method does not return all matching records but just the first one, you probably wanted to use the where method instead.

Secondly, the << operator on a has_many association actually saves the association record so a where query should return it perfectly after assigning the association, i.e. just after calling <<.

Update: If the main object does not yet exist in the database either, then indeed the << operator does not save anything. In that case, the only solution that comes to my mind is to give up ActiveRecord methods (such as find_by or where) because they always try to query the db to get the information and to search for the matching associated record manually instead.

So instead of @main.subs.where(x: 123) you would do:

@main.subs.to_a.select { |sub| sub.x == 123 }

This way, you will load all attached associations first, including the newly attached and unsaved ones and then filter them using a ruby condition against their attributes.

The big disadvantage of this is however that when using this code with a saved record, you will always load all its associated records, not only those which match the condition. Thus, if you had a record with a lot of associated records, you'd be killing the performance of such filtering.