PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Rails qual é a diferença no índice exclusivo e validates_uniqueness_of


Aqui estão as diferenças entre o índice único e o validates_uniqueness_of

Este é um patch para permitir que o ActiveRecord identifique erros gerados por db para violações de restrição exclusivas. Por exemplo, ele faz o seguinte funcionar sem declarar um validates_uniqueness_of:
create_table "users" do |t|
  t.string   "email",   null: false
end
add_index "users", ["email"], unique: true

class User < ActiveRecord::Base
end

User.create!(email: '[email protected]')
u = User.create(email: '[email protected]')
u.errors[:email]
=> "has already been taken"

Os benefícios são velocidade, facilidade de uso e completude --

Velocidade

Com essa abordagem, você não precisa fazer uma pesquisa de banco de dados para verificar a exclusividade ao salvar (o que às vezes pode ser bastante lento quando o índice é perdido -- https://rails.lighthouseapp.com/projects/8994/tickets/2503-validate.. . ). Se você realmente se preocupa em validar a exclusividade, terá que usar restrições de banco de dados de qualquer maneira, para que o banco de dados valide a exclusividade, não importa o que aconteça, e essa abordagem remove uma consulta extra. Verificar o índice duas vezes não é um problema para o banco de dados (ele é armazenado em cache na segunda vez), mas salvar uma viagem de ida e volta do banco de dados do aplicativo é uma grande vitória.

Facilidade de uso

Dado que você precisa ter restrições de banco de dados para a verdadeira exclusividade de qualquer maneira, essa abordagem permitirá que tudo aconteça automaticamente quando as restrições de banco de dados estiverem em vigor. Você ainda pode usar validates_uniqueness_of se quiser.

Integridade

validates_uniqueness_of sempre foi um pouco um hack -- ele não pode lidar com condições de corrida corretamente e resulta em exceções que devem ser tratadas usando uma lógica de manipulação de erros um tanto redundante. (Consulte a seção "Simultaneidade e integridade" em http://api.rubyonrails .org/classes/ActiveRecord/Validations/ClassMe... )

validates_uniqueness_of não é suficiente para garantir a exclusividade de um valor. A razão para isso é que, na produção, vários processos de trabalho podem causar condições de corrida:

  1. Duas solicitações simultâneas tentam criar um usuário com o mesmo nome (e queremos que os nomes de usuário sejam exclusivos)

  2. As solicitações são aceitas no servidor por dois processos de trabalho que agora as processarão em paralelo

  3. Ambas as solicitações verificam a tabela de usuários e verificam se o nome está disponível

  4. Ambas as solicitações passam na validação e criam um usuário com o nome aparentemente disponível

Para uma compreensão mais clara, verifique isto

Se você criar um índice exclusivo para uma coluna, significa que você tem a garantia de que a tabela não terá mais de uma linha com o mesmo valor para essa coluna. Usar apenas validação validates_uniqueness_of em seu modelo não é suficiente para impor exclusividade porque pode haver usuários simultâneos tentando criar os mesmos dados.

Imagine que dois usuários tentem registrar uma conta com o mesmo email onde você adicionou validates_uniqueness_of :email em seu modelo de usuário. Se eles clicarem no botão “Cadastre-se” ao mesmo tempo, o Rails procurará na tabela de usuários por esse e-mail e responderá que está tudo bem e que não há problema em salvar o registro na tabela. O Rails irá então salvar os dois registros na tabela de usuário com o mesmo email e agora você tem um problema muito ruim para lidar.

Para evitar isso, você também precisa criar uma restrição exclusiva no nível do banco de dados:
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email
      ...
    end
    
    add_index :users, :email, unique: true
  end
end

Então, ao criar o índice exclusivo index_users_on_email, você obtém dois benefícios muito bons. Integridade de dados e bom desempenho porque índices exclusivos tendem a ser muito rápidos.

Se você colocar unique:true em sua tabela de posts para user_id, não permitirá inserir registros duplicados com o mesmo user_id.