如何获取 ruby​​ on Rails 中的控制器和操作列表?

发布于 2024-12-23 08:19:39 字数 514 浏览 1 评论 0原文

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

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

例如,我有一个具有“添加”和“编辑”操作的产品控制器。我可以通过编程方式提取这些操作的名称来向用户显示支持哪些操作吗?

我研究了一种调用 ActionController::Routing::Routes.named_routes.routes.each 的方法 但我无法让它发挥作用。当我使用它时,我遇到了未初始化的常量 ActionDispatch::Routing::Routes 错误。

如果有什么好的教程或文档可以帮助我了解rails反射功能如何。我搜索了它,但我主要找到了与活动记录反射相关的博客。我正在寻找一些可以让我在运行时获取有关控制器和操作/方法的信息的东西。
谢谢,

塔布雷兹

In rails, I can get the name of the current controller via controller_name and the current action by calling action_name. I am looking for similar runtime reflection for fetching the following:

  1. List of all controllers in the application.
  2. List of all actions in a given controller.

For example, I a Product controller which has "add" and "edit" actions. Can I pull the names of these actions programmatically to show the user what operations are supported?

I have looked at a method that calls for use of ActionController::Routing::Routes.named_routes.routes.each
but I could not get that to work. I got uninitialized constant ActionDispatch::Routing::Routes error when I used it.

If there is any good tutorial or document that can help me understand how rails reflection capabilities. I searched for it but I mostly got active record reflection related blogs. I am looking for something that lets me get information on controllers and actions/methods at run time.
Thanks,

Tabrez

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

本宫微胖 2024-12-30 08:19:39

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

ApplicationController.descendants

但是,由于类是延迟加载的,因此您需要在执行此操作之前预先加载所有类。请记住,此方法需要时间,并且会减慢启动速度:

Rails.application.eager_load!

要获取控制器中的所有操作,请使用 action_methods

PostsController.action_methods

这将返回一个 Set,其中包含控制器中作为“操作”的所有方法的列表(使用 Rails 用来确定方法是否是要路由到的有效操作的相同逻辑)。

The easiest way to get a list of controller classes is:

ApplicationController.descendants

However, as classes are loaded lazily, you will need to eager load all your classes before you do this. Keep in mind that this method will take time, and it will slow down your boot:

Rails.application.eager_load!

To get all the actions in a controller, use action_methods

PostsController.action_methods

This will return a Set containing a list of all of the methods in your controller that are "actions" (using the same logic Rails uses to decide whether a method is a valid action to route to).

一瞬间的火花 2024-12-30 08:19:39

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

PostsController.action_methods will return all actions of PostsController including inherited, it's not what I want, I found PostsController.instance_methods(false), which will return all instance methods of PostsController and not include inherited, exactly what I want.

南风几经秋 2024-12-30 08:19:39

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

I had a similar problem; in my case it was for writing controller tests. There are certain basic tests that I want to run on every action for certain controllers (e.g., return 401 if the user is not logged in). The problem with the action_methods solution is that it picks up all methods on the controller class, even if the method does not have a corresponding route in config/routes.rb.

Here's what I ended up doing:

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

So if you wanted a list of actions for PostsController, you'd say:

actions_for_controller('posts')

And you would get:

['show', 'create', 'edit', 'destroy'] (or whatever)

If you wanted a list of all controllers, something like this should do it:

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
素染倾城色 2024-12-30 08:19:39

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

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

,它提供了一个很好的列表,其中包含在控制器名称下缩进的操作。

We are cleaning out unused controllers and actions. So I wanted to create an exhaustive list to mark for deletion. Here's what I ended up doing

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

That provides a nice list with actions indented under controller names.

可爱咩 2024-12-30 08:19:39

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 版中根本不起作用。

或者您可以在我的公共 github gist ControllerActionList 链接上使用我的课程

TLDR

you check this on your rails console

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"]]
# ] 

this already tested also in Rails 7.0 and other lower versions.
because ApplicationController.descendants didn't work at all at 7th version of rails.

or you can use use my class on my public github gist ControllerActionList link

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文