List enrolled users & show checkmark if all activities are complete
Before looking at the code, there's a simple and immediate option for speeding things up: When a user completes an activity (or a part of one), check the user's other activities, and set an overall completed flag on the user's enrollment accordingly. That way, you only need to check completion for one user at a time and only in connection with an activity update (whereas right now, you check completion for everyone, all the time). Whenever you need to display the list, you'll already have completed boolean values to use.

So that's one way to go.

Now, looking at the code, the first thing I see is a lot of duplication. 

Second thing I see is that you unnecessarily abbreviate stuff. Ironic that "spelling" is spelt "spel"... Really, just write what you mean, and mean what you write. There's no reason whatsoever to abbreviate.

Anyway, duplication: The only thing that differs from method to method is the activity name.

So you could get rid of all the completed_* method, and just do this:

def users_with_completed_activity(name)
  lesson = Lesson.find(params[:id])
  enrolled_users.map do |user|
    current_enrollment = lesson.enrollment_for(user)
    user if current_enrollment.send(name).all?(&amp;:completed?)
  end
end


Note that this:

all? { |x| x.completed == true }


is just checking "is true true?", so it's the same as:

all? { |x| x.completed } 


which, with Ruby's shortcuts, is the same as:

all?(&amp;:completed)


However there's another weird thing going on. You load the Lesson record. Then you call enrolled_users (which also loads the Lesson, by the way), which finds users from their enrollments, and then, for each user, you go back and get their Enrollment.

So:


Fetching the Lesson should probably be extracted into a before_action (Rails' scaffolded controllers include examples of exactly this)
You're getting the enrollments to get the users to get their enrollments... Notice the runaround there?


Sidestepping that, you get something like (assuming Lesson's been set in a before_action):

def users_with_completed_activity?(name)
  @lesson.enrollments.map do |enrollment|
    enrollment.user if enrollment.send(name).all?(&amp;:completed?)
  end
end


Of course, I'm not exactly sure why you want an array with a mix of User records and nils. All it means is that you make it vastly more complicated in the view because you have to use include?. And that's slow, since it has to look through the array every time. So you have a system that'll get exponentially slower the more users you add.

It'd make more sense to send back an array of user/completed pairs:

def users_with_completed_activity?(name)
  @lesson.enrollments.map do |enrollment|
    [enrollment.user, enrollment.send(name).all?(&amp;:completed?)]
  end
end


which you can then step through like:

users_with_completed_activity(:spelling).each do |user, completed|
  # do something
end


Getting a combined completed-all-activities boolean I'll leave to the reader (since this is all just stop-gap improvements anyway - read on).

I'd also ask why the Enrollment is also responsible for tracking activity completion. It's not necessarily wrong, but it doesn't seem the best fit either. Whether or not a user completes an activity doesn't really affect their enrollment. Whether or not you do well, you're presumably still enrolled. But with this structure, that's what happens. So that's a little odd.

Lastly, you have a call to uniq because - for some reason - it seems it's possible for users to be enrolled multiple times? I can't see any other reason. But why would someone be enrolled multiple times? It doesn't make sense in the real world, nor as a software model. How do you know which enrollment to update when an activity is completed? Which enrollment to check?

Now, none of this is likely to make things go much faster. The trouble is still that you're simply doing too much each request. As mentioned in the beginning, the simplest solution would probably be to update a flag on the enrollment, when a user completes an activity. Then that's all you need to check. It's not something that changes very often, so why go through all the motions of figuring it out every time? It's like a bank account balance: If every time you wanted to check your balance, the bank had to sum up all deposits and withdrawals, things would grind to a halt. So it stores the current balance and keeps it up to date.

There are many other ways to go about this (doing more processing in the database layer, doing different data modelling, in-memory caching, etc. etc.) but the simplest one is simply to store the things you need to access often.