Menda nishonlar bor (StackOverflow kabi).
Ulardan ba'zilari nishonli narsalarga biriktirilishi mumkin (masalan, postga > X ta fikr bildirish belgisi postga biriktirilgan). Deyarli barchasi bir nechta darajalarda keladi (masalan, >20, >100, >200) va har bir nishonli x nishon turi uchun faqat bitta darajaga ega boʻlishingiz mumkin (= badgeset_id
).
Har bir nishon uchun bir darajali cheklovni qoʻllashni osonlashtirish uchun nishonlar oʻz nishonlarini asosiy kalit (badge_id
) bilan emas, ikki ustunli tashqi kalit – badgeset_id
va level
bilan belgilashini xohlayman, lekin nishonlarda standart mavjud asosiy kalit ham.
Kodda:
class Badge < ActiveRecord::Base
has_many :badgings, :dependent => :destroy
# integer: badgeset_id, level
validates_uniqueness_of :badgeset_id, :scope => :level
end
class Badging < ActiveRecord::Base
belongs_to :user
# integer: badgset_id, level instead of badge_id
#belongs_to :badge # <-- how to specify?
belongs_to :badgeable, :polymorphic => true
validates_uniqueness_of :badgeset_id, :scope => [:user_id, :badgeable_id]
validates_presence_of :badgeset_id, :level, :user_id
# instead of this:
def badge
Badge.first(:conditions => {:badgeset_id => self.badgeset_id, :level => self.level})
end
end
class User < ActiveRecord::Base
has_many :badgings, :dependent => :destroy do
def grant badgeset, level, badgeable = nil
b = Badging.first(:conditions => {:user_id => proxy_owner.id, :badgeset_id => badgeset,
:badgeable_id => badgeable.try(:id), :badgeable_type => badgeable.try(:class)}) ||
Badging.new(:user => proxy_owner, :badgeset_id => badgeset, :badgeable => badgeable)
b.level = level
b.save
end
end
has_many :badges, :through => :badgings
# ....
end
has_many :through
dan foydalanishim uchun buni amalga oshiradigan (va badge_id
dan foydalanishga urinmaydigan) belongs_to
assotsiatsiyasini qanday belgilashim mumkin?
ETA: Bu qisman ishlaydi (masalan, @badging.badge ishlaydi), lekin o'zini iflos his qiladi:
belongs_to :badge, :foreign_key => :badgeset_id, :primary_key => :badgeset_id, :conditions => 'badges.level = #{level}'
E'tibor bering, shartlar ikki emas, balki bitta qo'shtirnoq ichida, bu esa uni yuklanish vaqtida emas, balki ish vaqtida izohlaydi.
Biroq, buni :through assotsiatsiyasi bilan ishlatmoqchi bo'lganimda, men undefined local variable or method 'level' for #<User:0x3ab35a8>
xatosini olaman. Va hech narsa aniq emas (masalan, 'badges.level = #{badgings.level}'
) ishlayotganga o'xshaydi ...
ETA 2: EmFi kodini olish va uni biroz tozalash ishlaydi. Bu Badgega badge_set_id
qo'shishni talab qiladi, bu ortiqcha, lekin yaxshi.
Kod:
class Badge < ActiveRecord::Base
has_many :badgings
belongs_to :badge_set
has_friendly_id :name
validates_uniqueness_of :badge_set_id, :scope => :level
default_scope :order => 'badge_set_id, level DESC'
named_scope :with_level, lambda {|level| { :conditions => {:level => level}, :limit => 1 } }
def self.by_ids badge_set_id, level
first :conditions => {:badge_set_id => badge_set_id, :level => level}
end
def next_level
Badge.first :conditions => {:badge_set_id => badge_set_id, :level => level + 1}
end
end
class Badging < ActiveRecord::Base
belongs_to :user
belongs_to :badge
belongs_to :badge_set
belongs_to :badgeable, :polymorphic => true
validates_uniqueness_of :badge_set_id, :scope => [:user_id, :badgeable_id]
validates_presence_of :badge_set_id, :badge_id, :user_id
named_scope :with_badge_set, lambda {|badge_set|
{:conditions => {:badge_set_id => badge_set} }
}
def level_up level = nil
self.badge = level ? badge_set.badges.with_level(level).first : badge.next_level
end
def level_up! level = nil
level_up level
save
end
end
class User < ActiveRecord::Base
has_many :badgings, :dependent => :destroy do
def grant! badgeset_id, level, badgeable = nil
b = self.with_badge_set(badgeset_id).first ||
Badging.new(
:badge_set_id => badgeset_id,
:badge => Badge.by_ids(badgeset_id, level),
:badgeable => badgeable,
:user => proxy_owner
)
b.level_up(level) unless b.new_record?
b.save
end
def ungrant! badgeset_id, badgeable = nil
Badging.destroy_all({:user_id => proxy_owner.id, :badge_set_id => badgeset_id,
:badgeable_id => badgeable.try(:id), :badgeable_type => badgeable.try(:class)})
end
end
has_many :badges, :through => :badgings
end
Bu ishlayotgan bo'lsa-da - va bu yaxshiroq yechim bo'lsa-da, men buni a) ko'p kalitli tashqi kalitlar yoki b) assotsiatsiyalar orqali ishlaydigan dinamik shartli assotsiatsiyalar qanday qilish kerakligi haqidagi savolga haqiqiy javob deb hisoblamayman. Shunday ekan, kimdir bunga yechim topsa, ayting.