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.