Is this the best way to find the user_activity inside the show method?

Basically a user joins a challenge. Each challenge has a goal like 300000 steps in 30 days. I want keep a track on the user of his daily activities for the next 30 days.

Is this the best design and also is this the right show method in the challenges controller ?

The show method is called when the current_user clicks on a particular challenge.

  def show
      @challenge = Challenge.find(params[:id])
      @user_activity = UserActivity.find_by(user:current_user,challenge:@challenge)
    end
User 
 has_many :user_activities
 has_many :challenges, through: :user_activities

class Challenge < ActiveRecord::Base
	has_many :user_activities
  has_many :user, through: :user_activities

class UserActivity < ActiveRecord::Base
	belongs_to :challenge
	belongs_to :user

I would try to keep as much logic out of the controller as possible. In that vein I would do something like:

class ChallengesController < ApplicationController
...
  def show
    @challenge = Challenge.find(params[:id])
    @user_activity = @challenge.activity_for(current_user)
  end
...
end

User < ActiveRecord::Base
  has_many :user_activities
  has_many :challenges, through: :user_activities
  ...
end

class Challenge < ActiveRecord::Base
  has_many :user_activities
  has_many :user, through: :user_activities

  def activity_for(user)
    self.user_activities.where(user: user)
  end
  ...
end

class UserActivity < ActiveRecord::Base
  belongs_to :challenge
  belongs_to :user
  ...
end

The activity_for method will call self (in this case, @challenge), then get the user_activities for that challenge where the user is current_user.

1 Like

Thanks but could you explain me the different between having putting activity_for method in the user class vs putting in the challenge class.

I am trying to find the user_activity that is related to the current_user and the @challenge.

Also I was doing a find and you did a where so doesnt where scan the whole total? I could go and put an index on [user_id,challenge_id]

Putting the activity_for on the user vs challenge class is a matter of preference. I put it on the challenge class so I could call it on @challenge.

In terms of indices, [user_id,challenge_id] isnā€™t a bad one. Generally you want to put indices on all your relationships. Is the request slow?

Otherwise the code will provide the user_activities that is related to the current_user and the @challenge as expected.

Also using where will return all the models that match the condition. Using find will only return the first model it finds. So while find would technically be quicker, you want to use where if you want all the user_activites. It seems like you wouldnā€™t just want the first one.

Actually at one time user can participate in many challenges at the same like Walking Challenge, Cycling Challenge, Diet Challenge. But for each challenge there can be only on UserActivity.

So Charlie has joined the challengge WalkingChallenge and User Activity for that challenge keeps a track on Charlieā€™s daily actiivity.