验证HABTM关联中名称的唯一性

验证HABTM关联中名称的唯一性

本文介绍了验证HABTM关联中名称的唯一性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Artist模型,在HABTM关联中有很多Album.尽管我想允许两张不同的专辑使用相同的名称,但我想确保一位艺术家的收藏中没有两张专辑.到目前为止的示例:

I have an Artist model that has many Albums in a HABTM association. Though I would like to permit two different albums to have the same name I'd like to ensure that there aren't two in the collection of one artist. So far example:

artist_1 = Artist.create(name: "Jay-Z")
artist_2 = Artist.create(name: "The Beatles")

album_1 = Album.create(name: "The Black Album", artist_ids: [1])

album_2 = Album.create(name: "The Black Album", artist_ids: [1])
=> Should return error

album_2 = Album.create(name: "The Black Album", artist_ids: [2])
=> Should not return an error

我首先想到了在Album模型中验证名称的唯一性,但是在尝试创建新对象时出现此错误:

I first thought of validating the uniqueness of the name in the Album model but get this error when I try to create a new object:

SQLite3::SQLException: no such column: albums.artist_id: SELECT 1 AS one FROM "albums" WHERE ("albums"."name" = 'The Black Album' AND "albums"."artist_id" IS NULL) LIMIT 1

然后我想到了将验证放入连接模型AlbumArtist中,但出现错误undefined method 'name'(name是相册的属性之一):

I then thought of putting the validation in my join model, AlbumArtist but get the error undefined method 'name' (name is one of the album's attributes):

undefined method `name' for #<AlbumArtist:0x007f8e1fc335e8>

如何使它正常工作?

class Album < ActiveRecord::Base
    has_many :album_artists
    has_many :artist, through: :album_artists
end

class AlbumArtist < ActiveRecord::Base
  belongs_to :album
  belongs_to :artist

  # validates_uniqueness_of :name, scope: [:artist_id]
end

class Artist < ActiveRecord::Base
  has_many :album_artists
  has_many :albums, through: :album_artists

  # validates_uniqueness_of :name, scope: [:artist_id]
end

架构

create_table "albums", force: :cascade do |t|
  t.string   "name"
end

create_table "album_artists", force: :cascade do |t|
  t.integer  "album_id"
  t.integer  "artist_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

add_index "album_artists", ["album_id"], name: "index_album_artists_on_album_id"
add_index "album_artists", ["artist_id"], name: "index_album_artists_on_artist_id"

create_table "artists", force: :cascade do |t|
  t.string   "name"
end

推荐答案

在这种情况下,最直接的方法是在关系模型中放置自定义验证器:

The most straightforward way in this case would be to put a custom validator in your relation model:

class AlbumArtist < ActiveRecord::Base
  belongs_to :album
  belongs_to :artist

  validates_presence_of :album, :artist

  validate :ensure_unique, on: :create

  private

  def ensure_unique
    if self.artist.albums.where(name: self.album.name).any?
      errors[:base] << 'Artist already has an album by this name'
    end
  end
end

如果还没有索引,您可能还想在名称列中添加索引.

You may also want to add an index to the name column if you don't already have one.

这篇关于验证HABTM关联中名称的唯一性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 21:30