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

Add a way to reach specific training modules and slides via ID numbers #5502

Conversation

gabina
Copy link
Member

@gabina gabina commented Oct 8, 2023

What this PR does

The purpose of this PR is to add:

  • A way to reach a training module by their id.
  • A way to reach an individual slide by their id.

In order to do that, two new routes were added (find_training_module and find_training_slide), as long as their corresponding controllers and specs.

The logic behind the controllers is to redirect the user to the URL for the given training module (/training/library-slug/module-slug) or to the individual slide (/training/library-slug/module-slug/slide-slug).

Closes #4940

Screenshots

After this PR, users are redirected to the training module or slide site.

Screencast.from.08-10-23.23.50.00.webm

Open questions and concerns

… to be able to reach a training module by their id
@gabina gabina marked this pull request as draft October 8, 2023 03:53
@gabina gabina marked this pull request as draft October 8, 2023 03:53
@gabina gabina marked this pull request as draft October 8, 2023 03:53
Comment on lines 20 to 26
FactoryBot.define do
factory :training_slide do
id { 456875}
title { 'How to create a slide' }
slug { 'how-to-create-a-slide' }
end
end
Copy link
Member Author

Choose a reason for hiding this comment

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

Added this because I want to test the behavior for an orphan slide (one that doesn't belong to any module).

@gabina gabina marked this pull request as ready for review October 9, 2023 02:52
@gabina gabina changed the title Add a way to reach specific training modules and slides via ID numbers [WIP] Add a way to reach specific training modules and slides via ID numbers Oct 9, 2023
@gabina
Copy link
Member Author

gabina commented Oct 9, 2023

Thanks for approving the workflow. It looks like the new TrainingController specs I added passed. However, CI failed. By taking a look at the failed examples I think it's not related to my changes.

Failed examples:

rspec ./spec/features/article_finder_spec.rb:17 # article finder performs searches and returns results
rspec ./spec/lib/lift_wing_api_spec.rb:10 # LiftWingApi returns the basically the same data as OresApi
rspec ./spec/lib/lift_wing_api_spec.rb:20 # LiftWingApi handles TextDeleted revs similarly
rspec ./spec/lib/ores_api_spec.rb:29 # OresApi#get_revision_data fetches json from ores.wikimedia.org for wikipedia
rspec ./spec/lib/ores_api_spec.rb:37 # OresApi#get_revision_data fetches json from ores.wikimedia.org for wikidata
rspec ./spec/lib/ores_api_spec.rb:46 # OresApi#get_revision_data handles many revisions per request for wikipedia
rspec ./spec/lib/ores_api_spec.rb:53 # OresApi#get_revision_data handles many revisions per request for wikidata
rspec ./spec/lib/replica_spec.rb:88 # Replica API requests returns a list of existing articles

Edit: ragesoss told me I can ignore those ^^

training_module = find_module_from_slide_slug(training_slide.slug)
raise ActionController::RoutingError, 'module not found' unless training_module
training_library = find_library_from_module_slug(training_module.slug)
raise ActionController::RoutingError, 'library not found' unless training_library
Copy link
Member

Choose a reason for hiding this comment

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

It's possible to have a module that is not in any library, and it would render if you visited a path that had any valid training library slug. (You can view a module from one library even if you substitute the slug from another library.)

It would be good to find the library as you do here, but if no library is found, it would be better to use TrainingLibrary.first as a fallback instead of throwing a 404.

Copy link
Member Author

Choose a reason for hiding this comment

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

hmm interesting. That behavior is not so intuitive I guess.

I changed the logic for the controllers and updated specs on fbb894f

Note that the new definitions may result in failure if no library exists. In such a scenario, calling TrainingLibrary.first would return nil, causing an error when attempting to access the slug.
Not sure if a world with no libraries makes sense, or it is not worth considering this case and we can suppose TrainingLibrary.first is always well defined.
It looks like modules and slides render even using a non-existing library slug, so we could use a literal string
'mylibrary' as default library slug value if no libraries at all.
What's your opinion here?

# Given a module slug, it returns the first library that has a
# category including that module slug. It returns nil if no such
# library is found.
def find_library_from_module_slug(module_slug)
Copy link
Member

Choose a reason for hiding this comment

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

I think both of these helper methods would make more sense as instance methods of TrainingSlide and TrainingModule respectively.

Copy link
Member Author

@gabina gabina Oct 10, 2023

Choose a reason for hiding this comment

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

Yep, agreed. I made all your suggested changes on 54f8848

end
end

# Given a slide slug, it returns the first module including it.
Copy link
Member

Choose a reason for hiding this comment

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

As a TrainingSlide instance method, you could implement this as

TrainingModule.all.detect { |tm| tm.slide_slugs.include? slug }

Copy link
Member Author

Choose a reason for hiding this comment

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

Much more idiomatic, I like it!

@ragesoss
Copy link
Member

ragesoss commented Oct 9, 2023

This looks great overall.

# category including that module slug. It returns nil if no such
# library is found.
def find_library_from_module_slug(module_slug)
TrainingLibrary.all.find_each do |library|
Copy link
Member

Choose a reason for hiding this comment

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

For this method, I would suggest implementing TrainingLibrary#training_module_slugs (for example:

  def training_module_slugs
    categories.map do |cat|
      cat['modules'].map { |mod| mod['slug'] }
    end.flatten
  end

)

and then using that to implement TrainingModule#library:

TrainingLibrary.all.detect { |tl| tl.training_module_slugs.include? slug }

Comment on lines +162 to +166
# Returns a specific training library for the module,
# or a default library if it is not found.
def find_or_default_library
find_library_by_slug || TrainingLibrary.first
end
Copy link
Member Author

@gabina gabina Oct 10, 2023

Choose a reason for hiding this comment

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

I created this method only to avoid code duplication in controllers.

Alternatively, I guess I could define just something like this:

  # Returns the first library that has a category including the module slug,
  # or a default library if it is not found.
  def find_library_by_slug_or_default
    TrainingLibrary.all.detect(-> { TrainingLibrary.first }) { |tl| tl.training_module_slugs.include? slug }
  end

@gabina gabina requested a review from ragesoss October 10, 2023 16:20
@ragesoss
Copy link
Member

Nice work!

@ragesoss ragesoss merged commit d1a587b into WikiEducationFoundation:master Oct 10, 2023
1 check failed
@gabina gabina deleted the AddFunctionalityToReachSpecificTrainingModulesAndSlidesViaIDNumbers branch October 10, 2023 19:48
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.

Add a way to reach specific training modules and slides via ID numbers
2 participants