2016-01-07 36 views
0

我有一个Artist模型,该模型在HABTM关联中有很多Album s。虽然我想允许两张不同的专辑具有相同的名称,但我希望确保一位艺术家的收藏中没有两张专辑。到目前为止,例如:验证HABTM协会中名称的唯一性

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模型,但是当我尝试创建一个新的对象得到这个错误:

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 
+0

你可以发布db/schema.rb这些吗? – GoGoCarl

+0

此外,您可能必须使用自定义验证程序专辑艺术家。我会先等待db/schema.rb,但这可能会成为您的解决方案。 – GoGoCarl

+0

在这种情况下,艺术家和专辑都有'name'属性,album_artist连接模型只有两个ID:'album_id'和'artist_id' –

回答

1

在这种情况下,最简单的方法是把一个自定义验证你的关系模型:

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 

您可能还需要增加一个如果您还没有名称列的索引。

+0

似乎这样做!非常感谢!你说要在名称列上添加一个索引。为什么这样? –

+0

没问题。由于您将要为验证目的检查该列,因此应该通过性能方式帮助将其编入索引。 – GoGoCarl

+0

很高兴知道谢谢。另外值得一提的是,我的相册表单目前已设置为显示所有与@相册对象相关的错误:<%@ album.errors.full_messages.each do | message | %>'。我现在如何在视图中包含'AlbumArtist'对象来使这个特定的消息可见? –