배지가 있습니다 (예 : StackOverflow와 유사).ActiveRecord/Rails의 복수 열 외래 키/연결
일부는 badgeable 물건에 첨부 할 수 있습니다 (예 : 게시물의 X 코멘트에 대한 배지가 게시물에 첨부 됨). 거의 모두 여러 수준 (예 :> 20,> 100,> 200)으로 표시되며 배지 가능 x 배지 유형 (= badgeset_id
) 당 하나의 수준 만 가질 수 있습니다. , 배지하지만 오히려 기본 키 (badge_id
)보다는 - badgeset_id
및 level
-
내가 badgings은 2 열 외부 키에 의해 자신의 배지를 지정하려면, 그것은 쉽게 한 레벨 당 배지 제약 조건을 적용 할 수 있도록 표준 기본 키가 너무 있습니다. 코드에서
: 나는이 has_many :through
을 사용할 수 있도록
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
나는 것을 않습니다 (그리고 badge_id
를 사용하려고하지 않습니다)를 belongs_to
연결을 지정할 수 있습니까?
ETA : 이것은 부분적으로 (즉, @ badging.badge 작동) 작동하지만, 더러운 느낌 : 조건이 단일 따옴표, 오히려 런타임에 해석하게하는, 두 번하지를 것을
가belongs_to :badge, :foreign_key => :badgeset_id, :primary_key => :badgeset_id, :conditions => 'badges.level = #{level}'
주 로드 타임보다
그러나 : through 연결과 함께 사용하려고하면 undefined local variable or method 'level' for #<User:0x3ab35a8>
오류가 발생합니다. 그리고 확실한 것은 없습니다 (예 : 'badges.level = #{badgings.level}'
). 작동하지 않는 것 같습니다 ...
2 번 : EmFi의 코드를 작성하여 조금만 청소하면됩니다. 배지에 badge_set_id
을 추가해야합니다. 중복되었지만 잘되었습니다.
코드 :이 작동하는 동안
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
는 - 그것은 아마도 더 나은 솔루션입니다 - 나는) 멀티 키 외래 키 작업을 수행하는 방법에 대한 질문이 실제 답을 고려하지 않거나 b) 연관 관계를 통해 작동하는 동적 조건 연결. 그래서 누군가가 그 해결책을 가지고 있다면, 위로 말하십시오.
다소 효과가 있습니다. 이 질문에 대한 대답은 아니지만 문제의 해답이 될 수 있습니다. 나는 코드를 정리하고 질문에 넣었습니다. – Sai
알아. 당신이 묻고있는 것은 Rails로 쉽게 할 수있는 것을 넘어서는 것처럼 보였습니다. 플러그인을 찾았습니까? 한눈에, http://compositekeys.rubyforge.org/는 당신이 찾고있는 것을 할 수있는 것처럼 보입니다. – EmFi