Forum: Ruby on Rails We don't need no stinking Badges! Guidance, anyone?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Lake D. (Guest)
on 2009-02-04 21:37
Hi, Thanks for taking a look at this. I am in need of some guidance for
a particular problem:

My Requirements:
The concept of a user
The concept of a badge

A badge is simply a small image over the user's avatar that displays
extra information about the user.
An admin user will be able to assign a badge to any user and the
assigned badge will become the user's current badge, displayed for all
the world to see.

Not required for now but required in the future: a user will be able to
choose from a list of badges and create their own custom badges.


The Way of the Lost:

After toying with these requirements and bits of code for a few days, I
have decided to ask for help.
Please enlighten me on a better, a more rails way of implementing this.
I am truly curious to know. There MUST be a better way!


RELATIONSHIPS:

I decided to implement the requirements by using a HasManyThrough
association.
I have three classes that collaborate: User, Badge, UserBadge

  class User < ActiveRecord::Base
    has_many :user_badges
    has_many :badges, :through => :user_badges
    has_one  :current_badge, :class_name => "UserBadge", :conditions =>
{ :current => true }
  end

  class Badge < ActiveRecord::Base
    # t.string   :title
    # t.string   :image_file_name
    # t.string   :image_content_type
    # t.integer  :image_file_size
    # t.datetime :image_updated_at
    # t.timestamps

    has_many :user_badges
    has_many :users, :through => :user_badges
  end

  class UserBadge < ActiveRecord::Base

    #  t.integer :user_id
    #  t.integer :badge_id
    #  t.boolean :current, :default => false
    #  t.timestamps

    belongs_to :user
    belongs_to :badge
  end

ASSIGNING A CURRENT BADGE:

 I need a way to assign a badge to a user, so I created an attr_accessor
in the User class called :assign_current_badge
 Then, I override the assign_current_badge setter method.

 The assign_current_badge=(badge_id) method:
  * accepts a badge_id as a formal parameter
  * updates any other current user_badges to "current=false" with the
deactivate_badges method
  * checks for existance of a user_badge with the user's id and badge_id
    * setting the user_badge.current to true if it exists
    * creating and setting the user_badge.current to true if it does not
exist
  * sets the user's current_badge_id to the badge_id


 class User < ActiveRecord::Base
  ... # relationships

  attr_accessor :assign_current_badge

  def assign_current_badge=(badge_id)
    deactivate_badges
    if UserBadge.exists?(:user_id => id, :badge_id => badge_id)
      user_badges.find_by_badge_id(badge_id).update_attribute(:current,
true)
    else
      user_badges.create!(:badge => Badge.find(badge_id), :current =>
true)
    end
    self.current_badge_id = badge_id
  end

  def deactivate_badges
    user_badges.update_all("current = 0")
  end
 end

PROBLEMS I HAVE ENCOUNTERED:

  The main problem I encounter is setting the current badge to a blank
value through the user's edit form.
  "Couldn't find Badge with ID=" is being raised since there really is
no badge with a blank id.
  This tells me, obviously, that there is a better way to go about this.
My gut tells me there is something shady about passing in the badge_id
instead of an existing badge object.

  - form_for @user, :url => admin_user_path(@user) do |f|
    = f.error_message
    # ... more fields
    %div
      = f.label :assign_current_badge
      = f.select :assign_current_badge, Badge.all.map {|b| [b.title,
b.id]}, { :selected => @user.current_badge_id, :include_blank => true }
    # ... submit button

Finale:
  If you have any advice for me, please reply. Hopefully I explained my
situation well enough through code and writing. If you would like me to
elaborate on anything, just ask.
Julian L. (Guest)
on 2009-02-05 02:02
(Received via mailing list)
Could you explain your problem more clearly? The rest was beautiful.

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/

On 05/02/2009, at 6:37 AM, Lake D. <rails-mailing-list@andreas-
Harold (Guest)
on 2009-02-05 04:34
(Received via mailing list)
Why do you even need a UserBadge model?

I would have User model, a Badge model, where the relationship is User
belongs_to :badge, and badge has_many :users.

Then you can simply assign it with some_user.badge = some_badge. It
seems like you're adding complexity with the UserBadge model and the
current attribute.

Maybe I'm missing something but looks like, from the requirements
you've outlined, you can drop that model altogether, and keep your
design simple...

-H

On Feb 4, 2:37 pm, Lake D. <removed_email_address@domain.invalid>
This topic is locked and can not be replied to.