如何解决RoR:如何在动态确定类的控制器中创建对象?
| 我的应用程序具有STI模型:# file: app/models/metered_service.rb
class MeteredService < ActiveRecord::Base
...
end
# file: app/models/metered_services/pge_residential.rb
class PGEResidential < MeteredService
...
end
# file: app/models/metered_services/sce_residential.rb
class SCEResidential < MeteredService
...
end
和支持STI的架构:
# file: db/schema.rb
create_table \"metered_services\",:force => true do |t|
t.integer \"premise_id\"
t.string \"type\"
end
MeteredService是一个嵌套资源(尽管与该问题并不真正相关):
# file: config/routes.rb
resources :premises do
resources :metered_services
end
因此,这就是问题所在:要创建MeteredService,用户可以在下拉列表中选择其众多子类之一。表单将类名作为字符串返回到params[\'metered_services\'][\'class\']
中的MeteredServicesController#create。现在我们需要创建适当的子类。
我采用的方法行之有效-但我想知道这是否是最好的方法:
def create
@premise = Premise.find(params[:premise_id])
MeteredService.descendants() # see note
class_name = params[\"metered_service\"].delete(\"class\")
@metered_service = Object.const_get(class_name).new(params[:metered_service].merge({:premise_id => @premise.id}))
if @metered_service.save
... standard endgame
end
end
我正在做的是从ѭ5中剥离类名,以便可以使用剩余的参数来创建计量服务。并且将class_name解析为一个类(通过Object.const_get
),因此我可以在其上调用.new方法。
之所以出现“ 7”调用,是因为在开发模式下完成了缓存。它可以工作,但是确实很丑陋-请查看此问题以解释我为什么这样做。
有没有更好/更可靠的方法来做到这一点?
解决方法
正如John Gibb在评论中所说,您的主要问题是安全性。您必须通过批准的白名单过滤类别。
您在评论中给出的解决方案也不是完美的。首先,创建MeteredService的实例,然后只需使用另一个类的名称更改text属性。您正在使用的实例仍然是基类。例如,如果您在降级类上定义一些验证,则可能会导致一些问题。
做这样的事情:
AVAILABLE_CLASSES = {\"PGEResidential\" => PGEResidential,\"SCEResidential\" => SCEResidential } # You may automatize this
def create
#....
class_name = params[\"metered_service\"].delete(\"class\")
if c = AVAILABLE_CLASSES[class_name]
@metered_service = c.new(params[:met...
else
handle_error_somehow
end
...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。