-
Notifications
You must be signed in to change notification settings - Fork 0
FIX: proper handling of group memberships #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: group-dm-user-addition-pre
Are you sure you want to change the base?
Conversation
WalkthroughThis change set overhauls group management in the admin interface by introducing paginated member lists, explicit member add/remove endpoints, and UI controls for pagination and member management. It refactors both client-side JavaScript and server-side Ruby code, updates templates, styles, localization, and tests to align with the new group membership workflows and API structure. Changes
Sequence Diagram(s)sequenceDiagram
participant Admin as Admin UI
participant GroupModel as Group Model
participant Server as Rails Server
Admin->>GroupModel: findMembers(offset, limit)
GroupModel->>Server: GET /groups/:id/members?offset=&limit=
Server-->>GroupModel: { members, meta }
GroupModel-->>Admin: members, pagination info
Admin->>GroupModel: addMembers(usernames)
GroupModel->>Server: PUT /admin/groups/:id/members (usernames)
Server-->>GroupModel: success
GroupModel->>GroupModel: findMembers() (refresh)
Admin->>GroupModel: removeMember(member)
GroupModel->>Server: DELETE /admin/groups/:id/members (user_id)
Server-->>GroupModel: success
GroupModel->>GroupModel: findMembers() (refresh)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🔭 Outside diff range comments (1)
spec/controllers/admin/groups_controller_spec.rb (1)
67-129: Update all remaining deprecated RSpec syntaxMultiple test contexts still use deprecated
shouldsyntax. Update all instances to modernexpectsyntax for consistency.Examples of required changes:
# destroy context - response.status.should == 422 - Group.where(id: group.id).count.should == 1 + expect(response.status).to eq(422) + expect(Group.where(id: group.id).count).to eq(1) # add_members context - response.status.should == 422 + expect(response.status).to eq(422) - response.should be_success + expect(response).to be_success - group.users.count.should == 2 + expect(group.users.count).to eq(2) # remove_member context - response.status.should == 422 + expect(response.status).to eq(422) - response.should be_success + expect(response).to be_success - group.users.count.should == 0 + expect(group.users.count).to eq(0)
🧹 Nitpick comments (5)
app/assets/stylesheets/common/admin/admin_base.scss (1)
462-481: Consider reducing!importantdeclarations.The group-specific styles look good overall, but the multiple
!importantdeclarations (lines 465, 468, 472, 474) suggest potential CSS specificity issues.Consider refactoring to avoid
!importantdeclarations:.groups { .ac-wrap { - width: 100% !important; + width: 100%; .item { width: 190px; - margin-right: 0 !important; + margin-right: 0; } } .next, .previous { - color: #333 !important; + color: #333; &.disabled { - color: #aaa !important; + color: #aaa; } }This would require ensuring the selectors have appropriate specificity without forcing precedence.
app/controllers/groups_controller.rb (1)
22-36: Well-implemented pagination with good response structure.The pagination implementation is solid with sensible defaults and a clean JSON response format. The separate total count query and ordered results provide good UX for pagination controls.
Consider adding an upper limit validation for security:
-limit = (params[:limit] || 50).to_i +limit = [(params[:limit] || 50).to_i, 200].minThis prevents potentially expensive queries from very large limit values.
spec/controllers/admin/groups_controller_spec.rb (1)
14-132: Clean up extra empty lines for consistent formattingRuboCop identified multiple formatting inconsistencies with extra empty lines at block boundaries.
Remove the extra empty lines at the beginning and end of each context block to follow Ruby style conventions. For example:
context ".index" do - it "produces valid json for groups" doapp/assets/javascripts/discourse/models/group.js (1)
17-17: Use strict equality operator- if (c > 0) { return c; } + if (c > 0) { return c; }app/controllers/admin/groups_controller.rb (1)
6-9: Clarify assignment in conditionalRuboCop flagged the assignment in the conditional. Add parentheses to make the intent clear.
- if search = params[:search] + if (search = params[:search]) search = search.to_s groups = groups.where("name ILIKE ?", "%#{search}%") end
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
app/assets/javascripts/admin/controllers/admin-group.js.es6(2 hunks)app/assets/javascripts/admin/routes/admin_group_route.js(1 hunks)app/assets/javascripts/admin/templates/group.hbs(1 hunks)app/assets/javascripts/admin/templates/group_member.hbs(1 hunks)app/assets/javascripts/admin/views/group-member.js.es6(1 hunks)app/assets/javascripts/discourse/models/group.js(1 hunks)app/assets/javascripts/discourse/routes/group-members.js.es6(1 hunks)app/assets/javascripts/discourse/templates/components/admin-group-selector.hbs(0 hunks)app/assets/javascripts/discourse/templates/group/members.hbs(1 hunks)app/assets/javascripts/discourse/templates/user-selector-autocomplete.raw.hbs(1 hunks)app/assets/stylesheets/common/admin/admin_base.scss(2 hunks)app/controllers/admin/groups_controller.rb(2 hunks)app/controllers/groups_controller.rb(1 hunks)config/locales/client.en.yml(1 hunks)config/routes.rb(1 hunks)spec/controllers/admin/groups_controller_spec.rb(2 hunks)
💤 Files with no reviewable changes (1)
- app/assets/javascripts/discourse/templates/components/admin-group-selector.hbs
🧰 Additional context used
🪛 RuboCop (1.76.1)
spec/controllers/admin/groups_controller_spec.rb
[convention] 14-15: Extra empty line detected at block body beginning.
(Layout/EmptyLinesAroundBlockBody)
[convention] 31-32: Extra empty line detected at block body end.
(Layout/EmptyLinesAroundBlockBody)
[convention] 35-36: Extra empty line detected at block body beginning.
(Layout/EmptyLinesAroundBlockBody)
[convention] 46-47: Extra empty line detected at block body end.
(Layout/EmptyLinesAroundBlockBody)
[convention] 50-51: Extra empty line detected at block body beginning.
(Layout/EmptyLinesAroundBlockBody)
[convention] 59-60: Extra empty line detected at block body end.
(Layout/EmptyLinesAroundBlockBody)
[convention] 77-78: Extra empty line detected at block body end.
(Layout/EmptyLinesAroundBlockBody)
[convention] 81-82: Extra empty line detected at block body beginning.
(Layout/EmptyLinesAroundBlockBody)
[convention] 88-89: Extra empty line detected at block body end.
(Layout/EmptyLinesAroundBlockBody)
[convention] 92-93: Extra empty line detected at block body beginning.
(Layout/EmptyLinesAroundBlockBody)
[convention] 109-110: Extra empty line detected at block body end.
(Layout/EmptyLinesAroundBlockBody)
[convention] 113-114: Extra empty line detected at block body beginning.
(Layout/EmptyLinesAroundBlockBody)
[convention] 131-132: Extra empty line detected at block body end.
(Layout/EmptyLinesAroundBlockBody)
app/controllers/admin/groups_controller.rb
[warning] 6-6: Use == if you meant to do a comparison or wrap the expression in parentheses to indicate you meant to assign in a condition.
(Lint/AssignmentInCondition)
[warning] 72-72: Use == if you meant to do a comparison or wrap the expression in parentheses to indicate you meant to assign in a condition.
(Lint/AssignmentInCondition)
🔇 Additional comments (13)
app/assets/javascripts/discourse/templates/group/members.hbs (1)
6-6: LGTM! Template iteration updated for paginated members.The change from iterating over
modeltomembersaligns with the pagination refactoring described in the PR. This change ensures the template works with the new paginated member data structure.app/assets/javascripts/admin/views/group-member.js.es6 (1)
1-4: LGTM! Well-structured view component.The view component follows Discourse conventions correctly:
- Properly extends
Discourse.View- Uses appropriate CSS class naming
- References the correct template path
app/assets/javascripts/admin/templates/group_member.hbs (1)
1-1: LGTM! Clean and functional member template.The template correctly:
- Displays member avatar and username
- Conditionally shows remove link only for non-automatic members
- Uses appropriate FontAwesome icon for the remove action
- Properly binds the
removeMemberaction with the member parameterapp/assets/javascripts/discourse/templates/user-selector-autocomplete.raw.hbs (1)
5-8: LGTM! Improved code formatting and readability.The indentation changes enhance the template's readability without affecting functionality. The cleaner structure makes it easier to understand the HTML hierarchy.
Also applies to: 15-19
config/locales/client.en.yml (2)
1623-1623: LGTM! More specific placeholder text.The change from "add users" to "enter username" provides clearer guidance to users about the expected input format.
1630-1633: LGTM! Comprehensive localization for new member management features.The added localization keys properly support the new group member management functionality:
delete_member_confirm: Provides user confirmation for member removalname: Labels the group name input fieldadd: Generic add button labeladd_members: Descriptive label for the member addition sectionThese keys align well with the enhanced group management UI described in the PR.
config/routes.rb (1)
49-50: LGTM! RESTful route design for member management.The new routes properly implement explicit member addition and removal endpoints following RESTful conventions. Using DELETE for
remove_memberand PUT foradd_membersis appropriate for these operations.app/assets/javascripts/discourse/routes/group-members.js.es6 (1)
8-12: Good simplification of route lifecycle.Moving member fetching from
afterModeltosetupControllerand delegating tomodel.findMembers()simplifies the route logic. This aligns well with the pagination refactor where the model handles member fetching responsibility.app/assets/stylesheets/common/admin/admin_base.scss (1)
164-182: Good consolidation of form styles.Consolidating the
.form-horizontalstyles for both.groupsand.badgescontainers reduces code duplication and ensures consistent styling across the admin interface.app/assets/javascripts/admin/routes/admin_group_route.js (1)
11-15: Consistent with the member fetching refactor.The changes mirror those in the group-members route, maintaining consistency across the codebase. Delegating member fetching to the model's
findMembers()method aligns with the pagination refactor.app/controllers/groups_controller.rb (1)
40-45: Improved parameter handling and security.The updated
find_groupmethod uses better parameter validation withparams.require()and implements case-insensitive group lookup while maintaining proper authorization checks.app/assets/javascripts/discourse/models/group.js (1)
82-82: Fix syntax error in destroy methodThe early return statement has incorrect syntax.
destroy: function(){ - if (!this.get('id')) { return }; + if (!this.get('id')) { return; } return Discourse.ajax("/admin/groups/" + this.get('id'), {type: "DELETE"});Likely an incorrect or invalid review comment.
app/controllers/admin/groups_controller.rb (1)
1-104: Well-structured controller refactoringThe refactoring to split member management into dedicated actions improves clarity and follows REST principles. The consistent handling of automatic group restrictions is excellent.
| if (this.get("user_count") == 0) { return 0; } | ||
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | ||
| }.property("limit", "offset", "user_count"), | ||
|
|
||
| totalPages: function() { | ||
| if (this.get("user_count") == 0) { return 0; } | ||
| return Math.floor(this.get("user_count") / this.get("limit")) + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use strict equality operators
Replace loose equality operators with strict equality to avoid type coercion issues.
currentPage: function() {
- if (this.get("user_count") == 0) { return 0; }
+ if (this.get("user_count") === 0) { return 0; }
return Math.floor(this.get("offset") / this.get("limit")) + 1;
}.property("limit", "offset", "user_count"),
totalPages: function() {
- if (this.get("user_count") == 0) { return 0; }
+ if (this.get("user_count") === 0) { return 0; }
return Math.floor(this.get("user_count") / this.get("limit")) + 1;
}.property("limit", "user_count"),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (this.get("user_count") == 0) { return 0; } | |
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | |
| }.property("limit", "offset", "user_count"), | |
| totalPages: function() { | |
| if (this.get("user_count") == 0) { return 0; } | |
| return Math.floor(this.get("user_count") / this.get("limit")) + 1; | |
| currentPage: function() { | |
| if (this.get("user_count") === 0) { return 0; } | |
| return Math.floor(this.get("offset") / this.get("limit")) + 1; | |
| }.property("limit", "offset", "user_count"), | |
| totalPages: function() { | |
| if (this.get("user_count") === 0) { return 0; } | |
| return Math.floor(this.get("user_count") / this.get("limit")) + 1; | |
| }.property("limit", "user_count"), |
🤖 Prompt for AI Agents
In app/assets/javascripts/admin/controllers/admin-group.js.es6 around lines 7 to
13, replace all instances of loose equality operators (==) with strict equality
operators (===) to prevent unintended type coercion and ensure accurate
comparisons.
| addMembers: function() { | ||
| // TODO: should clear the input | ||
| if (Em.isEmpty(this.get("usernames"))) { return; } | ||
| this.get("model").addMembers(this.get("usernames")); | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Address TODO: Clear usernames input after adding members
The TODO comment indicates missing functionality. The usernames input should be cleared after successfully adding members.
addMembers: function() {
- // TODO: should clear the input
if (Em.isEmpty(this.get("usernames"))) { return; }
- this.get("model").addMembers(this.get("usernames"));
+ var self = this;
+ this.get("model").addMembers(this.get("usernames")).then(function() {
+ self.set("usernames", null);
+ });
},Would you like me to create an issue to track this enhancement?
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| addMembers: function() { | |
| // TODO: should clear the input | |
| if (Em.isEmpty(this.get("usernames"))) { return; } | |
| this.get("model").addMembers(this.get("usernames")); | |
| }, | |
| addMembers: function() { | |
| if (Em.isEmpty(this.get("usernames"))) { return; } | |
| var self = this; | |
| this.get("model").addMembers(this.get("usernames")).then(function() { | |
| self.set("usernames", null); | |
| }); | |
| }, |
🤖 Prompt for AI Agents
In app/assets/javascripts/admin/controllers/admin-group.js.es6 around lines 61
to 65, the addMembers function currently does not clear the usernames input
after adding members, as noted by the TODO comment. To fix this, after calling
addMembers on the model with the usernames, reset the usernames property to an
empty string or appropriate empty value to clear the input field.
| <a {{bind-attr class=":previous showingFirst:disabled"}} {{action "previous"}}>{{fa-icon "fast-backward"}}</a> | ||
| {{currentPage}}/{{totalPages}} | ||
| <a {{bind-attr class=":next showingLast:disabled"}} {{action "next"}}>{{fa-icon "fast-forward"}}</a> | ||
| </div> | ||
| <div class="ac-wrap clearfix"> | ||
| {{each member in members itemView="group-member"}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update deprecated Ember.js syntax
The template uses deprecated Ember helpers that should be updated to modern syntax:
- Replace
bind-attrwith direct attribute binding - Use modern
eachblock syntax
- <a {{bind-attr class=":previous showingFirst:disabled"}} {{action "previous"}}>{{fa-icon "fast-backward"}}</a>
+ <a class="previous {{if showingFirst 'disabled'}}" {{action "previous"}}>{{fa-icon "fast-backward"}}</a>
{{currentPage}}/{{totalPages}}
- <a {{bind-attr class=":next showingLast:disabled"}} {{action "next"}}>{{fa-icon "fast-forward"}}</a>
+ <a class="next {{if showingLast 'disabled'}}" {{action "next"}}>{{fa-icon "fast-forward"}}</a>
</div>
<div class="ac-wrap clearfix">
- {{each member in members itemView="group-member"}}
+ {{#each members as |member|}}
+ {{group-member member=member}}
+ {{/each}}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <a {{bind-attr class=":previous showingFirst:disabled"}} {{action "previous"}}>{{fa-icon "fast-backward"}}</a> | |
| {{currentPage}}/{{totalPages}} | |
| <a {{bind-attr class=":next showingLast:disabled"}} {{action "next"}}>{{fa-icon "fast-forward"}}</a> | |
| </div> | |
| <div class="ac-wrap clearfix"> | |
| {{each member in members itemView="group-member"}} | |
| <a class="previous {{if showingFirst 'disabled'}}" {{action "previous"}}>{{fa-icon "fast-backward"}}</a> | |
| {{currentPage}}/{{totalPages}} | |
| <a class="next {{if showingLast 'disabled'}}" {{action "next"}}>{{fa-icon "fast-fast-forward"}}</a> | |
| </div> | |
| <div class="ac-wrap clearfix"> | |
| {{#each members as |member|}} | |
| {{group-member member=member}} | |
| {{/each}} |
🤖 Prompt for AI Agents
In app/assets/javascripts/admin/templates/group.hbs around lines 16 to 21, the
template uses deprecated Ember.js syntax such as `bind-attr` and the old `each`
helper. Replace `bind-attr` with direct class attribute bindings using curly
braces and class concatenation or class helper. Update the `each` loop to use
the modern block form `{{#each members as |member|}}` instead of `{{each member
in members}}`.
| </div> | ||
|
|
||
| <div class='buttons'> | ||
| <button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update deprecated bind-attr helper
Replace the deprecated bind-attr helper with modern attribute binding syntax.
- <button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button>
+ <button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button> | |
| <button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button> |
🤖 Prompt for AI Agents
In app/assets/javascripts/admin/templates/group.hbs at line 47, the code uses
the deprecated bind-attr helper to bind the disabled attribute. Replace
bind-attr with the modern Ember attribute binding syntax by directly using
disabled={{disableSave}} inside the button tag to properly bind the disabled
attribute.
| removeMember: function(member) { | ||
| var self = this; | ||
| return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', { | ||
| type: "DELETE", | ||
| data: { user_id: member.get("id") } | ||
| }).then(function() { | ||
| // reload member list | ||
| self.findMembers(); | ||
| }); | ||
| }, | ||
|
|
||
| asJSON: function() { | ||
| return { group: { | ||
| name: this.get('name'), | ||
| alias_level: this.get('alias_level'), | ||
| visible: !!this.get('visible'), | ||
| usernames: this.get('usernames') } }; | ||
| addMembers: function(usernames) { | ||
| var self = this; | ||
| return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', { | ||
| type: "PUT", | ||
| data: { usernames: usernames } | ||
| }).then(function() { | ||
| // reload member list | ||
| self.findMembers(); | ||
| }) | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling to member management methods
Both removeMember and addMembers methods lack error handling. Also, the promise should be returned to allow proper chaining in the controller.
removeMember: function(member) {
var self = this;
return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', {
type: "DELETE",
data: { user_id: member.get("id") }
}).then(function() {
// reload member list
- self.findMembers();
+ return self.findMembers();
+ }).catch(function(error) {
+ bootbox.alert(I18n.t("generic_error"));
+ throw error;
});
},
addMembers: function(usernames) {
var self = this;
return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', {
type: "PUT",
data: { usernames: usernames }
}).then(function() {
// reload member list
- self.findMembers();
- })
+ return self.findMembers();
+ }).catch(function(error) {
+ bootbox.alert(I18n.t("generic_error"));
+ throw error;
+ });
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| removeMember: function(member) { | |
| var self = this; | |
| return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', { | |
| type: "DELETE", | |
| data: { user_id: member.get("id") } | |
| }).then(function() { | |
| // reload member list | |
| self.findMembers(); | |
| }); | |
| }, | |
| asJSON: function() { | |
| return { group: { | |
| name: this.get('name'), | |
| alias_level: this.get('alias_level'), | |
| visible: !!this.get('visible'), | |
| usernames: this.get('usernames') } }; | |
| addMembers: function(usernames) { | |
| var self = this; | |
| return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', { | |
| type: "PUT", | |
| data: { usernames: usernames } | |
| }).then(function() { | |
| // reload member list | |
| self.findMembers(); | |
| }) | |
| }, | |
| removeMember: function(member) { | |
| var self = this; | |
| return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', { | |
| type: "DELETE", | |
| data: { user_id: member.get("id") } | |
| }).then(function() { | |
| // reload member list | |
| return self.findMembers(); | |
| }).catch(function(error) { | |
| bootbox.alert(I18n.t("generic_error")); | |
| throw error; | |
| }); | |
| }, | |
| addMembers: function(usernames) { | |
| var self = this; | |
| return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', { | |
| type: "PUT", | |
| data: { usernames: usernames } | |
| }).then(function() { | |
| // reload member list | |
| return self.findMembers(); | |
| }).catch(function(error) { | |
| bootbox.alert(I18n.t("generic_error")); | |
| throw error; | |
| }); | |
| }, |
🤖 Prompt for AI Agents
In app/assets/javascripts/discourse/models/group.js between lines 40 and 60, the
removeMember and addMembers methods lack error handling and do not properly
return promises for chaining. To fix this, add .catch handlers to both methods
to handle potential AJAX errors gracefully, and ensure the promise returned by
Discourse.ajax is returned from the methods so callers can chain further actions
or handle errors as needed.
| usernames.split(",").each do |username| | ||
| if user = User.find_by_username(username) | ||
| group.add(user) | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Optimize user lookup and clarify assignment
The current implementation makes N database queries. Consider optimizing with a single query. Also, add parentheses to clarify the assignment.
usernames.split(",").each do |username|
- if user = User.find_by_username(username)
+ if (user = User.find_by_username(username))
group.add(user)
end
endFor better performance with many usernames:
users = User.where(username: usernames.split(",").map(&:strip))
users.each { |user| group.add(user) }🧰 Tools
🪛 RuboCop (1.76.1)
[warning] 72-72: Use == if you meant to do a comparison or wrap the expression in parentheses to indicate you meant to assign in a condition.
(Lint/AssignmentInCondition)
🤖 Prompt for AI Agents
In app/controllers/admin/groups_controller.rb around lines 71 to 75, the code
performs a database query for each username in the list, causing N queries. To
optimize, split the usernames string by commas, strip whitespace, and perform a
single query using User.where with the array of usernames. Then iterate over the
resulting users to add them to the group. Also, add parentheses around the
assignment in the if condition to clarify it or refactor to avoid assignment
inside the condition.
| end | ||
|
|
||
| it "is a subclass of AdminController" do | ||
| (Admin::GroupsController < Admin::AdminController).should == true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Update deprecated RSpec syntax
Replace deprecated should syntax with modern expect syntax.
- (Admin::GroupsController < Admin::AdminController).should == true
+ expect(Admin::GroupsController < Admin::AdminController).to eq(true)🤖 Prompt for AI Agents
In spec/controllers/admin/groups_controller_spec.rb at line 10, the test uses
the deprecated RSpec `should` syntax to check inheritance. Replace this with the
modern `expect` syntax by using `expect(Admin::GroupsController <
Admin::AdminController).to eq(true)` to ensure compatibility with current RSpec
standards.
| response.status.should == 200 | ||
| ::JSON.parse(response.body).keep_if {|r| r["id"] == group.id }.should == [{ | ||
| "id"=>group.id, | ||
| "name"=>group.name, | ||
| "user_count"=>1, | ||
| "automatic"=>false, | ||
| "alias_level"=>0, | ||
| "visible"=>true | ||
| }] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Update all deprecated RSpec syntax in index context
Replace all instances of deprecated should syntax with modern expect syntax.
xhr :get, :index
- response.status.should == 200
- ::JSON.parse(response.body).keep_if {|r| r["id"] == group.id }.should == [{
+ expect(response.status).to eq(200)
+ expect(::JSON.parse(response.body).keep_if {|r| r["id"] == group.id }).to eq([{
"id"=>group.id,
"name"=>group.name,
"user_count"=>1,
"automatic"=>false,
"alias_level"=>0,
"visible"=>true
- }]
+ }])🤖 Prompt for AI Agents
In spec/controllers/admin/groups_controller_spec.rb around lines 21 to 29, the
test uses deprecated RSpec `should` syntax for expectations. Replace all
`should` calls with the modern `expect` syntax by wrapping the subject in
`expect()` and using `.to eq` or appropriate matchers instead of `should ==`.
| response.status.should == 200 | ||
|
|
||
| groups = Group.where(name: "bob").to_a | ||
|
|
||
| groups.count.should == 1 | ||
| groups[0].name.should == "bob" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Update deprecated RSpec syntax in create context
- response.status.should == 200
+ expect(response.status).to eq(200)
groups = Group.where(name: "bob").to_a
- groups.count.should == 1
- groups[0].name.should == "bob"
+ expect(groups.count).to eq(1)
+ expect(groups[0].name).to eq("bob")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| response.status.should == 200 | |
| groups = Group.where(name: "bob").to_a | |
| groups.count.should == 1 | |
| groups[0].name.should == "bob" | |
| expect(response.status).to eq(200) | |
| groups = Group.where(name: "bob").to_a | |
| expect(groups.count).to eq(1) | |
| expect(groups[0].name).to eq("bob") |
🤖 Prompt for AI Agents
In spec/controllers/admin/groups_controller_spec.rb around lines 39 to 44, the
RSpec syntax used for expectations is deprecated. Replace the old `should`
syntax with the newer `expect` syntax by changing lines like
`response.status.should == 200` to `expect(response.status).to eq(200)`, and
similarly update the other assertions to use `expect` with appropriate matchers.
| response.should be_success | ||
|
|
||
| group = Group.find(1) | ||
| group.name.should_not == "WAT" | ||
| group.visible.should == true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Update deprecated RSpec syntax in update context
xhr :put, :update, id: 1, name: "WAT", visible: "true"
- response.should be_success
+ expect(response).to be_success
group = Group.find(1)
- group.name.should_not == "WAT"
- group.visible.should == true
+ expect(group.name).not_to eq("WAT")
+ expect(group.visible).to eq(true)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| response.should be_success | |
| group = Group.find(1) | |
| group.name.should_not == "WAT" | |
| group.visible.should == true | |
| xhr :put, :update, id: 1, name: "WAT", visible: "true" | |
| expect(response).to be_success | |
| group = Group.find(1) | |
| expect(group.name).not_to eq("WAT") | |
| expect(group.visible).to eq(true) |
🤖 Prompt for AI Agents
In spec/controllers/admin/groups_controller_spec.rb around lines 53 to 57, the
RSpec syntax used is deprecated. Replace the old `should` syntax with the newer
`expect` syntax by changing `response.should be_success` to `expect(response).to
be_successful`, `group.name.should_not == "WAT"` to `expect(group.name).not_to
eq("WAT")`, and `group.visible.should == true` to `expect(group.visible).to
eq(true)`.
Test 8
Summary by CodeRabbit
New Features
Bug Fixes
Style
Documentation
Tests