3

I'm trying to implement a unique constraint on a has_and_belongs_to_many relationship like so:

class User
  has_and_belongs_to_many :foos, uniq: true
end

Because I only want unique foos when I call user.foos, I added the uniq option. Since upgrading to Rails 4 I've started to get the following warning:

DEPRECATION WARNING: The following options in your User.has_and_belongs_to_many :foos declaration are deprecated: :uniq. Please use a scope block instead. For example, the following:

  has_many :spam_comments, conditions: { spam: true }, class_name: 'Comment'

should be rewritten as the following:

  has_many :spam_comments, -> { where spam: true }, class_name: 'Comment'

I've tried a number of different combinations, and read through the source, but can't figure out how to write the unique constraint to remove the warning?

Gavin Miller
  • 43,168
  • 21
  • 122
  • 188
  • Maybe [this](http://stackoverflow.com/questions/16569994/deprecation-warning-when-using-has-many-through-uniq-in-rails-4) could help – AbM Nov 26 '13 at 19:57

1 Answers1

18
class User
  has_and_belongs_to_many :foos, -> { uniq }
end

According to the documentation here

usha
  • 28,973
  • 5
  • 72
  • 93
  • So, but if you use an `after_add` callback it will be repeated every time again – Ivan Black Apr 18 '14 at 15:27
  • I know it's an old answer but commenting anyway. Thanks it works good and adds `DISTINCT` to the generated SQL. But the link you have shows no information for this. – 244an Apr 26 '16 at 22:29
  • 3
    and in rails 5.1 this won't work anymore and should be: `has_and_belongs_to_many : foos, -> { distinct }` – murb Mar 06 '17 at 19:16
  • 1
    Oddly enough, this validation does not appear to preempt database-level constraints. That is, if you also set `add_index :join_table, [:user_id, :foo_id], unique: true` in the migration, and then you write a test/spec to see what happens when you try to add the same `foo` to a given `user` multiple times, the duplicate entry **won't be caught by the data model validation**, getting passed down to the database and raising an error. If anyone has any insight, I'd be glad to hear it. – Ryan Lue Jul 07 '17 at 11:11
  • 1
    @RyanLue I believe that's because the uniq/distinct only impacts what's requested from the database, and not the behavior of the model that's being saved into it. [discussion in this q/a](https://stackoverflow.com/q/1129781/4096667) – A C Aug 08 '17 at 19:45