问题描述
我有一个Artist
模型,在HABTM关联中有很多Album
.尽管我想允许两张不同的专辑使用相同的名称,但我想确保一位艺术家的收藏中没有两张专辑.到目前为止的示例:
I have an Artist
model that has many Album
s 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关联中名称的唯一性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!