Skip to content
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

Refactor how Rails handles filter categories passed to and from Vue #546

Merged
merged 14 commits into from
May 15, 2021

Conversation

h-m-m
Copy link
Collaborator

@h-m-m h-m-m commented Jun 27, 2020

Why

The contribution filtering works nicely, but difficult to understand. We'd like to add new filters, and that's hard at the moment. I wrote the original code and am unhappy with how confusing it is. Its confusing complexity is what makes adding or editing filters more difficult for us, and also slows down bringing people into the project and up to speed on how all this stuff works.

What

The big change is making each type of filter its own class.
Each class

  • accepts an ActiveRecord relation
  • knows how to filter that relation by request parameters passed from the controller

Also used this opportunity to:

  • make the controller code easier to follow
  • simplify the logic around conditionally passing links to the frontend (do we show the link to contact someone? does the user have permission to see this?
  • work on our nomenclature for clarity & simplicity

And hopefully this will make adding new filters easier in the future

Testing

Updated some tests. Could probably use more work in this regard

Next Steps

Some next steps are already called out in the comments when this PR was in Draft status.
Also: add a filter for Date now that it should be easier to do so

Accessibility

We were very careful to leave the existing UI unchanged in any visible way, so this should be accessibility-neutral

Security

Hopefully this improves the security what with less dynamic/functional code and code that's easier for future devs to maintain

Pre-Merge Checklist

  • Security & accessibility have been considered
  • Tests have been added, or an explanation has been given why the features cannot be tested
  • Documentation and comments have been added to the codebase where required
  • Entry added to CHANGELOG.md if appropriate
  • Outstanding questions and concerns have been resolved
  • Any next steps have been turned into Issues or Discussions as appropriate

Copy link
Collaborator Author

@h-m-m h-m-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now functional

TODO:

  • add tests
  • check if everyone feels this is legible enough
  • add additional filters (maybe in a separate PR)
  • discuss sorting results on the Vue side

I added a bunch of comments. Please suggest cleanup/rewording/etc. of them, whatever would help you understand the code better

Sorry, @maebeale, for the flipping back and forth about what goes in instances and what goes in classes. I added on to your work some of the structure I thought @exbinary was interested in, but I might have misremembered that whole conversation

def scopes
classes = parameters.blank? ? ALL_ALLOWED_TYPES : parameters.keys
classes.intersection(ALL_ALLOWED_TYPES).map do |type|
type.constantize.matchable
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right — that matchable is what we want here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. we'll need to add that scope to CommunityResource to return objects that are still published

Copy link
Collaborator

@solebared solebared left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, @h-m-m ! A few comments inline but overall really like how this is shaping.

app/blueprints/filter_options_blueprint.rb Outdated Show resolved Hide resolved
app/blueprints/filter_options_blueprint.rb Outdated Show resolved Hide resolved
app/models/browse_filter.rb Outdated Show resolved Hide resolved

def filter(scope)
return super unless parameters
scope.joins(:person).where(people: { preferred_contact_method: parameters.keys })
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm noticing all the filters use parameters.keys. Could we get the keys in BrowseFilter or BaseFilter.new and make just the keys available to individual filters?

Relatedly, the shape of parameters is not clear from looking at the code. Could be solved by looking at specs, or maybe a comment describing how params will come in?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the shape of parameters is not clear from looking at the code

This is really the key point here. Thanks for surfacing this, because this point is helping me find the most confusing points.

I started writing some tests around this and got stuck because it was hard. I think I've introduced a small, modest mess in BrowseFilter#contributions and cleaning up the parameters structure here is dependent on cleaning that up, too.

There's a part of me that wants to get this PR out first and then focus on cleaning up that problem. I want to do that because this PR has taken a very long time and not directly for any code-specific reasons. This PR seems so big to me already, and I'd really like to focus on the refactor I'll need here as a separate thing from the other changes in this PR.

I'm open to suggestions. Let me know what you think

Comment on lines 3 to 7
{
name: "Categories",
# Currently only filtering by top-level categories
filters: FilterOptionsBlueprint.render_as_hash(Category.roots)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serializing inside the filters doesn't feel quite right. Is it possible to have options return a relation as the value of filters and let the controller handle serialization?

Suggested change
{
name: "Categories",
# Currently only filtering by top-level categories
filters: FilterOptionsBlueprint.render_as_hash(Category.roots)
}
{
name: "Categories",
# Currently only filtering by top-level categories
filters: Category.roots
}

This might require introducing another blueprint at the level of a filter that then has an association :filters.

Copy link
Collaborator Author

@h-m-m h-m-m Apr 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only issue with your suggestion is that the Ask/Offer distinction is one I'm doing manually:

class ContributionTypeFilter
def self.filter_group
{ name: 'Contribution Types', filter_options: [
{ id: 'ContributionType[Ask]', name: 'Ask' },
{ id: 'ContributionType[Offer]', name: 'Offer' }
]}
end

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, i see the challenge. I had a go at extracting the serialization out in 8b8c8a9, curious your thoughts?
In any case, i don't think this question should hold up this PR.

app/models/browse_filter.rb Outdated Show resolved Hide resolved
@h-m-m h-m-m force-pushed the filter-by-date branch 2 times, most recently from 0b47685 to 5062a99 Compare April 16, 2021 00:32
@h-m-m h-m-m marked this pull request as ready for review April 16, 2021 00:55
Conflicts:
* CHANGELOG.md
* app/controllers/contributions_controller.rb
* app/models/browse_filter.rb
* app/models/category.rb
* app/models/contribution_type.rb
* spec/blueprints/contribution_blueprint_spec.rb
* spec/blueprints/filter_type_blueprint_spec.rb
Copy link
Collaborator

@solebared solebared left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@h-m-m , i merged main, resolved conflicts and pushed to this branch.
Should be good to merge once you give it a quick look.

app/filters/contribution_type_filter.rb Outdated Show resolved Hide resolved
@h-m-m
Copy link
Collaborator Author

h-m-m commented May 15, 2021

Notes on what we're thinking of following up on as a subsequent refactoring:

  • Removing paramters.keys references in the filters so filter classes can scan the full parameter list as they see fit (comment
  • Move serialization concerns out of the filter classes, perhaps by breaking up filter_grouping in to one method that returns the filter grouping's name and another method that returns the filter options for that filter grouping (comment)

@h-m-m h-m-m merged commit 23600d7 into main May 15, 2021
@h-m-m h-m-m deleted the filter-by-date branch May 15, 2021 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants