如何在 ruby on rails 中获取控制器和操作列表?
Posted
技术标签:
【中文标题】如何在 ruby on rails 中获取控制器和操作列表?【英文标题】:How to get list of controllers and actions in ruby on rails? 【发布时间】:2012-01-30 23:14:17 【问题描述】:在rails中,我可以通过controller_name获取当前控制器的名称,通过调用action_name获取当前动作。我正在寻找类似的运行时反射来获取以下内容:
-
应用程序中所有控制器的列表。
给定控制器中所有操作的列表。
例如,我是一个具有“添加”和“编辑”操作的产品控制器。我可以以编程方式提取这些操作的名称以向用户显示支持哪些操作吗?
我查看了一个需要使用ActionController::Routing::Routes.named_routes.routes.each
的方法
但我无法让它发挥作用。使用时出现未初始化常量ActionDispatch::Routing::Routes
错误。
如果有任何好的教程或文档可以帮助我了解 Rails 的反射功能。我搜索了它,但我主要得到了与记录反射相关的活跃博客。我正在寻找可以让我在运行时获取有关控制器和操作/方法的信息的东西。 谢谢,
塔布雷兹
【问题讨论】:
您是在运行时还是在 rake 作业中执行此操作。运行时是一个坏主意。耙工作很容易做到这一点。 您的意思是“rake routes”吗?我在运行时寻找一些东西。我不需要 rake 路由输出的大量信息。我只需要控制器名称,我假设它必须作为集合提供。作为一个 Rails 的菜鸟,我只是不知道在运行时可以在 Rails 中访问哪些上下文对象。 在这里找到了类似的问题,***.com/questions/1564278/… @nkm:我已经检查过这个问题。它在一定程度上相似,但接受的答案与我正在寻找的信息不符。 【参考方案1】:获取控制器类列表的最简单方法是:
ApplicationController.descendants
但是,由于类是延迟加载的,因此您需要在执行此操作之前预先加载所有类。请记住,此方法需要时间,并且会减慢您的启动速度:
Rails.application.eager_load!
要获取控制器中的所有操作,请使用action_methods
PostsController.action_methods
这将返回一个Set
,其中包含控制器中所有“动作”方法的列表(使用 Rails 用来确定方法是否是要路由到的有效动作的相同逻辑)。
【讨论】:
这正是我想要的。非常感谢!是否有任何特定的 Rails 资源/指南/书籍可能有助于理解这些类型的问题?更具体地说,rails 经历的页面生命周期和运行时对象?任何指针都会有很大的帮助,因为我是 Rails 新手。 值得一提的是,通过调用.action_methods
,您只能得到一个类中定义的公共方法(=actions)的列表。由于 Rails 可以在控制器中没有实际方法的情况下渲染模板,因此可能会导致应用程序中的安全漏洞。【参考方案2】:
PostsController.action_methods
将返回PostsController
的所有动作,包括继承,这不是我想要的,我发现PostsController.instance_methods(false)
,它将返回PostsController
的所有实例方法而不包括继承,这正是我想要的。
【讨论】:
.instance_methods(false),这正是我想要的【参考方案3】:我遇到了类似的问题;就我而言,它是用于编写控制器测试。我想对某些控制器的每个操作运行某些基本测试(例如,如果用户未登录,则返回 401)。 action_methods 解决方案的问题在于它会拾取控制器类上的所有方法,即使该方法在 config/routes.rb 中没有对应的路由。
这是我最终做的:
def actions_for_controller(controller_path)
route_defaults = Rails.application.routes.routes.map(&:defaults)
route_defaults = route_defaults.select |x| x[:controller] == controller_path
route_defaults.map |x| x[:action] .uniq
end
因此,如果您想要 PostsController 的操作列表,您会说:
actions_for_controller('posts')
你会得到:
['show', 'create', 'edit', 'destroy'] (or whatever)
如果你想要一个所有控制器的列表,应该这样做:
def controllers_list
route_defaults = Rails.application.routes.routes.map(&:defaults)
files = route_defaults.map |x| "#x[:controller]_controller" .uniq
files -= ['_controller']
files.map |x| x.split('/').map(&:camelize).join('::').constantize
end
【讨论】:
由于某种原因我也需要这个,因为 .intance_methods(false) 仅在应用程序内部工作,但是当我尝试运行 rake swagger:docs 时,我得到的是空数组,你提到的方法效果很好【参考方案4】:我们正在清理未使用的控制器和操作。所以我想创建一个详尽的列表来标记删除。这就是我最终做的事情
ApplicationController.descendants.each do |controller|
puts controller.name
controller.action_methods.each do |action|
puts ' ' + action
end
end
这提供了一个很好的列表,其中包含在控制器名称下缩进的操作。
【讨论】:
这很好!【参考方案5】:TLDR
你在 Rails 控制台上检查这个
all_controllers = Rails.application.routes.routes.map do |route|
route.defaults[:controller]
end.uniq.compact
controllers = all_controllers.reject |x| x =~ /active_storage|rails|action_mailbox|devise|service_worker/
controller_with_actions = controllers.map do |name|
controller = if name.match?('/')
splits = name.split('/')
prefix = splits[0..-2].map(&:capitalize)
suffix = [splits[-1]].map(&:classify)
(prefix + suffix).join('::').pluralize
else
name.classify.pluralize
end
verified_controller = controller.concat('Controller').constantize rescue controller.singularize.concat('Controller').constantize rescue next
[verified_controller.to_s, verified_controller&.public_instance_methods(false)&.to_a] rescue next
end.compact
# [
# ["DashboardController", ["index"]],
# ["UsersController", ["index", "new", "create", "show", "update", "destroy"]]
# ["Api::V1::StaticController", ["index", "new", "create", "show", "update", "destroy"]]
# ]
这已经在 Rails 7.0 和其他较低版本中进行了测试。
因为ApplicationController.descendants
在第 7 版的 rails 中根本不起作用。
或者您可以在我的公共 github gist ControllerActionList 链接上使用我的课程
【讨论】:
以上是关于如何在 ruby on rails 中获取控制器和操作列表?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Ruby on Rails 发出 HTTP 请求?
如何在 AWS OpsWorks 上调试 Ruby On Rails?
如何使用 Ruby on Rails 发出 HTTP 请求?