Ruby:使用字符串插值来访问ActiveRecord属性

时间:2015-07-21 22:01:16

标签: ruby-on-rails ruby activerecord

我是否可以使用字符串插值来构建ActiveRecord查询,如下所示:

query = '.owner.name'
widget = Widget.first
name = "#{Widget" + query + "}"

这显然不起作用,但我正在寻找一个可接受的替代方案。

3 个答案:

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