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

时间:2021-10-27 17:01:09

I have badges (sorta like *).

我有徽章(有点像*)。

Some of them can be attached to badgeable things (e.g. a badge for >X comments on a post is attached to the post). Almost all come in multiple levels (e.g. >20, >100, >200), and you can only have one level per badgeable x badge type (= badgeset_id).

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

To make it easier to enforce the one-level-per-badge constraint, I want badgings to specify their badge by a two-column foreign key - badgeset_id and level - rather than by primary key (badge_id), though badges does have a standard primary key too.

为了更容易实施每个徽章的一级约束,我希望徽章通过两列外键 - badgeset_id和level - 而不是主键(badge_id)来指定徽章,尽管徽章确实有标准主键也是。

In code:

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

How I can specify a belongs_to association that does that (and doesn't try to use a badge_id), so that I can use the has_many :through?

我如何指定执行该操作的belongs_to关联(并且不尝试使用badge_id),以便我可以使用has_many:through?

ETA: This partially works (i.e. @badging.badge works), but feels dirty:

ETA:这部分有效(即@ badging.badge有效),但感觉很脏:

belongs_to :badge, :foreign_key => :badgeset_id, :primary_key => :badgeset_id, :conditions => 'badges.level = #{level}'

Note that the conditions is in single quotes, not double, which makes it interpreted at runtime rather than loadtime.

请注意,条件是单引号,而不是double,这使得它在运行时而不是加载时进行解释。

However, when trying to use this with the :through association, I get the error undefined local variable or method 'level' for #<User:0x3ab35a8>. And nothing obvious (e.g. 'badges.level = #{badgings.level}') seems to work...

但是,当尝试使用:through关联时,我得到错误未定义的局部变量或# <0x3ab35a8>

<>>>>>>>>>>><>>>><>>>>>>>>>>


  

>>>>>><>>>><>>>>>


  

>>>>>><>>>><>>>>>