从 Rails 添加约束到 table - ActiveRecord

Add constraint to table from Rails - ActiveRecord

我在 Rails 中有两个关联模型。用户,和 Post。

在向 post table 添加一个布尔值列 'Avatar' 时,我想为其所属的用户创建一个唯一的真值。

也就是说用户只能有一个'Avatar' post值为真。这是因为这些posts(图片)可以用作用户头像。

post已经属于用户,而用户有很多post,所以我想设置约束,用户只有一个post,值为对阿凡达来说是真的。此外,如果新头像是 uploaded/selected,则此操作取消并伪造任何以前的头像。

这是我目前的迁移文件:

add_avatar_to_user_profiles.rb

class AddAvatarToUserProfiles < ActiveRecord::Migration
  def change
    add_column :posts, :avatar, :boolean, default: false
  end
end

schema.rb

ActiveRecord::Schema.define(version: 20151018160617) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "comments", force: :cascade do |t|
    t.text     "comment"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "post_id"
    t.integer  "user_id"
  end

  add_index "comments", ["post_id"], name: "index_comments_on_post_id", using: :btree
  add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree

  create_table "posts", force: :cascade do |t|
    t.string   "caption"
    t.integer  "likes"
    t.datetime "created_at",         null: false
    t.datetime "updated_at",         null: false
    t.integer  "user_id"
    t.string   "image_file_name"
    t.string   "image_content_type"
    t.integer  "image_file_size"
    t.datetime "image_updated_at"
  end

  add_index "posts", ["user_id"], name: "index_posts_on_user_id", using: :btree

  create_table "sessions", force: :cascade do |t|
    t.string   "session_id", null: false
    t.text     "data"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", unique: true, using: :btree
  add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree

  create_table "users", force: :cascade do |t|
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.string   "provider"
    t.string   "uid"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
  add_index "users", ["provider"], name: "index_users_on_provider", using: :btree
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
  add_index "users", ["uid"], name: "index_users_on_uid", using: :btree

  add_foreign_key "comments", "posts"
  add_foreign_key "comments", "users"
  add_foreign_key "posts", "users"
end

希望以上内容足以说明问题,我已搜索文档无济于事,我认为解决方案应该足够简单。

您可以像这样在 Post 模型中添加自定义验证器:

# post.rb
validate :unique_post_avatar

private

def unique_post_avatar
  if self.user.posts.select { |p| p.avatar == true }.count > 1
    errors.add(:avatar, "only one post avatar for this user can be true")
  end
end

这实质上是选择头像为真的用户帖子。如果此计数大于 1,则会抛出验证错误。我想这就是您要找的:-)