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.