gpt4 book ai didi

mysql - ActiveRecord/Rails 中的多列外键/关联

转载 作者:可可西里 更新时间:2023-11-01 06:34:07 25 4
gpt4 key购买 nike

我有徽章(有点像 StackOverflow)。

它们中的一些可以附加到可标记的东西上(例如,一个帖子的 >X 评论的徽章附加到帖子上)。几乎所有都有多个等级(例如 >20、>100、>200),并且每个 badgeable x 徽章类型只能有一个等级 (= badgeset_id)。

为了更容易地执行每个徽章一个级别的约束,我希望徽章通过两列外键指定它们的徽章 - badgeset_idlevel - 而不是通过主键 ( badge_id ),尽管徽章也有一个标准的主键。

在代码中:

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

如何指定 belongs_to这样做的协会(并且不尝试使用 badge_id ),以便我可以使用 has_many :through

预计到达时间:这部分有效(即@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

虽然这可行——而且它可能是更好的解决方案——但我不认为这是对如何执行 a) 多键外键或 b) 使用 :through 的动态条件关联的实际答案协会。因此,如果有人对此有解决方案,请说出来。

最佳答案

如果将 Badge 分成两个模型,似乎它可能会锻炼得最好。以下是我将如何分解它以实现您想要的功能。我加入了一些命名范围以保持实际执行操作的代码干净。

class BadgeSet
has_many :badges
end

class Badge
belongs_to :badge_set
validates_uniqueness_of :badge_set_id, :scope => :level

named_scope :with_level, labmda {|level
{ :conditions => {:level => level} }
}

named_scope :next_levels, labmda {|level
{ :conditions => ["level > ?", level], :order => :level }
}

def next_level
Badge.next_levels(level).first
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
save
end
end

class User < ActiveRecord::Base
has_many :badgings, :dependent => :destroy do
def grant badgeset, level, badgeable = nil
b = badgings.with_badgeset(badgeset).first() ||
badgings.build(
:badge_set => :badgeset,
:badge => badgeset.badges.level(level),
:badgeable => badgeable
)

b.level_up(level) unless b.new_record?

b.save
end
end
has_many :badges, :through => :badgings
# ....
end

关于mysql - ActiveRecord/Rails 中的多列外键/关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1633369/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com