Проверка уникальности значения между несколькими полями - PullRequest
2 голосов
/ 20 апреля 2011

Я понимаю, что проверить уникальность стандартного отдельного поля, такого как "имя пользователя", легко.Однако для чего-то, что имеет неограниченное количество входов, таких как, например, «Любимые фильмы», где пользователь может добавить столько любимых фильмов, это то, что я не могу понять.или удалить поля через компоновщик, но как я могу убедиться, что две или более записей не являются дубликатами?

Ответы [ 6 ]

7 голосов
/ 20 апреля 2011

Я думаю, что самый простой способ сделать что-то подобное - это проверить уникальность чего-либо в области видимости. Я не могу точно сказать, как он будет соответствовать вашему сценарию, поскольку вы не описали ассоциации моделей, но вот пример того, как это может работать в модели FavoriteMovie:

class FavoriteMovie < ActiveRecord::Base
  belongs_to :user

  validates_uniqueness_of :movie_name, :scope => :user_id
end

Это гарантирует, что не может быть двух одинаковых названий фильмов для одного конкретного пользователя.

4 голосов
/ 20 апреля 2011

Оказывается, что при использовании вложенных атрибутов вы можете проверять только то, что уже есть в базе данных, а не новые повторяющиеся вхождения. Таким образом, расширение проверки (ниже) с проверкой памяти, на самом деле, является единственным вариантом, к сожалению.

#user.rb

class User
  has_many :favorite_movies

  validate :validate_unique_movies

  def validate_unique_movies
    validate_uniqueness_of_in_memory(
      favorite_movies, [:name, :user_id], 'Duplicate movie.')
  end
end

#lib/extensions.rb

module ActiveRecord
  class Base
    def validate_uniqueness_of_in_memory(collection, attrs, message)
      hashes = collection.inject({}) do |hash, record|
        key = attrs.map {|a| record.send(a).to_s }.join
        if key.blank? || record.marked_for_destruction?
          key = record.object_id
        end
        hash[key] = record unless hash[key]
        hash
      end
      if collection.length > hashes.length
        self.errors.add_to_base(message)
      end
    end
  end
end
2 голосов
/ 20 апреля 2011

Очень непростое решение проблемы - добавить ограничение уникального ключа для столбцов, которые в комбинации должны быть уникальными:

create unique index names_idx on yourtable (id, name);
0 голосов
/ 20 апреля 2011

Немного более современный подход: validates метод

validates :movie_name, :uniqueness => {:scope => : user_id}
0 голосов
/ 20 апреля 2011
  1. Вы можете попробовать создать виртуальный атрибут и проверить его уникальность:

    def full_name
      [first_name, last_name].joun(' ')
    end
    
    def full_name=(name)
      split = name.split(' ', 2)
      self.first_name = split.first
      self.last_name = split.last
    end  
    
    1. Вы можете проверить уникальность на уровне базы данных, исправив миграцию:

      CREATE TABLE properties (
         namespace CHAR(50),
         name      CHAR(50),
         value     VARCHAR(100),
       );
      
       execute <<-SQL
        ALTER TABLE properties
        ADD CONSTRAINT my_constraint UNIQUE (namespace, name)
       SQL
      
0 голосов
/ 20 апреля 2011

Вы можете легко проверить это как:

params[:user][:favourite_movies].sort.uniq == params[:user][:favourite_movies].sort

или в модели:

self.favourite_movies.sort.uniq == self.favourite_movies.sort


irb(main):046:0> movies = ['terminator', 'ninja turtles', 'titanic', 'terminator' ].map {|movie| movie.downcase }
=> ["terminator", "ninja turtles", "titanic", "terminator"]
irb(main):047:0> movies.sort.uniq == movies.sort
=> false
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...