# 在插件中覆盖 user\_guardian.rb（无需 fork！）

**URL:** <https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839>\
**Category:** Development\
**Created:** [2021年一月3日 03:36 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839 "2021-01-03T03:36:43Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![leighno5](https://avatars.discourse-cdn.com/v4/letter/l/e19b73/32.png) [@leighno5](https://meta.discourse.org/u/leighno5)\
**Post date:** [2021年一月3日 03:36 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/1 "2021-01-03T03:36:44Z")

</div>

嘿，抱歉问这个新手问题。我一直在阅读文档，但还是需要一些指导。

我 fork 了 Discourse 并进行了自己的修改，希望基于这些修改进行自己的部署。[贡献指南](https://meta.discourse.org/t/beginners-guide-to-install-discourse-on-ubuntu-for-development/14727)介绍了如何进行修改并提交 PR，但在这个场景中，我并不想提交 PR。我只是希望基于我的微小修改，让 Discourse 能够正常安装运行。我原以为方法是将这一行指向我自己的仓库：

> <https://github.com/discourse/discourse_docker/blob/master/image/base/Dockerfile#L143>

我这样做了并执行了安装，但我的修改并没有生效，显然我哪里做错了。有什么建议吗？谢谢！

编辑：  
为了透明起见，也以防有人有更简单的方法，我实际上只是想允许匿名用户在进入匿名模式时更改他们的用户名。这很简单，只需将这一行中的 `false` 改为 `true`：

> <https://github.com/discourse/discourse/blob/main/lib/guardian/user_guardian.rb#L45>

如果有更好的方法，我非常乐意听取。但目前我只需要启用这个功能。我擅长 Python、Java 以及许多其他后端技术，但对 Ruby/JavaScript/HTML 等几乎一无所知。

编辑 2：  
根据[我在其他地方看到的一篇帖子](https://meta.discourse.org/t/cant-change-repo-in-discourse-docker/49376/5?u=leighno5)，我按以下方式更新了 app.yml：

```
run:
- exec:
 cd: /var/www/discourse
 cmd:
    - sudo -u discourse git remote set-url origin https://github.com/my/forked/discourse.git
    - sudo -u discourse git fetch origin
    - sudo -u discourse git checkout origin/master

```

重新构建应用后仍然没有效果。应用可以正常启动，但我的修改似乎并未生效。

---

<div class="post-metadata">

**Author:** ![itsbhanusharma](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/itsbhanusharma/32/180717_2.png) [@itsbhanusharma](https://meta.discourse.org/u/itsbhanusharma)\
**Post date:** [2021年一月3日 05:55 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/2 "2021-01-03T05:55:33Z")

</div>

难道不能将您的更改打包成一个插件来使用吗？

---

<div class="post-metadata">

**Author:** ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)\
**Post date:** [2021年一月3日 05:58 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/3 "2021-01-03T05:58:44Z")

</div>

> [@leighno5](#):
>
> 我 fork 了 Discourse 并进行了自己的修改

所有这样做的人都后悔莫及，而且在这里你也很难得到帮助。

无论你打算做什么，请通过插件来实现。

---

<div class="post-metadata">

**Author:** ![leighno5](https://avatars.discourse-cdn.com/v4/letter/l/e19b73/32.png) [@leighno5](https://meta.discourse.org/u/leighno5)\
**Post date:** [2021年一月3日 09:14 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/4 "2021-01-03T09:14:33Z")

</div>

好的。你知道如何通过插件来实现吗？

---

<div class="post-metadata">

**Author:** ![neounix](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/neounix/32/215617_2.png) [@neounix](https://meta.discourse.org/u/neounix)\
**Post date:** [2021年一月3日 09:19 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/5 "2021-01-03T09:19:22Z")

</div>

嘿 @leighno5

就我个人经验而言，我的想法是：如果你已经足够了解 Ruby 和 Rails，能够轻松地为 Discourse 编写插件（或修改任何 Rails 类），那么通过插件来实现你在“分支”中所做的事情会容易得多。

如果我们还不足以轻松理解 Rails 和 Ruby 并编写 Discourse 插件，那么我的经验是：直接 Fork 并修改核心代码是“误入歧途”的。

我想打个比方（抱歉这个想法很简单）：

“有人觉得走路很困难，于是决定直接去跑步。”

如果不介意的话，让我解释一下：

在我开始编写 Rails 应用（与 Discourse 无关）并尝试编写 Discourse 插件之前，我有点迷茫，甚至对 Discourse 有些恼火。这就像第一次打高尔夫球：球不会直线飞行，需要大量练习才能将球打到球道中央。Fork 并修改 Discourse 核心，就像在你还不会用短铁杆切球和推杆之前，就直接在练习场拿出大号开球木杆！

我曾暂时停止对 Discourse 的“黑客式”修改（那是几个月前的事了），转而实际从零开始构建了一些 Rails 应用。之后（也只有在那之后），我才开始对 Rails 建立起某种“直觉性”的理解。从那以后，当我决定修改 Discourse 时（目前我已在生产环境中运行了自己编写的 6 个自定义插件），一切都变得直观起来，那些需要修改 Ruby 核心的插件也变得过于简单。

Ruby 非常灵活。我们可以覆盖任何类、任何对象，甚至可以重新定义 Ruby 的每一个方面。随着经验的积累，我们会开始感叹：“哇！我完全没想到 Ruby 如此灵活（而且强大）！”然后开始“变得危险”，因为我们能像超人一样在 Ruby 和 Rails 中自由翱翔。那时，我们才刚刚踏上 Ruby 和 Rails 的旅程，远未到终点！

凭借我在 2020 年积累的 Ruby 和 Rails 知识，如果现在让我重来，我绝不会像你所提议的那样去 Fork Discourse 并修改 Ruby 和 Rails 核心。因为一旦我们理解了 Ruby 类的基础以及元编程的基本概念，通过插件来覆盖和修改 Ruby 类简直太容易了。

我想表达的意思是（抱歉如此直接）：如果有人认为必须通过修改 Discourse 核心来实现一些微小的 Ruby 改动，那说明他们对 Ruby 和 Rails 的理解还不够深入；因为如果他们真的理解了，就不会去修改核心，而是会直接编写一个简单的插件来覆盖类，并享受“猴子补丁”（monkey-patching）的乐趣。

另一方面，如果我想做一些疯狂的事情，比如用 React 和 Ant Design 替换 Discourse 的 EmberJS，让自己陷入痛苦，那么 Fork 确实是唯一可行的途径！然而，在我看来，“Discourse”并非由“JavaScript 库”定义。Discourse 是由核心开发团队（这些人）的技能、他们对细节的关注、客户服务、开源代码开发的团队协作方式、他们的 SPA 功能管线以及他们所有的辛勤工作所定义的！仅仅因为可能更喜欢 Ant Design（配合 React）或 VueJS 而不是 Ember，就抛弃所有这些智慧，在我看来有点疯狂。

如果我们只是打算对 Discourse 核心进行零星的修改，这一点更是如此！为了这种目的去 Fork 它，抛弃那些真正的“人”（他们才是“真正的”Discourse，而非代码），未免有点“疯了”。

以上只是我 2020 年学习 Ruby 和 Rails 的个人经历。现在，基础部分已经变得容易，我也开始“变得危险”了，哈哈。我可以“随意进行猴子补丁”，但这并不总是好事；而这正是 Discourse 插件存在的意义。

保持核心坚如磐石，尽情通过插件在 Discourse 上“折腾”吧。

希望这能帮到你。

顺便一提，在写这条回复时，你写道：

> [@leighno5](#):
>
> 好的。你知道如何通过插件来实现这个吗？

这某种程度上证明了我的观点，你不觉得吗？

在 Discourse 中编写“插件”，从某个层面来说就是编写"Ruby 代码”；而对其他人来说，这还涉及更深层的内容（比如 EmberJS）。

在你开始编写 Discourse 插件之前，我的友好建议（虽然对你来说可能显得毫无价值）是：先开发一些 Ruby on Rails 应用。至少掌握 Ruby 和 Rails 的基础知识，之后，你自然会回答自己上面提出的问题。

今天早上，我和客户开了三个小时的电话会议，讨论一个 Rails 应用、验证、模型等内容。会议结束后，我稍作休息，编写了一些会议中确定的待办事项，然后读到了你的帖子。

在我看来，编写 Discourse 插件的最短路径，就是先学习 Rails。

希望这能帮到你！

---

<div class="post-metadata">

**Author:** ![itsbhanusharma](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/itsbhanusharma/32/180717_2.png) [@itsbhanusharma](https://meta.discourse.org/u/itsbhanusharma)\
**Post date:** [2021年一月3日 09:24 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/6 "2021-01-03T09:24:45Z")

</div>

这是一个不错的起点：

> [@Developing Discourse Plugins - Part 1 - Create a basic plugin](https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins-part-1/30515?u=itsbhanusharma):
>
> Building a plugin in Discourse can be really simple, once you learn a couple of quirks. The goal of this post is to create a skeleton plugin and introduce you to the basics. Your development environment Make sure you have a development environment of Discourse running on your computer. I recommend you use [the appropriate setup guide](https://meta.discourse.org/tag/dev-install) and come back when you’re done. plugin.rbtada Use [GitHub - discourse/discourse-plugin-skeleton: Template for Discourse plugins](https://github.com/discourse/discourse-plugin-skeleton) to create a complete discourse p…

---

<div class="post-metadata">

**Author:** ![leighno5](https://avatars.discourse-cdn.com/v4/letter/l/e19b73/32.png) [@leighno5](https://meta.discourse.org/u/leighno5)\
**Post date:** [2021年一月3日 09:44 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/7 "2021-01-03T09:44:34Z")

</div>

不，您完全正确。我完全没有 Ruby 经验，所以绝对没有冒犯之意！

我已经看过插件指南，并反复阅读了几遍，但遗憾的是，我对 Ruby 的无知仍然让我感到沮丧。我完全不知道该如何编写一个插件，来覆盖 user-guardian 文件中的那部分代码，以允许匿名用户更改他们的用户名。😕

---

<div class="post-metadata">

**Author:** ![neounix](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/neounix/32/215617_2.png) [@neounix](https://meta.discourse.org/u/neounix)\
**Post date:** [2021年一月3日 10:30 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/8 "2021-01-03T10:30:30Z")

</div>

> [@leighno5](#):
>
> 我已经看过插件指南，也反复阅读了几遍，但遗憾的是，我对 Ruby 的无知依然让我感到挫败。我完全不知道该如何编写一个插件，来覆盖 user-guardian 文件中的那一段代码，从而允许匿名用户修改自己的用户名。

你好 @leighno5

是的，我理解你的情况。

那些“如何操作”（HOWTO）类的插件主题是由非常有才华的开发者撰写的，他们拥有超过十年的 Rails 和 Ruby 编程经验（甚至可能更长）。事实上，其中一些人可以说是全球顶尖的 Ruby 和 JavaScript 开发者之一。

我百分之百确定，这些开发者在编写他们的第一个 Discourse 插件之前，早就已经学习了 Rails 和 Ruby。

学习 Rails 其实并没有那么难；但你确实需要亲身实践“动手仪式”，从零开始构建几个 Rails 应用程序。不仅仅是跟着 YouTube 教程走（这当然很好），而是要真正构建一个可运行的应用程序，在其中你必须处理数据库设置、生成自己的模型、生成自己的控制器、编写模型验证、编写初始化脚本、编写辅助模块、进行数据库迁移（修改）、使用嵌入式 Ruby 等等。

这其实非常有趣，也是让你真正感到有信心编写插件的“最短路径”（就 Rails 方面而言，我个人并不太涉及 Ember，但我非常喜欢 Rails 这一侧的工作！）。

此外，你还必须掌握 Rails 控制台！Rails 控制台真的很有趣，我每天都很愉快地使用它！

今天，我和我最喜欢的客户通过 AnyDesk 协作，他问：“我们能不能看看这个新的库存视图？”他想看着我现场完成整个过程。当我们把它搭建并运行起来后，通话结束时他说：“你在 Rails 中用 30 分钟完成的事情，几十年前可能需要花费数周时间！！”真是太棒了，@leighno5。加油吧！！

当你学会 Rails 之后，你会发现编写 Discourse 插件其实相当简单，至少就 Rails 和 Ruby 部分而言是这样！！

希望这对你有帮助（HTH）。

---

<div class="post-metadata">

**Author:** ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)\
**Post date:** [2021年一月3日 10:53 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/9 "2021-01-03T10:53:05Z")

</div>

参考现有的 #Customization > Plugin 代码。现在已经有大量的插件，因此有很多示例可供参考。务必不要跳过阅读这些先例，以便加以利用。

听起来你只是想重写一个方法，这只需在 plugin.rb 中重新定义该方法即可（尽管最佳实践可能是将每个模块的代码单独拆分成一个文件，但对于单个方法来说，这样做似乎不太必要！）

---

<div class="post-metadata">

**Author:** ![leighno5](https://avatars.discourse-cdn.com/v4/letter/l/e19b73/32.png) [@leighno5](https://meta.discourse.org/u/leighno5)\
**Post date:** [2021年一月3日 11:12 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/10 "2021-01-03T11:12:10Z")

</div>

> [@merefield](#):
>
> 在你的 plugin.rb 中重新定义它

冒着进一步暴露我的无知并滥用您已给予的善意的风险，您是否愿意对此稍作展开说明？或者，如果您知道其他有人覆盖模块的示例并能提供链接，我将不胜感激。我完全不反对“阅读手册”（rtfm），但尽管我花了很多时间浏览各种教程和文档，我对 Discourse 工作原理的缺乏理解仍然让我感到沮丧。是的，我知道这类基础问题会让人觉得我投入甚少，但我保证事实并非如此！

---

<div class="post-metadata">

**Author:** ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)\
**Post date:** [2021年一月3日 12:40 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/11 "2021-01-03T12:40:48Z")

</div>

这是我们在 PostGuardian 中定义了一个方法的示例：

> <https://github.com/merefield/discourse-topic-previews-sidecar/blob/f4332f9742a37827fd6364b2365c45524f1e7faf/lib/guardian_edits.rb#L10>

你可以对 UserGuardian 采用类似的做法，使用现有的方法名，这样应该会覆盖原有实现。

#### 简单方案（用于快速实现，但不够稳健）：

直接复制原始方法的代码并进行你的修改。缺点是：如果 Discourse 更新了代码，你的插件可能会导致实例出错。

#### 高级方案（更稳健的解决方案）：

为了更进一步，你可以尝试使用 `super` 来继承原始方法，但这并不保证一定能成功（原因这里就不详细展开了）。不过，这仍是最佳实践，因为这样 Discourse 对该方法的任何更新都会被自动考虑，而无需你手动修改插件代码。

Discourse 是一个平台，需要时间来熟悉。请一步一步来。

---

<div class="post-metadata">

**Author:** ![Jonathan5](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jonathan5/32/197134_2.png) [@Jonathan5](https://meta.discourse.org/u/Jonathan5)\
**Post date:** [2021年一月3日 13:48 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/12 "2021-01-03T13:48:27Z")

</div>

> [@merefield](#):
>
> 直接写出原始方法代码并进行修改即可。缺点是：如果 Discourse 更改了代码，你的插件可能会导致实例故障。

这正是我所担心的。你下一段中提到的“高级方法”在操作指南中有涵盖吗？是否有现成插件中使用的、简单且良好的示例，可供在创建新插件时参考（或复制）？

---

<div class="post-metadata">

**Author:** ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)\
**Post date:** [2021年一月3日 14:28 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/13 "2021-01-03T14:28:52Z")

</div>

目前不必担心高级方法，先确保它能正常运行。你可以在线指南的其他部分研究 Ruby on Rails 的一般知识。这超出了 Discourse 具体内容和本论坛的范围，请知悉。

---

<div class="post-metadata">

**Author:** ![Jonathan5](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jonathan5/32/197134_2.png) [@Jonathan5](https://meta.discourse.org/u/Jonathan5)\
**Post date:** [2021年一月3日 14:32 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/14 "2021-01-03T14:32:14Z")

</div>

好的，谢谢！假设我抽空写了一个小型插件。如果我没理解错的话，每次升级时，我都应该检查核心代码，并在相关核心代码发生变化时重写该插件。是这样吗？谢谢。

---

<div class="post-metadata">

**Author:** ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)\
**Post date:** [2021年一月3日 14:35 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/15 "2021-01-03T14:35:43Z")

</div>

没错。只需偶尔检查一下，尤其是在它开始出现故障时。由于 Guardian 代码涉及站点授权，因此更为关键，请密切关注。

另一种解决方案是添加测试用例（即 specs），并设置自动化任务来运行它们……但这会变得更加复杂！

---

<div class="post-metadata">

**Author:** ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)\
**Post date:** [2021年一月3日 16:26 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/16 "2021-01-03T16:26:53Z")

</div>

另一个额外加分任务是设置 [travis-ci.org](http://travis-ci.org) 来运行你的插件测试，这样一旦插件出现问题，你就能及时收到通知。

---

<div class="post-metadata">

**Author:** ![Jonathan5](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jonathan5/32/197134_2.png) [@Jonathan5](https://meta.discourse.org/u/Jonathan5)\
**Post date:** [2021年一月3日 18:58 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/17 "2021-01-03T18:58:33Z")

</div>

这显然不是一项可以掉以轻心的任务。我想修改登录/创建新账户的模态框，并移除 Twitter 图片。或许后者是更合适的首要项目。谢谢。

---

<div class="post-metadata">

**Author:** ![leighno5](https://avatars.discourse-cdn.com/v4/letter/l/e19b73/32.png) [@leighno5](https://meta.discourse.org/u/leighno5)\
**Post date:** [2021年一月4日 05:41 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/18 "2021-01-04T05:41:22Z")

</div>

如果任何人遇到此问题，且曾像我一样感到迷茫，我将提供我的代码，因为它已按预期运行。我没有修改任何文件，只需创建一个新文件 `plugin.rb`，并将以下内容放入其中：

```ruby
# name: noms
# about: 允许匿名模式下的用户更改其用户名
# version: 0.1

require_dependency 'guardian'
require_dependency 'guardian/user_guardian'

class ::Guardian
end

module ::UserGuardian
  def can_edit_username?(user)
    return false if SiteSetting.sso_overrides_username?
    return true if is_staff?
    return false if SiteSetting.username_change_period <= 0
    return true if is_anonymous?
    is_me?(user) && ((user.post_count + user.topic_count) == 0 || user.created_at > SiteSetting.username_change_period.days.ago)
  end

  def can_edit_name?(user)
    return false unless SiteSetting.enable_names?
    return false if SiteSetting.sso_overrides_name?
    return true if is_staff?
    return true if is_anonymous?
    can_edit?(user)
  end
end

```

这会覆盖 Discourse 核心中的 [user\_guardian.rb](https://github.com/discourse/discourse/blob/master/lib/guardian/user_guardian.rb) 类，从而允许用户更改其匿名用户账户的用户名和名称。

如果你将我提供的代码与 Discourse 核心中的 `user_guardian.rb` 进行对比，你会发现其中还有很多其他内容，我无需对其进行任何修改，因此保持原样。我只需要修改 `can_edit_username` 和 `can_edit_name` 这两个方法，将某些返回值从 `false` 改为 `true`，即可实现所需功能。

当然，这仍有改进空间，也可能存在最佳实践，这些可以通过阅读此处及其他地方的相关帖子来了解。但如果你像我一样是 Ruby 新手，只想对核心功能进行一些非常简单的调整，那么这是一个极简且可工作的示例，展示了你需要做什么。

非常感谢本线程中的各位对我的耐心、鼓励与帮助！特别感谢 @merefield，他过去曾帮助过我另一个帖子。

---

<div class="post-metadata">

**Author:** ![neounix](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/neounix/32/215617_2.png) [@neounix](https://meta.discourse.org/u/neounix)\
**Post date:** [2021年一月4日 06:33 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/19 "2021-01-04T06:33:47Z")

</div>

哈哈

为了完成这些简单的任务，你们已经从最初打算分叉整个 Discourse 并放弃主分支的想法，走了很远的路。

干得漂亮 🙂

---

<div class="post-metadata">

**Author:** ![Jonathan5](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jonathan5/32/197134_2.png) [@Jonathan5](https://meta.discourse.org/u/Jonathan5)\
**Post date:** [2021年一月4日 10:19 UTC](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839/20 "2021-01-04T10:19:10Z")

</div>

> [@leighno5](#):
>
> 而且很可能存在最佳实践

你是按照 [Install Discourse on Ubuntu or Debian for Development](https://meta.discourse.org/t/beginners-guide-to-install-discourse-on-ubuntu-for-development/14727?u=jonathan5) 的完整路径进行的，还是直接在您的生产站点上操作并听天由命？

[下一頁](https://meta.discourse.org/t/overriding-user-guardian-rb-in-a-plugin-no-fork-necessary/174839.md?page=2)
