Devise Invitable 正在修改现有用户

Devise Invitable is modifying existing users

上下文

我正在使用 devise_invitable 允许用户(具有管理员角色)在我的应用程序中注册另一个用户。

用户对象有电子邮件、密码、令牌(随机字符串)、角色(也是字符串)和关联的HealthRecord对象有姓名、姓氏、dni(个人 ID)以及一些额外信息

问题

出于某种原因,当我输入现有电子邮件时,出现错误(这是为了验证),但它也破坏了与拥有该现有电子邮件的用户关联的 HealthRecord。

代码

这是我的控制台在尝试使用现有电子邮件创建用户时显示的内容

Started POST "/users/invitation" for ::1 at 2021-11-26 10:04:15 -0300
Processing by Users::InvitationsController#create as HTML
  Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"email"=>"paciente1@example.com", "role"=>"Paciente", "health_record_attributes"=>{"residencia"=>"Cementerio", "nombre"=>"overriding", "apellido"=>"test", "dni"=>"123456789", "risk"=>"0", "birth"=>"1999-02-12"}}, "commit"=>"Registrar"}
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 5], ["LIMIT", 1]]
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."email" = ? ORDER BY "users"."id" ASC LIMIT ?  [["email", "paciente1@example.com"], ["LIMIT", 1]]
  HealthRecord Load (0.1ms)  SELECT "health_records".* FROM "health_records" WHERE "health_records"."user_id" = ? LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
  TRANSACTION (0.1ms)  begin transaction
  HealthRecord Destroy (0.5ms)  DELETE FROM "health_records" WHERE "health_records"."id" = ?  [["id", 1]]
  TRANSACTION (207.2ms)  commit transaction
  User Exists? (0.3ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = ? AND "users"."id" != ? LIMIT ?  [["email", "paciente1@example.com"], ["id", 1], ["LIMIT", 1]]
  HealthRecord Exists? (0.4ms)  SELECT 1 AS one FROM "health_records" WHERE "health_records"."dni" = ? LIMIT ?  [["dni", "123456789"], ["LIMIT", 1]]
  Rendering layout layouts/application.html.erb
  Rendering users/invitations/new.html.erb within layouts/application
  HealthRecord Load (0.1ms)  SELECT "health_records".* FROM "health_records" WHERE "health_records"."user_id" = ? LIMIT ?  [["user_id", 5], ["LIMIT", 1]]
  ↳ app/views/users/invitations/new.html.erb:18

生成新用户的视图

<h2>Registro excepcional</h2>

<%= form_for(setup_user(resource), as: resource_name, url: invitation_path(resource_name), html: { method: :post }) do |f| %>

  <% resource.class.invite_key_fields.each do |field| -%>
    <div class="field">
      <%= f.label field %><br />
      <%= f.text_field field, class: 'form-control'%> 
    </div>
  <% end %>

  <div class="field">
    <%= f.hidden_field :role, :value=>"Paciente"%> 
  </div>

  <%= f.fields_for :health_record do |ff| %>
    <div class="field">
      <%= ff.hidden_field :residencia, :value=>current_user.health_record.residencia%> 
    </div>
    
    <div class="field">
      <%= ff.label "Nombre" %><br/>
      <%= ff.text_field :nombre, class: 'form-control',:required => true%> 
    </div>
    <div class="field">
      <%= ff.label "Apellido" %><br/>
      <%= ff.text_field :apellido, class: 'form-control',:required => true%> 
    </div>
    <div class="field">
      <%= ff.label "DNI" %><br/>
      <%= ff.text_field :dni, class: 'form-control',:required => true%> 
    </div>
    <div class="field">
      <%= ff.label "Es de riesgo:",:required => true %>
      <%= ff.check_box :risk  %> 
    </div>
    <div class="field">
        <%= ff.label "Fecha de nacimiento:"%><br/>
        <%= ff.date_field :birth, class: 'form-control',:required => true%> 
    </div>
  <% end %>
  <br/>
  <div class="actions">
    <%= f.submit "Registrar" %>
  </div>
<% end %>

用户模型具有validate_on_invite

class User < ApplicationRecord
  devise :invitable, :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :authentication_keys => [:token,:email], :validate_on_invite => true
  has_many :comprobantes, :dependent => :destroy
  has_one :health_record, :dependent => :destroy
  has_many :TurnoAsignado, :dependent => :destroy 
  has_many :TurnoNoAsignado, :dependent => :destroy

  validates :email, uniqueness: true
  
  before_save :init

  accepts_nested_attributes_for :health_record

  def init()
    if self.token.nil?
      self.token = (rand()*1000000).to_i
    end
  end

end

HealthRecord 模型

class HealthRecord < ApplicationRecord
  belongs_to :user
  validates :dni, presence: true
  validates :dni, uniqueness: true
  validates :nombre, presence: true
  validates :apellido, presence: true
  validates :birth, presence: true
  before_save :upcase_content
  
  def upcase_content
      self.nombre=self.nombre.downcase
      self.apellido=self.apellido.downcase
      self.nombre=self.nombre.split(/ |\_/).map(&:capitalize).join(" ")
      self.apellido=self.apellido.split(/ |\_/).map(&:capitalize).join(" ")
  end

end

邀请控制器(几乎是默认设置,我只是添加了参数和一个 after_path)

class Users::InvitationsController < Devise::InvitationsController
   
  before_action :configure_permitted_parameters

    #Permit the new params here.
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:invite, keys: [
        :token,
        :role,
        health_record_attributes: [
            :apellido, 
            :nombre,
            :dni,
            :risk, 
            :birth,
            :residencia
          ]
        ])
  end

  def after_invite_path_for(resource)
    new_asignado_path(self.resource.id)
  end
  
end

我认为问题可能出在这一行

form_for(setup_user(resource),...

我正在使用助手将用户的 HealthRecord 设置为空(fields_for 需要用户拥有 HealthRecord 才能工作)

module FormHelper
    def setup_user(user)
      user.health_record ||= HealthRecord.new # ||= means “assign this value unless it already has a value”
      user
    end
  end

也许发生的事情是空的 HealthRecord 不知何故分配给了现有用户?

我通过拦截邀请控制器中创建方法的流程解决了这个问题,通过询问用户电子邮件或 dni 是否存在

def create
    @correo = User.find_by(email:params[:user][:email])
    @dni = HealthRecord.find_by(dni:params[:user][:health_record_attributes][:dni])
    
    if (@correo.nil? && @dni.nil?) #si no existe mail ni dni
      super
    else
      mensaje="Los siguientes campos ya estan registrados:"
      if !(@correo.nil?)
        mensaje = mensaje + " email"
      end
      if !(@dni.nil?)
        mensaje = mensaje + " dni"  
      end
      flash[:notice] = mensaje
      redirect_to new_user_invitation_path
    end
  end

虽然可行,但我不确定问题的原因,欢迎任何见解