验证 HABTM 关联中名称的唯一性
Validate uniqueness of name in a HABTM association
我有一个 Artist
模型,它在 HABTM 协会中有很多 Album
。虽然我想允许两张不同的专辑同名,但我想确保一位艺术家的 collection 中没有两张专辑。到目前为止的例子:
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
模型中名称的唯一性,但是当我尝试创建新的 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
是相册的属性之一):
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
在这种情况下,最直接的方法是在您的关系模型中放置一个自定义验证器:
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
如果您还没有索引,您可能还想为名称列添加一个索引。
我有一个 Artist
模型,它在 HABTM 协会中有很多 Album
。虽然我想允许两张不同的专辑同名,但我想确保一位艺术家的 collection 中没有两张专辑。到目前为止的例子:
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
模型中名称的唯一性,但是当我尝试创建新的 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
是相册的属性之一):
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
在这种情况下,最直接的方法是在您的关系模型中放置一个自定义验证器:
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
如果您还没有索引,您可能还想为名称列添加一个索引。