如何在ruby on rails中获得控制器和动作列表



在rails中,我可以通过controller_name获得当前控制器的名称,通过调用action_name获得当前操作。我正在寻找类似的运行时反射获取以下内容:

  1. 应用程序中所有控制器的列表。
  2. 给定控制器中所有动作的列表。

例如,我有一个Product控制器,它有"添加"one_answers"编辑"动作。我能否以编程方式拉出这些操作的名称,以向用户显示支持哪些操作?

我研究了一个调用ActionController::Routing::Routes.named_routes.routes.each的方法但我不能让它工作。当我使用它时,我得到了未初始化的常量ActionDispatch::Routing::Routes错误。

如果有任何好的教程或文档,可以帮助我了解如何rails反射的能力。我搜索了一下,但我得到的大多是活跃的记录反映相关的博客。我正在寻找一些东西,让我在运行时获得控制器和动作/方法的信息。
谢谢你,

Tabrez

获取控制器类列表的最简单方法是:

ApplicationController.descendants

然而,由于类是惰性加载的,因此您需要在执行此操作之前立即加载所有类。请记住,此方法将花费时间,并且会减慢引导速度:

Rails.application.eager_load!

获取控制器中的所有动作,使用action_methods

PostsController.action_methods

这将返回一个Set,其中包含控制器中所有方法的列表,这些方法是"动作"(使用相同的逻辑Rails用于决定方法是否为路由的有效动作)。

PostsController.action_methods将返回PostsController的所有动作,包括继承,这不是我想要的,我发现PostsController.instance_methods(false),这将返回PostsController的所有实例方法,而不包括继承,正是我想要的。

我有一个类似的问题;在我的例子中,它是用于编写控制器测试。我希望对某些控制器的每个操作运行某些基本测试(例如,如果用户未登录,则返回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

我们正在清理未使用的控制器和操作。所以我想创建一个详尽的列表来标记删除。这是我最后做的

ApplicationController.descendants.each do |controller|
  puts controller.name
  controller.action_methods.each do |action|
    puts '  ' + action
  end
end

这提供了一个很好的列表,在控制器名称下缩进操作。

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在rails的第7个版本中根本不起作用。

或者你可以使用use my class on my public github gist ControllerActionList link

相关内容

  • 没有找到相关文章

最新更新