【问题标题】:Faking a Database record for Active Record methods为 Active Record 方法伪造数据库记录
【发布时间】:2016-08-18 12:53:20
【问题描述】:

我在关联上使用 find_by:

“sub”与“main”是多对一的关系

@main.subs.find_by(x: 123)

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

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 时,它看起来就像我从数据库查询中获得的活动记录关系,但如果我执行 find_by/all 之类的操作,它会尝试访问数据库,看看那里什么都没有,然后返回一个空关系。

有什么方法可以阻止 find_by(或任何活动记录方法)访问数据库并只处理我为它创建的存根关系?

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    我认为您的问题存在一些误解。首先,find_by 方法不会返回所有匹配记录,而只返回first one,您可能想改用where 方法。

    其次,has_many 关联上的&lt;&lt; 运算符实际上是saves the association record,所以where 查询应该在分配关联后完美返回它,即在调用&lt;&lt; 之后。

    更新:如果主对象在数据库中也不存在,那么&lt;&lt; 操作符确实不会保存任何东西。在这种情况下,我想到的唯一解决方案是放弃 ActiveRecord 方法(例如find_bywhere),因为它们总是尝试查询数据库以获取信息并手动搜索匹配的关联记录而是。

    所以你可以代替@main.subs.where(x: 123)

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

    这样,您将首先加载所有附加的关联,包括新附加的和未保存的关联,然后使用 ruby​​ 条件针对它们的属性过滤它们。

    但是,这样做的最大缺点是,当将此代码与 已保存 记录一起使用时,您将始终加载 其所有关联记录,而不仅仅是那些符合条件的记录.因此,如果您有一个包含大量关联记录的记录,那么您将扼杀这种过滤的性能。

    【讨论】:

    • 根据您提供的链接更新了问题。从我所看到的情况来看,如果 main 也是数据库中的记录,那么 subs 将被保存,但在我的情况下,它不是。 /跨度>
    • 好的,更新了答案。另外,还有一个问题:这应该用于测试吗?
    • 不,我希望.. 然后我也可以存根 find_by 并完成它。我只需要调节 find_by 并仅在我不应该使用存根时运行它,因为大多数时候它应该从数据库中检索记录而不是不检索记录,而是使用一种硬编码记录.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    • 2013-02-25
    • 1970-01-01
    相关资源
    最近更新 更多