views:

241

answers:

1

I just got referred to stackoverflow by a friend here to help with a problem I am having. I am fairly new to ruby on rails and I am working on a collaborative project where we have a script (medal_worker.rb) that is scheduled to run at a fixed intervals to award people various medals based on various participation and success on our website. One of the new medals I am working on rewards people for "milestones". For the purpose of this problem, let's say we want to give them medals when they make 100, 1000, and 10000 comments. I would like to do this by using named_scopes from the User model (user.rb) to give me filtered lists of the users I am looking for.

*My question is: How do I find the users who do not have the respective medals for the respective milestone comment level (preferably using the named_scopes from the User model)?*

Here is an exerpt from my model_worker.rb file:

def award_comment_milestone(comments)
   users = Users.frequent_comment_club_members(comments).not_awarded_medal(Medal.find_by_id(medal.id))
   for user in users do
      award_medal(medal, nil, user) if @award
   end
end

Here is where I am at with the named_scopes in the user model (user.rb):

named_scope :frequent_comment_club_members, lambda { |*args|
        {:include => comment_records, :conditions => ['comment_records.comment_type = ? and comment_records.comments >= ?', 'User', (args.first || 0)]}
}

named_scope :not_awarded_medal, lambda { |medal|
    {:include => :awards, :conditions => ['awards.medal_id not in (select awards.medal_id from awards where awards.medal_id = ?)", medal.id] }
}

This is not working as I would like, but I don't know if the problem is in the named_scopes or how I am passing arguements or what. Thanks.

+1  A: 

Your named_scopes look fine. Except you are starting with a single apostrophe and ending with a double apostrophe in the not_awarded_medal condition statement.

EDIT:

Take it back. Your not_awarded_medal named_scope is off.

Try something like this:

named_scope :not_awarded_medal, lambda { |medal_id|
  { :include => :awards,
    :conditions => [
      "? not in (select awards.id from awards where awards.user_id = users.id)", medal_id
    ]
  }
}

untested

Now this is assuming that you have the following relationships:

User: has_many :awards Award: belongs_to :user

If you are using has_many :through then you are going to have to change the SQL to look at the join (users_awards) table.

--

But I do see a couple of things in the award_comment_milestone function.

What is the parameter coming into award_comment_milestone? Is it an array of comments or is it a count of comments? Also where is medal defined?

If comments is an array then you need to pass comments.length into frequent_comment_club_members. If it's the count then I would rename it to comments_count so the next person can understand the logic more quickly.

Some general observations:

  • not_awarded_medal should just take a medal_id and not the whole object (no need to do multiple queries)
  • Why are you doing Medal.find_by_id(medal.id)? You already have the medal object.
Tony Fontenot
Thanks for the quick feedback. The single quote vs. the double quote is probably how I typed code here, but good observation.Regarding the parameter passed into award_comment_milestone, I didn't specify but this function gets called three times each time passing in one of three values (100, 1000, 10000) for different milestones to check. Assuming 100 is passed in, I want to find the number of users who have more than 100 comments, but not yet awarded the medal for this milestone (same for 1000 and 10000). Perhaps calling it comment_count or comment_milestone vs. comments is good idea.
jadavis
See my edit. I think you have issues with the `not_awarded_medal` named_scope
Tony Fontenot
thanks for the help
jadavis