我是否可以使用字符串插值来构建ActiveRecord查询,如下所示:
query = '.owner.name'
widget = Widget.first
name = "#{Widget" + query + "}"
这显然不起作用,但我正在寻找一个可接受的替代方案。
答案 0 :(得分:4)
query = '.owner.name'
widget = Widget.first
name = eval "widget#{query}"
这不是一个好主意,但确实有效。
Is 'eval' supposed to be nasty?
强大的力量带来了巨大的责任(和风险)。
由于Rails使用哈希将列映射到方法,而这些哈希是“具有无差别访问权限的哈希”,因此您可以使用字符串或符号。 因此:
widget = Widget.first
widget[:owner] # => returns the same as widget.owner
widget['owner'] # => also returns widget.owner.
上面代码的问题是,所有者IS PROBABLY是另一列的外键,所以方法名实际上是:
widget['owner_id']
返回一个整数,Rails用它来查找Owners表中的id。因此,如果您只将在Widget表中返回列的列串起来,则可以使用上面的代码。但是当你将查询方法串在一起时,通常是因为你在数据库中查找某些关系并在其上调用列方法。
因此,您需要执行某种递归循环:
query = 'owner.name'
q = query.split'.'
然后处理导致的结果:
q0 = "#{q[0]}_id"
q1 = "#{q[1]}"
Owner.find(widget[q0])[q1]
#Owner Load (0.6ms) SELECT "owners".* FROM "owners" WHERE "owners"."id" = $1 LIMIT 1 [["id", 9]]
#=> "Joe"
所以理论上你将查询字符串拆分为点,将“_id”添加到除最后一个之外的所有人,然后使用(可能嵌套的).find
命令将它们链接在一起。可以吗?大概。它应该按照我描述的方式完成吗?可能不是。
如果您提供更具描述性的用例场景,那么人们可能会提供更好的答案。从更广泛的角度来看,你真正想做什么?可能还有其他一些方法可以完全否定你要求做的事情。
答案 1 :(得分:0)
这是一个不那么串型的版本。
widget = Widget.first
query = 'owner.name'
name = query.split('.').inject(widget){|sum, meth| sum.send(meth)}
这将应用由传递给inject的对象后面的点分隔的方法。
您甚至可以在模型中将注入调用定义为方法。
但要注意,如果有人注射了一个&class; .delete_all'在您的属性中,您的所有小部件都将被删除(也适用于其他解决方案)
答案 2 :(得分:-1)
虽然你可以使用aval
并获得你想要的东西,但这并不是最好的解决方法。
因此。它是否有条件地附加有效的记录查询,你应该使用merge
作为您案例中的概述(不是最好的例子,但您明白了)
widget = Widget.first
owner = Widget.first.owner
widget_owner = if <some condition>
widget.merge(owner)
end
widget_owner.try(:name)