Tôi có các huy hiệu (sắp xếp như StackOverflow).Nhiều khóa/liên kết ngoài của cột trong ActiveRecord/Rails
Một số trong số đó có thể được đính kèm với những thứ có thể gây hại (ví dụ: huy hiệu cho> nhận xét X trên bài đăng được đính kèm vào bài đăng). Hầu như tất cả đều có nhiều cấp độ (ví dụ:> 20,> 100,> 200) và bạn chỉ có thể có một cấp cho mỗi loại huy hiệu x có thể xáo trộn (= badgeset_id
).
Để làm cho nó dễ dàng hơn để thực thi các chế một cấp mỗi huy hiệu, tôi muốn badgings để xác định huy hiệu của họ bằng một hai cột nước ngoài chủ chốt - badgeset_id
và level
- chứ không phải bằng khóa chính (badge_id
), mặc dù phù hiệu cũng có khóa chính chuẩn.
Trong mã:
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
Làm thế nào tôi có thể chỉ định một hiệp hội belongs_to
nào đó (và không cố gắng sử dụng một badge_id
), vì vậy mà tôi có thể sử dụng has_many :through
?
ETA: Đây một phần hoạt động (ví dụ: @ badging.badge hoạt động), nhưng cảm thấy bẩn:
belongs_to :badge, :foreign_key => :badgeset_id, :primary_key => :badgeset_id, :conditions => 'badges.level = #{level}'
Lưu ý rằng các điều kiện là trong đơn dấu ngoặc kép, không tăng gấp đôi, mà làm cho nó giải thích tại thời gian chạy khá hơn thời gian tải.
Tuy nhiên, khi cố gắng sử dụng điều này với: thông qua liên kết, tôi nhận được lỗi undefined local variable or method 'level' for #<User:0x3ab35a8>
. Và không có gì rõ ràng (ví dụ: 'badges.level = #{badgings.level}'
) dường như hoạt động ...
ETA 2: Lấy mã của EmFi và làm sạch nó một chút. Nó yêu cầu thêm badge_set_id
vào Huy hiệu, là thừa, nhưng tốt.
Mã:
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
Trong khi làm việc này - và nó có thể là một giải pháp tốt hơn - Tôi không coi đây là một câu trả lời thực tế cho câu hỏi làm thế nào để làm một) khóa ngoại đa-key, hoặc b) các hiệp hội điều kiện động hoạt động với: thông qua các hiệp hội. Vì vậy, nếu có ai có một giải pháp cho điều đó, xin vui lòng lên tiếng.
Điều đó hoạt động, nhiều hơn hoặc ít hơn. Nó không hoàn toàn là câu trả lời cho câu hỏi, mặc dù nó là một câu trả lời cho vấn đề, và tôi tin nó như vậy. Tôi đã xóa mã của bạn và đặt mã đó vào câu hỏi. – Sai
Tôi biết. Những gì bạn đang yêu cầu dường như vượt xa những gì dễ dàng thực hiện với Rails. Bạn đã tìm các plugin chưa? Trong nháy mắt, http://compositekeys.rubyforge.org/ có vẻ như nó có thể làm những gì bạn đang tìm kiếm. – EmFi