Ok, so how do you let the database enforce the constraint, but still handle duplicate records gracefully? Start with adding the unique index to the database in a migration:
add_index :wishlist_books, [:user_id, :book_id], :unique => trueNow, instead of creating the record directly in the controller, call a method in the model:
current_user.add_book_to_wishlist(book)In the user model, you might have something like this:
# Add a book to the wish list.Don't worry too much about the associations. I'm just trying to show the code somewhat in context. The important part is the exception that is caught.
# This is idempotent. It will just do the right thing if the user tries to
# insert a duplicate record.
# Important: if you call this method, then the next time you load the wish
# list, you must reload to clear the cache. For instance:
wishlist_books.create! do |list_item|
list_item.book = book
rescue ActiveRecord::StatementInvalid => e
raise e unless /Mysql::Error: Duplicate entry/.match(e)
Naturally, this is MySQL specific. I don't know the exact thing to look for with PostgreSQL. However, that's okay. I don't mind using MySQL specific features in my models where it makes sense.