【问题标题】:Validate uniqueness of name in a HABTM association验证 HABTM 关联中名称的唯一性
【发布时间】:2016-01-07 23:43:30
【问题描述】:

我有一个 Artist 模型,它在 HABTM 关联中有许多 Albums。虽然我想允许两张不同的专辑具有相同的名称,但我想确保一位艺术家的收藏中没有两张。到目前为止的例子:

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

【问题讨论】:

  • 你可以为这些发布 db/schema.rb 吗?
  • 另外,您可能必须为专辑艺术家使用自定义验证器。我会等着看 db/schema.rb,但这可能是你的解决方案。
  • 在这种情况下,艺术家和专辑都有一个name 属性,并且album_artist 连接模型只有两个ID:album_idartist_id
  • 我就是这么想的。是的,等一下,我会发布答案...
  • 如果有帮助,还提供了架构。

标签: ruby-on-rails validation activerecord model unique


【解决方案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

如果您还没有索引,您可能还想为 name 列添加索引。

【讨论】:

  • 这似乎做到了!非常感谢!您说要在名称列上添加索引。为什么会这样?
  • 没问题。由于您将经常检查该列以进行验证,因此应该有助于在性能方面将其编入索引。
  • 很高兴知道谢谢。另外值得一提的是,我的相册表单当前设置为显示与@album 对象有关的所有错误:&lt;% @album.errors.full_messages.each do |message| %&gt;。我现在如何在视图中包含 AlbumArtist 对象以使此特定消息可见?
  • 你应该可以把errors[:base]改成self.album.errors[:base]
  • 太棒了。乐于助人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
相关资源
最近更新 更多