# (Obsolete) Set category tracking level defaults historically

**URL:** https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165
**Category:** Self-Hosting
**Tags:** how-to
**Created:** [21 Noviembre, 2016 00:45 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165 "2016-11-21T00:45:27Z")
**Posts on this page:** 20
**Page:** 2

<div class="post-metadata">

### Author: ![alehandrof](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alehandrof/32/119526_2.png) [@alehandrof](https://meta.discourse.org/u/alehandrof)
#### Post date: [7 Febrero, 2017 13:42 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/21 "2017-02-07T13:42:46Z")

</div>

Nope. Using `:normal` results in an error:

```plaintext
  User Load (3.1ms) SELECT "users".* FROM "users"
   (0.4ms) SELECT "category_users"."category_id" FROM "category_users" WHERE "category_users"."user_id" = 121 AND "category_users"."notification_level" IS NULL
   (0.9ms) SELECT "categories"."id" FROM "categories" WHERE (id in (10))
   (0.2ms) BEGIN
  SQL (0.8ms) INSERT INTO "category_users" ("user_id", "category_id") VALUES (121, 10) RETURNING "id" [["user_id", 121], ["category_id", 10]]
   (0.2ms) ROLLBACK
ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR: null value in column "notification_level" violates not-null constraint
DETAIL: Failing row contains (1271, 10, 121, null).
: INSERT INTO "category_users" ("user_id", "category_id") VALUES (121, 10) RETURNING "id"
from /home/vagrant/.rvm/gems/ruby-2.3.1/gems/rack-mini-profiler-0.10.1/lib/patches/db/pg.rb:90:in `exec'

```

My guess is that I don’t really want to set it as `:regular` but somehow to set it as _not_ `:watching`.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [7 Febrero, 2017 14:01 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/22 "2017-02-07T14:01:12Z")

</div>

The query is along the lines of:

```plaintext
builder.where('notification_level = :tracking')

```

Later on doing this does nothing cause there is no `watching` var to substitute.

```plaintext
builder.exec(watching: notification_levels[:watching]) 

```

---

<div class="post-metadata">

### Author: ![alehandrof](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alehandrof/32/119526_2.png) [@alehandrof](https://meta.discourse.org/u/alehandrof)
#### Post date: [7 Febrero, 2017 14:05 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/23 "2017-02-07T14:05:47Z")

</div>

@sam, I’m afraid I don’t understand your answer. I’ve taken us a bit astray from the OT, but this is what I’m struggling with:

> [@alehandrof](#):
>
> I’ve previously made everyone “watch” a category with ID 5. How can I remove that setting?

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [7 Febrero, 2017 14:07 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/24 "2017-02-07T14:07:58Z")

</div>

What are you trying to do, delete all the category user records for all users that have it set to watching and 5?

```plaintext
CategoryUser.where(category_id: 5, notification_level: CategoryUser.notification_levels[:watching]).delete_all 

```

---

<div class="post-metadata">

### Author: ![alehandrof](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alehandrof/32/119526_2.png) [@alehandrof](https://meta.discourse.org/u/alehandrof)
#### Post date: [7 Febrero, 2017 14:22 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/25 "2017-02-07T14:22:24Z")

</div>

> [@sam](#):
>
> What are you trying to do, delete all the category user records for all users that have it set to watching and 5?

I wouldn’t of said it like that, but YES! Holy cow, yes.

---

<div class="post-metadata">

### Author: ![alehandrof](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alehandrof/32/119526_2.png) [@alehandrof](https://meta.discourse.org/u/alehandrof)
#### Post date: [7 Febrero, 2017 14:46 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/26 "2017-02-07T14:46:51Z")

</div>

It seems to do just what it says on the tin. Any adverse side-effects I should be aware of before trying this on production?

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [7 Febrero, 2017 14:51 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/27 "2017-02-07T14:51:21Z")

</div>

well, it junks that user pref, any user that set watching on category 5, will no longer have watching on category 5.

---

<div class="post-metadata">

### Author: ![alehandrof](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alehandrof/32/119526_2.png) [@alehandrof](https://meta.discourse.org/u/alehandrof)
#### Post date: [7 Febrero, 2017 15:30 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/28 "2017-02-07T15:30:11Z")

</div>

That sounds about right 🙂

Thanks to everyone here for helping me. For those playing at home, here’s a summary of the last 15 posts or so.

### How to make all users watch (or unwatch) a specific category through the rails console

**Set your parameters:**

```ruby
# Levels → :tracking :watching :watching_first_post :muted
level = :watching
category_slug = "announcements"

```

**And then,** to make everyone watch (or whatever level you set) this category:

```plaintext
User.all.each do |user| CategoryUser.batch_set(user, level, [Category.find_by_slug(category_slug)]) end

```

**Or** to make everyone unwatch (or whatever level you set) this category:

```plaintext
CategoryUser.where(category_id: Category.find_by_slug(category_slug), notification_level: CategoryUser.notification_levels[level]).delete_all

```

And there you have it! 🎉

⚠ Warning: unlike the OP, this is a destructive change in the sense that it disregards users’ current settings.

---

<div class="post-metadata">

### Author: ![tophee](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tophee/32/73406_2.png) [@tophee](https://meta.discourse.org/u/tophee)
#### Post date: [10 Abril, 2017 10:12 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/29 "2017-04-10T10:12:30Z")

</div>

> [@rriemann](#):
>
> paste your version of the code below.

This works for top-level categories, but if I use the slug of a sub-category, it gives me

```
> category = Category.find_by_slug(category_slug)
=> nil

```

How do you achieve the same for sub-categories?

Edit:  
I think I figured it out (thanks to [this hint](https://meta.discourse.org/t/watching-categories-based-on-on-group-in-discourse/41488/17)). This seems to work, but there might be a more elegant way (I don’t know how to define and hand over an array)

```
# levels: :watching :watching_first_post
level = :watching
category_slug = "local-news"
parent_category_slug = "news" # <== added
category = Category.find_by_slug(category_slug, parent_category_slug)
group_name = "trust_level_0" # all users
group = group = Group.find_by_name(group_name)

group.users.each do |user|
  watched_categories = CategoryUser.lookup(user, level).pluck(:category_id)
  CategoryUser.set_notification_level_for_category(user, CategoryUser.notification_levels[level], 
category.id) unless watched_categories.include?(category.id)
end

```

---

<div class="post-metadata">

### Author: ![watchmanmonitor](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/watchmanmonitor/32/430970_2.png) [@watchmanmonitor](https://meta.discourse.org/u/watchmanmonitor)
#### Post date: [31 Julio, 2018 23:00 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/30 "2018-07-31T23:00:05Z")

</div>

Is there a way to re-apply all default watching/tracking/email preferences to all users?

Not per-category as the commands here describe, but more like “here are the defaults for new users.. go ahead & apply them to all users now”?

---

<div class="post-metadata">

### Author: ![icaria36](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/icaria36/32/426431_2.png) [@icaria36](https://meta.discourse.org/u/icaria36)
#### Post date: [7 Agosto, 2018 23:14 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/31 "2018-08-07T23:14:28Z")

</div>

If I can save the time I have spent with this thread to someone in the future…

If you want to reset the notification level of a **subcategory** for all users from e.g. “muted” to “regular” (being `regular` a special case), this is what you need to do:

`./launcher enter app`  
`rails c`

And then paste your version of

```plaintext
level = :muted
category_slug = "cats" # this is the subcategory
parent_category_slug = "mammals" # this is the parent category
CategoryUser.where(category_id: Category.find_by_slug(category_slug, parent_category_slug), notification_level: CategoryUser.notification_levels[level]).delete_all

```

---

<div class="post-metadata">

### Author: ![jomaxro](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jomaxro/32/126216_2.png) [@jomaxro](https://meta.discourse.org/u/jomaxro)
#### Post date: [9 Agosto, 2018 12:17 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/32 "2018-08-09T12:17:06Z")

</div>

Can this be modified to work in group PM inboxes? For example, I was on an extended vacation, and I’m now returning. I updated my notification state for a shared inbox to “tracking” so I didn’t have thousands of green notifications, and now I want to update the state for all messages back to “watching”.

---

<div class="post-metadata">

### Author: ![jomaxro](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jomaxro/32/126216_2.png) [@jomaxro](https://meta.discourse.org/u/jomaxro)
#### Post date: [27 Agosto, 2018 20:06 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/33 "2018-08-27T20:06:42Z")

</div>

Courtesy of @sam, here’s the code to update the notification level for PMs historically. The following placeholders must be replaced: `<user_id>`, `<group_id_1>` ,`<group_id_2>`.

```plaintext
TopicUser.where('notification_level < 3 and user_id = <user_id> and topic_id in (select topic_id from topic_allowed_groups where group_id in (<group_id_1>,<group_id_2>) )').update_all(notification_level: 3)

```

---

<div class="post-metadata">

### Author: ![tophee](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tophee/32/73406_2.png) [@tophee](https://meta.discourse.org/u/tophee)
#### Post date: [18 Noviembre, 2018 21:13 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/34 "2018-11-18T21:13:03Z")

</div>

> [@sam](#):
>
> - Step 3, run a query to backfill changes
> 
> Say I want to set categories watching first post to on a certain category, I look up per step one and find it is 5.
> 
> ```plaintext
> INSERT INTO category_users(category_id, user_id, notification_level) 
> SELECT 5, u.id, 4
> FROM users u 
> LEFT JOIN category_users cu ON cu.category_id = 5 AND cu.user_id = u.id 
> WHERE cu.user_id IS NULL;
> 
> ```
> 
> The above query sets it on all users that do not have an explicit default for the category already set, this means you can re-run it if needed.

Assuming that this still works, I’m wondering whether category permissions will be honoured here.

I have a number of restricted categories and whoever has access to any of those should be watching first post by default. So if I follow the above steps for each of those categories, will only only users who actually hsve access be watching them?

---

<div class="post-metadata">

### Author: ![jomaxro](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jomaxro/32/126216_2.png) [@jomaxro](https://meta.discourse.org/u/jomaxro)
#### Post date: [18 Noviembre, 2018 22:54 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/35 "2018-11-18T22:54:57Z")

</div>

Category permissions are 100% followed.

---

<div class="post-metadata">

### Author: ![tophee](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tophee/32/73406_2.png) [@tophee](https://meta.discourse.org/u/tophee)
#### Post date: [19 Noviembre, 2018 20:38 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/36 "2018-11-19T20:38:11Z")

</div>

Okay, just to double check: am I right in assuming that I can use the above procedure to add the category in question to _all_ users but if a user doesn’t have access to that category it will remain ineffective and invisible for that user until the user gains access?

(My reasoning is based on [how `default categories watching` (etc) works](https://meta.discourse.org/t/user-watching-categories-despite-not-having-access/102326/2))

---

<div class="post-metadata">

### Author: ![jomaxro](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jomaxro/32/126216_2.png) [@jomaxro](https://meta.discourse.org/u/jomaxro)
#### Post date: [20 Noviembre, 2018 00:44 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/37 "2018-11-20T00:44:21Z")

</div>

That is my understand, yes.

---

<div class="post-metadata">

### Author: ![tophee](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tophee/32/73406_2.png) [@tophee](https://meta.discourse.org/u/tophee)
#### Post date: [25 Noviembre, 2018 22:29 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/38 "2018-11-25T22:29:09Z")

</div>

> [@sam](#):
>
> ./launcher enter app rails c % Category.find\_by(name: “my category name”).id =\> 666

How can this be made to work with a two-container setup? If I enter `data` there is no rails. And if I enter `web_only` I get `NoMethodError: undefined method `id' for nil:NilClass`.

---

<div class="post-metadata">

### Author: ![tophee](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tophee/32/73406_2.png) [@tophee](https://meta.discourse.org/u/tophee)
#### Post date: [25 Noviembre, 2018 23:23 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/44 "2018-11-25T23:23:32Z")

</div>

Hm, I was searching for “staff”, to be on the safe side:

```plaintext
# rails c
[1] pry(main)> Category.find_by(name: "staff").id
NoMethodError: undefined method `id' for nil:NilClass
from (pry):1:in ` __pry__'
[2] pry(main)>

```

Edit: Okay, got it: it’s case sensitive. This works:

```
Category.find_by(name: "Staff").id

```

---

<div class="post-metadata">

### Author: ![SouperC](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/souperc/32/62875_2.png) [@SouperC](https://meta.discourse.org/u/SouperC)
#### Post date: [29 Noviembre, 2018 19:41 UTC](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165/45 "2018-11-29T19:41:12Z")

</div>

Yesterday I discovered where our email volume of 100K+/mo was coming from… All new users were getting set as subscribed to our “General karting” category…

So I need to correct that…

I need some help with the syntax of part 1 in the OP. Bare with me here… I’m not exactly sure what I’m doing wrong..

I tried both " and ’ for quotations, but otherwise, I’m not sure what I need to correct in my syntax

```
[1] pry(main)> % Category.find_by(name: "General Karting").id
SyntaxError: unexpected ')', expecting end-of-input
...ind_by(name: "General Karting").id

```

… ^

```
[1] pry(main)> % Category.find_by(name: 'General Karting').id
SyntaxError: unexpected ')', expecting end-of-input
...ind_by(name: 'General Karting').id
... ^

```

[Previous page](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165.md?page=1)

[Next page](https://meta.discourse.org/t/obsolete-set-category-tracking-level-defaults-historically/53165.md?page=3)
