我对 Rails 很陌生。我给自己设定了一个任务,用以下内容创建超级简单的网站:
授权管理区域添加/编辑/更新“页面”(包含 Slug 和正文)。将所述页面输出给未经授权的用户。
非常简单,但涵盖了常规博客演示之外的一些基础知识。
到目前为止最棘手的一点是使用生成器在命名空间区域内生成内容。
例如,我创建了一个名为页面的模型(位于
/models
中)。然后我想在 Admin 命名空间内为此执行 CRUD。
所以路线看起来像这样:
namespace :admin do
resources :pages, constraints: { format: :html }
end
现在,每当我使用生成器生成控制器或视图时,它都会不断地努力寻找路线
undefined method `page_path'
这是常见错误。
我是否对这里的生成器期望过高,是否创建了一个违反 Rails 约定的命名空间区域?如何在 Rails 应用程序内构建管理区域(或仅登录区域)?
您可能期望有点过高。
当模型与“命名空间”位于同一模块中时,Rails 生成器仅适用于命名空间资源。
例如,当您运行
rails g scaffold admin/pages
时,它将生成模型为:
class Admin::Page < ApplicationRecord
end
由于模块包含在型号名称中:
irb(main):001:0> Admin::Page.model_name
=>
#<ActiveModel::Name:0x000055caa5f6f958
@collection="admin/pages",
@element="page",
@human="Page",
@i18n_key=:"admin/page",
@klass=Admin::Page (call 'Admin::Page.connection' to establish a connection),
@name="Admin::Page",
@param_key="admin_page",
@plural="admin_pages",
@route_key="admin_pages",
@singular="admin_page",
@singular_route_key="admin_page",
@uncountable=false>
它仅适用于生成的视图/控制器,如下所示:
<%= link_to "Show this page", @admin_page %>
因为它将派生出路由助手方法
admin_page_path
,这就是您的路由生成的内容,因为 namespace
是路由助手的前缀。
如果您的
Page
类位于顶级命名空间,您将得到 undefined method 'page_path'
,因为它将派生该帮助程序名称。解决问题就像传递数组一样简单:
<%= link_to "Show this page", [:admin, @admin_page] %>
或者显式调用路由助手:
<%= link_to "Show this page", admin_page_path(@admin_page) %>
但是,代码模板还不够复杂,因此您必须在事后进行大量修复。如果您经常这样做,您可以自定义生成器或代码模板。
我是不是对这里的生成器期望太高了,是否创建了一个违反 Rails 约定的命名空间区域?
其实不然。代码模板实际上只是用于简单场景的快速原型设计,并不能完全覆盖所有可能的场景,甚至不能生成通过 Rubucop linting 的合适代码。我只是将它们视为需要修改的起点。
在约定范围内仍然需要考虑很多事情,例如嵌套资源,但无法使用生成器生成。
如何在 Rails 应用程序内构建管理区域(或只是登录区域)?
路由/控制器的命名空间与实现该功能关系不大。这实际上只是组织路线和代码的一种方式。
要在应用程序中创建限制区域,您很可能需要身份验证才能识别用户,并需要授权来限制用户可以执行的操作。这不是 Rails 内置的东西。
这个问题没有单一的解决方案,作为程序员,你必须找到最适合你的需求的解决方案。 Devise 和 Pundit 是受欢迎的选择。
生成控制器时,您可以覆盖模型以使用未命名空间的名称:
bin/rails g model page title body:text
bin/rails g scaffold_controller admin/page title body:text --model-name=page