Existe uma maneira de validar que um registro real é único e não apenas uma coluna? Por exemplo, um modelo / tabela de amizade não deve ter vários registros idênticos, como:
user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
Existe uma maneira de validar que um registro real é único e não apenas uma coluna? Por exemplo, um modelo / tabela de amizade não deve ter vários registros idênticos, como:
user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
Você pode selecionar uma validates_uniqueness_of
chamada da seguinte maneira.
validates_uniqueness_of :user_id, :scope => :friend_id
validates_uniqueness_of [:user_id, :friend_id]
. Talvez isso precise ser corrigido?
Você pode usar validates
para validar uniqueness
em uma coluna:
validates :user_id, uniqueness: {scope: :friend_id}
A sintaxe para a validação em várias colunas é semelhante, mas você deve fornecer uma matriz de campos:
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
No entanto , as abordagens de validação mostradas acima têm uma condição de corrida e não podem garantir consistência. Considere o seguinte exemplo:
os registros da tabela de banco de dados devem ser únicos por n campos;
várias ( duas ou mais ) solicitações simultâneas, tratadas por processos separados cada ( servidores de aplicativos, servidores de trabalho em segundo plano ou o que você estiver usando ), acessam o banco de dados para inserir o mesmo registro na tabela;
cada processo em paralelo valida se há um registro com os mesmos n campos;
a validação para cada solicitação é aprovada com êxito e cada processo cria um registro na tabela com os mesmos dados.
Para evitar esse tipo de comportamento, deve-se adicionar uma restrição exclusiva à tabela db. Você pode configurá-lo com o add_index
auxiliar para um (ou vários) campos executando a seguinte migração:
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :table_name, [:field1, ... , :fieldn], unique: true
end
end
Advertência : mesmo depois de definir uma restrição exclusiva, duas ou mais solicitações simultâneas tentarão gravar os mesmos dados no banco de dados, mas, em vez de criar registros duplicados, isso criará uma ActiveRecord::RecordNotUnique
exceção, que você deve tratar separadamente:
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end
Isso pode ser feito com uma restrição de banco de dados nas duas colunas:
add_index :friendships, [:user_id, :friend_id], unique: true
Você pode usar um validador de trilhos, mas em geral eu recomendo o uso de uma restrição de banco de dados.
Mais informações: https://robots.thoughtbot.com/validation-database-constraint-or-both
Is there a rails-way way
. E você oferece a ele caminhos não-trilhos, mas padrão.The Active Record way claims that intelligence belongs in your models, not in the database.
validates :field_name, unique: true
é propenso a condições de corrida, portanto, mesmo contra trilhos, é preferível uma restrição real. @HarryJoy Vou votar uma resposta descrevendo a maneira de restrição.