验证多个字段之间的值的唯一性

时间:2011-04-20 04:02:16

标签: ruby-on-rails ruby ruby-on-rails-3

我知道验证像“用户名”这样的标准单一字段的唯一性很容易。然而,对于具有无限数量输入的东西,例如,“喜欢的电影”,其中用户可以添加尽可能多的喜欢的电影,这是我无法弄清楚的。

他们可以选择通过构建器添加或删除字段,但如何确保没有两个或多个条目重复?

6 个答案:

答案 0 :(得分:7)

我认为完成这样的事情的最简单方法是验证范围内某些事物的唯一性。我不能确定它是如何适合您的场景的,因为您没有描述模型关联,但这里是一个如何在FavoriteMovie模型中工作的示例:

class FavoriteMovie < ActiveRecord::Base
  belongs_to :user

  validates_uniqueness_of :movie_name, :scope => :user_id
end

这可确保一个特定用户不能有两个相同的电影名称。

答案 1 :(得分:4)

事实证明,使用嵌套属性时,您只能验证数据库中已有的内容,而不是新的重复出现次数。因此,遗憾的是,带有内存验证的验证扩展(下面)是唯一的选择。

#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 :(得分:2)

解决这个问题的一个非常类似于解决方案的方法是在列上添加一个唯一的键约束,这些列必须是唯一的:

create unique index names_idx on yourtable (id, name);

答案 3 :(得分:0)

你可以轻松地检查它:

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

答案 4 :(得分:0)

  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
      

答案 5 :(得分:0)

更现代的方法:validates method

validates :movie_name, :uniqueness => {:scope => : user_id}