Eu tenho um modelo que validates_presence_of :organization
. Organização é outro modelo. Para evitar que cada controlador que cria um Usuário também estabeleça uma Organização para esse usuário (se não for passada), configurei um before_validation
método que atribui uma Organização ao Usuário. Meu código original para before_validation :assign_organization
era o seguinte:
validates_presence_of :organization
before_validation :assign_organization
def assign_organization
if self.new_record? && self.organization.nil?
organization = Organization.new
organization.save
self.organization = organization
end
end
Isso parecia funcionar bem, até que percebi que estava permitindo que um usuário fosse criado, independentemente de a organização ser salva ou não. Isso se deveu ao fato de que o organization
objeto existia, então apenas apontava para aquela instância, salvo ou não com sucesso. Para resolver isso, fiz o seguinte:self.organization
organization
validates_presence_of :organization
before_validation :assign_organization
def assign_organization
if self.new_record? && self.organization.nil?
organization = Organization.new
organization.save
self.organization_id = organization.id
end
end
Simplesmente mudando para , o retornaria false com sucesso, porque se não salvasse, seria . Antes, mesmo que o objeto não fosse salvo, a coluna do usuário apontava temporariamente para o objeto vazio e inválido, ao invés de algo , o que fazia passar a validação mesmo que fosse ao salvar o usuário.self.organization = organization
self.organization_id = organization.id
validates_presence_of :organization
organization
organization.id
nil
organization
organization
nil
self.organization
nil
Espero que isso ajude mais alguém!
T
PS Alguém mencionou apenas tentar , isso também não funcionará. Se você olhar para os documentos, retorna um objeto se ele passa nas validações ou não. Isso resultaria no mesmo cenário do meu bloco de código original.self.organization = Organization.create
create
EDITAR:
Como @boriscy mencionou nos comentários abaixo, você também pode fazer isso:
validates_presence_of :organization
before_validation :assign_organization
def assign_organization
if self.new_record? && self.organization.nil?
organization = Organization.new
organization.save! #throws an error if save fails
self.organization = organization
end
end
No entanto, é importante observar que a correção original que mencionei geraria automaticamente um erro que é salvo dentro dos user
erros do objeto, mas com a alternativa acima, você precisaria lidar com o erro do ActiveRecord lançado ou o aplicativo deixará de funcionar. Obrigado @boriscy !save!