开发者

ActiveRecord Validations for Models with has_many, belongs_to associations and STI

I have four models:

  • User
  • Award
  • Badge
  • GameWeek

The associations are as follows:

  • User has many awards.
  • Award belongs to user.
  • Badge has many awards.
  • Award belongs to badge.
  • User has many game_weeks.
  • GameWeek belongs to user.
  • GameWeek has many awards.
  • Award belongs to game_week.

Thus, user_id, badge_id and game_week_id are foreign keys in awards table.

Badge implements an STI model. Let's just say it has the following subclasses: BadgeA and BadgeB.

Some rules to note:

The game_we开发者_如何学Pythonek_id fk can be nil for BadgeA, but can't be nil for BadgeB.

Here are my questions:

  1. For BadgeA, how do I write a validation that it can only be awarded one time? That is, the user can't have more than one -- ever.
  2. For BadgeB, how do I write a validation that it can only be awarded one time per game week?


Data model:

In my comprehension, here is your data model (click to enlarge):

Data model http://yuml.me/6afcad62

Migration:

The migration will let you meet your second requirement, at the migration level:

class CreateAwards < ActiveRecord::Migration
  def self.up
    create_table :awards do |t|
      # custom attributes here
      t.string     :name
      t.text       :description
      t.references :user,       :null => false
      t.references :game_week#,  :null => false
      t.references :badge,      :null => false
      t.timestamps
    end
    # a user can be awarded no more than a badge per week
    add_index :awards, [:user_id, :badge_id, :game_week_id], :unique => true
    # a user can be awarded no more than a badge for ever
    #add_index :awards, [:user_id, :badge_id], :unique => true
  end

  def self.down
    drop_table :awards
  end
end

Model:

The model will let you meet both your requirements, at the model level:

class Award < ActiveRecord::Base
  validate_uniqueness_of :user, :badge,
    :if => Proc.new { |award| award.badge === BadgeA }
  validate_uniqueness_of :user, :badge, game_week,
    :unless => Proc.new { |award| award.badge === BadgeA }
  #validate_uniqueness_of :user, :badge, game_week,
  #  :if => Proc.new { |award| award.badge === BadgeB }
end

Note:

I didn't try these snippets, but I think that the idea is here :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜