How to retrieve group owners? (Rails code question)

I think this question gets into the weeds of Rails, but here goes:

I’m trying to figure out how to display the owner or owners of each group on the group index page (equivalent to this page).

My starting point is the group model, which implies to me that the group owners trait is not directly attached to a group (as opposed to, say,“full_name”, which I can see is part of the group schema at the bottom of that link).

So it’s clear that I can’t call group.owners like I can call group.full_name. Similarly, I don’t think I can get the info back from the API by retrieving info about a group, because “owners” doesn’t seem to be one of the returned values.

How would I get back the owners of a group to display that info?

I’m not totally clear on what you are trying to achieve, but I think you are looking for GroupUser. You can get a list of group_ids and their owners’ user_ids using something like:

GroupUser.where(owner: true).pluck("group_id", "user_id")
5 Likes

Thanks, this is definitely a step forward. My goal is to display the owners of a group under the group name on the group index page.

EDIT: For example, something like this:

<script type="text/x-handlebars" data-template-name="components/groups-info">
 {{#if showFullName}}
  <span class="groups-info-name">{{group.full_name}}</span>
  {{#each group.group_users as |gUser|}}
      {{#if gUser.owner}}
            <div>{{gUser.user.name}}</div>
      {{/if}}
  {{/each}}
{{else}}
  <span class="groups-info-name">{{group.displayName}}</span>
{{/if}}
</script>

This doesn’t quite work. What’s missing?

1 Like

You’ll need to write a small plugin to serialize the correct information. I saw your #marketplace post. Hopefully someone will take you up on that!

If you want to start seriously exploring plugins, you might consider checking out How to start building stuff for Discourse if you're newbie (like myself)

I hacked something together as a super rough proof of concept that might give you a starting point to figure it out on your own:

my-plugin/plugin.rb

# frozen_string_literal: true

# name: Group Test
# about: Group Test
# version: 0.1
# authors: Tester
# url: https://github.com/someone/something

enabled_site_setting :group_test_enabled

after_initialize do
  add_to_serializer(:basic_group, :owners) do
    GroupUser.where(group_id: object.id, owner: true).pluck("user_id")
  end
end

my-plugin/config/settings.yml

plugins:
  group_test_enabled:
    default: false
    client: true

In a theme’s </head> tab

<script type="text/x-handlebars" data-template-name="components/groups-info">
 {{#if showFullName}}
   <span class="groups-info-name">{{group.full_name}}</span>
 {{else}}
   <span class="groups-info-name">{{group.displayName}}</span>
   {{#each group.owners as |owner|}}
      {{#if owner}}
        <div>{{owner}}</div>
      {{/if}}
   {{/each}}
 {{/if}}
</script>

If you put all of that together and enable the plugin in your site settings, you should see the user ids of the group owners listed on the groups page.

I won’t be able to help beyond that, so best of luck!

6 Likes

This is extremely helpful–thanks. Understood you’re not able to provide further code help, but I’m hoping I can ask two general questions that others might find helpful too:

–Can you say briefly why a serializer is necessary here? (trying to understand not only for this but also other customizations)

And just a quick q–could I achieve this just in my dashboard? (creating a plugin would be a lot more organized for sure, but as I’m on a hosted plan I’m not able to directly import new plugins–it at least takes a few more steps)

1 Like

Sure :slight_smile: The data isn’t exposed by default in the BasicGroupSerializer. We only include what we need.

It’s a bit of a maze to follow, but the only reason the groups-info component has what it has available is because it’s passed group from it’s parent template:

https://github.com/discourse/discourse/blob/d3c972c30cafb8ca595a60233a30f75b2f95336c/app/assets/javascripts/discourse/app/templates/groups/index.hbs#L53-L53

And the parent template gets it from the controller:

https://github.com/discourse/discourse/blob/d3c972c30cafb8ca595a60233a30f75b2f95336c/app/assets/javascripts/discourse/app/controllers/groups-index.js#L37-L37

I’m afraid not. Unless there’s some magic I’m not aware of!

2 Likes

Awesome. Thank you very much for this helpful info.

1 Like

Edit: moved here after realizing the question I asked is more appropriate for a separate topic.

Hi @tshenry, I am trying to get a plugin going that includes some code like you provided above for exposing the group owner. One question I am sorting through:

–the relevant model here is “group” (that is referenced by the groups-info)
–but in the serializer, you don’t say: add_to_serializer(:group, :owners)… Instead of referencing :group, you reference :basic_group, like:

add_to_serializer(:basic_group, :owners)

Why do you reference basic_group, instead of group, in add_to_serializer?

It’s because ‘basic_group’ is the name of the serializer in this case: https://github.com/discourse/discourse/blob/master/app/serializers/basic_group_serializer.rb

3 Likes

How did you identify that serializer as being the right one for this case?

This is what I can gather: In the groups controller, in the index action, there is a render_json_dump function (or method) that includes the BasicGroupSerializer in the serialize_data call.

The relevant page for displaying groups data is the groups index, so the index action in the controller is the right one to look at here.

Is that how you know that the BasicGroupSerializer is the right one to reference here?

If that’s all correct, then would the GroupShowSerializer be used for when displaying the group show page, because that’s the serializer referenced in the show action in the controller? (the page with the details of a group–though there does not seem to be a “groups.show” view).

And then what about if there is no serializer referenced, such as in the new action in the controller?

This is indeed the reason

Because thats not a GET method. The serialisation is for the large quantities of repetitive data on the downlink.

@JQ331 take a look at the heart of the router config here: https://github.com/discourse/discourse/blob/master/config/routes.rb

This will show you how all the routes and controller methods are wired up in the base application.

Also consider reading through: Rails Routing from the Outside In — Ruby on Rails Guides

One additional thing to note which is really confusing and confused me a lot to begin with: Rails is a framework and it uses some very strict naming conventions to work some of its magic. It is not immediately clear when you are not used to it how everything gets wired together but when you take into account the naming conventions it starts to become clearer.

1 Like

Thanks for that reference–very helpful. I do find the routes file a little confusing. For example, as far as I can see, there is no groups#index controller action referenced, even though that’s clearly the relevant action for the main group get page. I do, however, see that groups#index action when I run:
% rails routes, which I guess is also a helpful way to see how a given page corresponds to a controller.

Don’t skip on the docs :wink:

This is how that works:
https://github.com/discourse/discourse/blob/57a8b3b964f867818c4dbfe394b762c0a286c28d/config/routes.rb#L95

See: Rails Routing from the Outside In — Ruby on Rails Guides

This is a very succinct way of routing a lot of methods.

3 Likes