# Override existing Discourse methods in plugins

**URL:** https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389
**Category:** Developers
**Tags:** plugin-guides, how-to
**Created:** [March 20, 2018, 11:37am UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389 "2018-03-20T11:37:16Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![gdpelican](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/gdpelican/32/81308_2.png) [@gdpelican](https://meta.discourse.org/u/gdpelican)
#### Post date: [March 20, 2018, 11:37am UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/1 "2018-03-20T11:37:16Z")

</div>

I’ve been running into a bunch of instances recently of needing to override existing ruby methods from plugins, and thought I’d share my best practices here.

#### Overriding an instance method

```plaintext
class ::TopicQuery
  module BabbleDefaultResults
    def default_results(options={})
      super(options).where('archetype <> ?', Archetype.chat)
    end
  end
  prepend BabbleDefaultResults
end

```

- Here I’m removing chat topics from an instance method which is returning a list of topics.
- The module name `BabbleDefaultResults` can be anything you want; I usually make it match the name of the method, plus my plugin name, to minimize any name conflict risks (although they’re already quite low)
- [Module#prepend](http://gshutler.com/2013/04/ruby-2-module-prepend/) is super cool and you should know about it if you’re writing plugins for anything in ruby. Note that it’s the fact that we’re prepending a module which allows us to call `super` inside the override method.
- PS, _always call `super`!_ This makes your plugin far less likely to break when the underlying implementation changes. Unless you’re _really, really sure_ that your functionality completely replaces _everything_ in the underlying method, you want to call super and modify the results from there, so that changes to this method in Discourse core don’t make your plugin break later.
- The `::` in `::TopicQuery` is ensuring that I’m referring to the top-level `TopicQuery` class to override, and not some modulized version of it (like `Babble::TopicQuery`)
- This can go straight into `plugin.rb` as is, or if your plugin is large you can consider separating each override out into a separate file.

#### Overriding a class method

```plaintext
class ::Topic
  module BabbleForDigest
    def for_digest(user)
      super(user).where('archetype <> ?', Archetype.chat)
    end
  end
  singleton_class.prepend BabbleForDigest
end

```

- Here I’m taking an existing `self.for_digest` method on the Topic class, and removing chat topics from the result
- Very similar to the instance method override, note the difference being that we’re calling `singleton_class.prepend` instead of just `prepend`. `singleton_class` is a mildly weird way of saying ‘I want to append this to the class level, not the instance level’, [further reading](http://www.getlaura.com/ruby-singleton-classes/) if you’re looking for a ruby-related rabbit hole.

#### Overriding a scope

```plaintext
class ::Topic
  @@babble_listable_topics = method(:listable_topics).clone
  scope :listable_topics, ->(user) {
    @@babble_listable_topics.call(user).where('archetype <> ?', Archetype.chat)
  }
end

```

- This one’s a little bit tricky because scopes don’t play well with `super` (or, at least, I couldn’t get them to). So instead, we’re taking an existing method definition, cloning it, storing it, and then calling it later.
- Again, `@@babble_listable_topics` can be anything you’d like, but using your plugin name as a namespacer is probably a good idea.
- More on the [method function](https://ruby-doc.org/core-2.2.0/Method.html), which is _also_ super cool, although the times when you’d really need it are pretty few and far between. Bonus free fun fact related to that; when debugging, if you’re having trouble figuring out what code is getting run for a particular method call (usually “Which gem is defining this method?”), you can use `source_location` to get the exact line of source code where the method is defined.

```plaintext
[7] pry(main)> Topic.new.method(:best_post).source_location
=> ["/Users/gdpelican/workspace/discourse/app/models/topic.rb", 282]

```

( ^^ this is saying that the `best_post` method on a new topic is defined in /app/models/topic.rb, on line 282)

Alright, that’s all I’ve got. Let me know if I should correct, expand, or clarify anything 🙂

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [March 20, 2018, 12:52pm UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/2 "2018-03-20T12:52:16Z")

</div>

This is great, thanks for sharing James!

**Overriding instance and class methods**

My fav resource on this is: [https://stackoverflow.com/a/4471202](https://stackoverflow.com/a/4471202)

I use basically the same structure, except I tend to seperate out the module and the prepend.

As you pointed out, this pattern is “super” 😉 useful when trying to avoid overriding core logic.

```plaintext
module InviteMailerEventExtension
  def send_invite(invite)
     ## stuff
     super(invite)
  end
end

require_dependency 'invite_mailer'
class ::InviteMailer
  prepend InviteMailerEventExtension
end

```

One small tip here is that when overriding private or protected methods, your overriding method also needs to be private or protected, e.g.

```plaintext
module UserNotificationsEventExtension
  protected def send_notification_email(opts)
    ## stuff
    super(opts)
  end
end

```

---

<div class="post-metadata">

### Author: ![fzngagan](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fzngagan/32/259349_2.png) [@fzngagan](https://meta.discourse.org/u/fzngagan)
#### Post date: [August 4, 2019, 6:12am UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/3 "2019-08-04T06:12:58Z")

</div>

@angus @gdpelican Thanks for this. This is great stuff. 😃 . This would be really essential all the (especially newbies like me) plugin developers out there.

> [@gdpelican](#):
>
> PS, _always call `super` !_ This makes your plugin far less likely to break when the underlying implementation changes. Unless you’re _really, really sure_ that your functionality completely replaces _everything_ in the underlying method, you want to call super and modify the results from there, so that changes to this method in Discourse core don’t make your plugin break later.

This is what I really really needed to be aware of. I use to think that if you override a method only to make a few changes to it, you’d probably copy the code to your new method and make changes to it which by the very thought of it sounded hacky.

---

<div class="post-metadata">

### Author: ![spirobel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/spirobel/32/170908_2.png) [@spirobel](https://meta.discourse.org/u/spirobel)
#### Post date: [May 29, 2020, 8:06am UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/4 "2020-05-29T08:06:10Z")

</div>

> [@angus](#):
>
> `require_dependency 'invite_mailer'`

Hi, I was wondering about this part of the code? why is this require\_dependency needed? It seems like the code is working without it as well.

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [May 31, 2020, 11:09pm UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/5 "2020-05-31T23:09:16Z")

</div>

Yes, indeed. Since that post, updates to Discourse’s use of rails have made `require_dependency` unecessary. I’m unable to edit the post to address that. See further:

> [@Upgrading Discourse to Zeitwerk](https://meta.discourse.org/t/upgrading-discourse-to-zeitwerk/128337):
>
> Rails 6 ships with two autoloading modes: zeitwerk and classic. In that pull request [DEV: Upgrading Discourse to Rails 6 by KrisKotlarek · Pull Request #8083 · discourse/discourse · GitHub](https://github.com/discourse/discourse/pull/8083) I upgraded Rails to version 6.0.0 with classic autoloader as a transitional phase. It would be interesting to try to switch to Zeitwerk. Zeitwerk is an efficient and thread-safe code loader for Ruby. As long as the project is following naming conventions, Zeitwerk can find correct files and load them on deman…

---

<div class="post-metadata">

### Author: ![frank.manuel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/frank.manuel/32/203348_2.png) [@frank.manuel](https://meta.discourse.org/u/frank.manuel)
#### Post date: [January 30, 2022, 5:07pm UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/6 "2022-01-30T17:07:19Z")

</div>

Any tips for overriding module classes? I want to make some changes to GroupGuardian (some special conditions for a special kind of group).

Thanks.

---

<div class="post-metadata">

### Author: ![michaeld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaeld/32/1594_2.png) [@michaeld](https://meta.discourse.org/u/michaeld)
#### Post date: [January 30, 2022, 8:05pm UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/7 "2022-01-30T20:05:13Z")

</div>

You can just redefine the module and redefine the function. Use `alias_method` like this [RubyDoc.info: Method: Module#alias\_method – Documentation for core (4.0.0) – RubyDoc.info](https://www.rubydoc.info/stdlib/core/Module:alias_method) if you want to retain access to the old method.

---

<div class="post-metadata">

### Author: ![TimFelix](https://avatars.discourse-cdn.com/v4/letter/t/919ad9/32.png) [@TimFelix](https://meta.discourse.org/u/TimFelix)
#### Post date: [November 15, 2025, 6:33pm UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/12 "2025-11-15T18:33:20Z")

</div>

New to discourse and Rails development.I’m using the Dev Container environment (in VS Code) locally.The guides and docs have been helpful.

I was wondering if anyone has any tips on how to override core discourse classes, specifically getting it to persist in a local development environment.

In my plugin, I am trying to override a method in the core discourse `TopicEmbed` class. (using the general approach nicely documented by @angus above.) **It works once when I rebuild and reload VS Code, but on subsequent http requests my override is never invoked.**

My override is defined in `/plugins/my-plugin/app/models/override.rb` and I use `require_relative` to include this file in my `plugin.rb`.

```plaintext
#override.rb:
class ::TopicEmbed

  # a module that will be prepended into TopicEmbed.singleton_class
  module TopicEmbedOverrideModule
    # method in TopicEmbed
    def first_paragraph_from(html)
      Rails.logger.info(“my override is happening! ”)

      # continue with the original implementation provided by TopicEmbed.
      super

    end
  end

  # do the prepend here
  singleton_class.prepend TopicEmbedOverrideModule
end

```

I suspect this my persistence challenge may be due to my dev environment and how ruby code is compiled/cached.  
I also tried `rm -rf tmp; bin/ember-cli -u`and `bundle exec rake tmp:cache:clear`.

---

<div class="post-metadata">

### Author: ![TimFelix](https://avatars.discourse-cdn.com/v4/letter/t/919ad9/32.png) [@TimFelix](https://meta.discourse.org/u/TimFelix)
#### Post date: [December 10, 2025, 5:36pm UTC](https://meta.discourse.org/t/override-existing-discourse-methods-in-plugins/83389/13 "2025-12-10T17:36:56Z")

</div>

i got it to work for a singleton class this way:

```plaintext
# my overrides.rb

# A module that will be prepended into TopicEmbed.singleton_class
module TopicEmbedOverrides

  # Override parse_html method
  def parse_html(html, url) # note: i dont use self. here
    # my new stuff here
    # then run original implementation
    super
  end

end

# do the override here
class ::TopicEmbed
  singleton_class.prepend TopicEmbedOverrides
end

```
