簡體   English   中英

Rails - Devise Invitable - 兩個 Devise 用戶模型 - 在發送邀請之前密碼不能為空錯誤 devise

[英]Rails - Devise Invitable - Two Devise User Models - Password can't be blank error with devise prior to invitation being sent

我正在嘗試使用兩個用戶模型設置 devise_invitable; 用戶和執行主機。 用戶 model 一切正常,首先實現了用戶代碼,然后添加了第二個 model,Exechost。

對於第二個 model,沒有創建或發送 email 邀請,我們被重定向到 devise 注冊表單,出現以下錯誤:

1 個錯誤禁止保存此 exechost:

  • 密碼不能為空

我也在使用 rolify 和 pundit。

下面是終端 output:

Started POST "/exechosts" for ::1 at 2022-04-07 10:17:33 -0400
10:17:33 web.1  | Processing by Exechosts::RegistrationsController#create as HTML
10:17:33 web.1  |   Parameters: {"authenticity_token"=>"[FILTERED]", "exechost"=>{"username"=>"test20", "email"=>"test20@test.com"}, "commit"=>"Add Moderator"}
10:17:33 web.1  |   TRANSACTION (0.1ms)  BEGIN
10:17:33 web.1  |   ↳ app/controllers/exechosts/registrations_controller.rb:18:in `create'
10:17:33 web.1  |   Exechost Exists? (0.3ms)  SELECT 1 AS one FROM "exechosts" WHERE "exechosts"."email" = $1 LIMIT $2  [["email", "test20@test.com"], ["LIMIT", 1]]
10:17:33 web.1  |   ↳ app/controllers/exechosts/registrations_controller.rb:18:in `create'
10:17:33 web.1  |   TRANSACTION (0.1ms)  ROLLBACK
10:17:33 web.1  |   ↳ app/controllers/exechosts/registrations_controller.rb:18:in `create'
10:17:33 web.1  |   Rendering layout layouts/application.html.erb
10:17:33 web.1  |   Rendering exechosts/registrations/new.html.erb within layouts/application
10:17:33 web.1  |   Rendered exechosts/shared/_error_messages.html.erb (Duration: 0.9ms | Allocations: 432)
10:17:33 web.1  |   Rendered exechosts/shared/_links.html.erb (Duration: 0.1ms | Allocations: 72)
10:17:33 web.1  |   Rendered exechosts/registrations/new.html.erb within layouts/application (Duration: 3.3ms | Allocations: 2073)
10:17:33 web.1  |   Exechost Load (0.3ms)  SELECT "exechosts".* FROM "exechosts" WHERE "exechosts"."id" = $1 ORDER BY "exechosts"."created_at" ASC, "exechosts"."id" ASC LIMIT $2  [["id", "9335e908-f90a-455c-9eb4-f2f8a7ab29ec"], ["LIMIT", 1]]
10:17:33 web.1  |   ↳ app/views/pages/_navBar.html.erb:25
10:17:33 web.1  |   ExecRole Load (0.4ms)  SELECT "exec_roles".* FROM "exec_roles" INNER JOIN "exechosts_exec_roles" ON "exec_roles"."id" = "exechosts_exec_roles"."exec_role_id" WHERE "exechosts_exec_roles"."exechost_id" = $1 AND (((exec_roles.name = 'owner') AND (exec_roles.resource_type IS NULL) AND (exec_roles.resource_id IS NULL)))  [["exechost_id", "9335e908-f90a-455c-9eb4-f2f8a7ab29ec"]]
10:17:33 web.1  |   ↳ app/views/pages/_navBar.html.erb:27
10:17:33 web.1  |   ExecRole Load (0.6ms)  SELECT "exec_roles".* FROM "exec_roles" INNER JOIN "exechosts_exec_roles" ON "exec_roles"."id" = "exechosts_exec_roles"."exec_role_id" WHERE "exechosts_exec_roles"."exechost_id" = $1 AND (((exec_roles.name = 'superowner') AND (exec_roles.resource_type IS NULL) AND (exec_roles.resource_id IS NULL)))  [["exechost_id", "9335e908-f90a-455c-9eb4-f2f8a7ab29ec"]]

下面是用用戶model邀請成功的output:



10:22:01 web.1  | Started POST "/account/users" for ::1 at 2022-04-07 10:22:01 -0400
10:22:01 web.1  | Processing by UsersController#create as HTML
10:22:01 web.1  |   Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"first_name"=>"test2", "last_name"=>"test with User", "phone"=>"111-111-1111", "email"=>"testwithUser@test.com"}, "commit"=>"Add Team Member"}
10:22:01 web.1  |   User Exists? (0.3ms)  SELECT 1 AS one FROM "users" WHERE "users"."customer_num" = $1 LIMIT $2  [["customer_num", 86384], ["LIMIT", 1]]
10:22:01 web.1  |   ↳ app/models/user.rb:39:in `block in assign_unique_customer_num'
10:22:01 web.1  |   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."created_at" ASC, "users"."id" ASC LIMIT $2  [["id", "e22018b6-61a9-401e-9d15-f02924debcfd"], ["LIMIT", 1]]
10:22:01 web.1  |   ↳ app/controllers/application_controller.rb:20:in `current_account'
10:22:01 web.1  |   Account Load (0.2ms)  SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2  [["id", "eaa76bc4-078f-432f-be4f-e1730f0c7274"], ["LIMIT", 1]]
10:22:01 web.1  |   ↳ app/controllers/application_controller.rb:21:in `current_account'
10:22:02 web.1  |   User Exists? (0.4ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "testwithuser@test.com"], ["LIMIT", 1]]
10:22:02 web.1  |   ↳ app/controllers/users_controller.rb:90:in `block in create'
10:22:02 web.1  |   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."invitation_token" = $1 ORDER BY "users"."created_at" ASC, "users"."id" ASC LIMIT $2  [["invitation_token", "[FILTERED]"], ["LIMIT", 1]]
10:22:02 web.1  |   ↳ app/controllers/users_controller.rb:90:in `block in create'
10:22:02 web.1  |   TRANSACTION (0.3ms)  BEGIN
10:22:02 web.1  |   ↳ app/controllers/users_controller.rb:90:in `block in create'
10:22:02 web.1  |   User Create (42.3ms)  INSERT INTO "users" ("first_name", "last_name", "phone", "status", "customer_num", "expiration_date", "created_at", "updated_at", "email", "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "account_id", "invitation_token", "invitation_created_at", "invitation_sent_at", "invitation_accepted_at", "invitation_limit", "invited_by_type", "invited_by_id", "invitations_count") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27) RETURNING "id"  [["first_name", "test2"], ["last_name", "test with User"], ["phone", "111-111-1111"], ["status", "acitve"], ["customer_num", 86384], ["expiration_date", nil], ["created_at", "2022-04-07 14:22:02.102863"], ["updated_at", "2022-04-07 14:22:02.102863"], ["email", "testwithuser@test.com"], ["encrypted_password", "[FILTERED]"], ["reset_password_token", "[FILTERED]"], ["reset_password_sent_at", "[FILTERED]"], ["remember_created_at", nil], ["sign_in_count", 0], ["current_sign_in_at", nil], ["last_sign_in_at", nil], ["current_sign_in_ip", nil], ["last_sign_in_ip", nil], ["account_id", "eaa76bc4-078f-432f-be4f-e1730f0c7274"], ["invitation_token", "[FILTERED]"], ["invitation_created_at", "2022-04-07 14:22:02.089182"], ["invitation_sent_at", "2022-04-07 14:22:02.089182"], ["invitation_accepted_at", nil], ["invitation_limit", nil], ["invited_by_type", "User"], ["invited_by_id", 0], ["invitations_count", 0]]
10:22:02 web.1  |   ↳ app/controllers/users_controller.rb:90:in `block in create'
10:22:02 web.1  |   TRANSACTION (3.5ms)  COMMIT
10:22:02 web.1  |   ↳ app/controllers/users_controller.rb:90:in `block in create'
10:22:02 web.1  |   Rendering devise/mailer/invitation_instructions.html.erb
10:22:02 web.1  |   Rendered devise/mailer/invitation_instructions.html.erb (Duration: 2.2ms | Allocations: 1376)
10:22:02 web.1  |   Rendering devise/mailer/invitation_instructions.text.erb
10:22:02 web.1  |   Rendered devise/mailer/invitation_instructions.text.erb (Duration: 1.7ms | Allocations: 698)
10:22:02 web.1  | Devise::Mailer#invitation_instructions: processed outbound mail in 12.1ms
10:22:03 web.1  | Delivered mail 624ef38a2a05e_9d004ed411349@Baileys-MacBook-Pro.local.mail (852.5ms)
10:22:03 web.1  | Date: Thu, 07 Apr 2022 10:22:02 -0400
10:22:03 web.1  | From: please-change-me-at-config-initializers-devise@example.com
10:22:03 web.1  | Reply-To: please-change-me-at-config-initializers-devise@example.com
10:22:03 web.1  | To: testwithuser@test.com
10:22:03 web.1  | Message-ID: <624ef38a2a05e_9d004ed411349@Baileys-MacBook-Pro.local.mail>
10:22:03 web.1  | Subject: Invitation instructions
10:22:03 web.1  | Mime-Version: 1.0
10:22:03 web.1  | Content-Type: multipart/alternative;
10:22:03 web.1  |  boundary="--==_mimepart_624ef38a28bcc_9d004ed411214";
10:22:03 web.1  |  charset=UTF-8
10:22:03 web.1  | Content-Transfer-Encoding: 7bit
10:22:03 web.1  | 
10:22:03 web.1  | 
10:22:03 web.1  | ----==_mimepart_624ef38a28bcc_9d004ed411214
10:22:03 web.1  | Content-Type: text/plain;
10:22:03 web.1  |  charset=UTF-8
10:22:03 web.1  | Content-Transfer-Encoding: 7bit
10:22:03 web.1  | 
10:22:03 web.1  | Hello testwithuser@test.com
10:22:03 web.1  | 
10:22:03 web.1  | Someone has invited you to http://localhost:3000/, you can accept it through the link below.
10:22:03 web.1  | 
10:22:03 web.1  | http://localhost:3000/users/invitation/accept?invitation_token=4TL5Vpyjfv5CFwCLGx9y
10:22:03 web.1  | 
10:22:03 web.1  |   This invitation will be due in April 21, 2022 02:22 PM.
10:22:03 web.1  | 
10:22:03 web.1  | If you don't want to accept the invitation, please ignore this email. Your account won't be created until you access the link above and set your password.
10:22:03 web.1  | 
10:22:03 web.1  | ----==_mimepart_624ef38a28bcc_9d004ed411214
10:22:03 web.1  | Content-Type: text/html;
10:22:03 web.1  |  charset=UTF-8
10:22:03 web.1  | Content-Transfer-Encoding: 7bit
10:22:03 web.1  | 
10:22:03 web.1  | <p>Hello testwithuser@test.com</p>
10:22:03 web.1  | 
10:22:03 web.1  | <p>Someone has invited you to http://localhost:3000/, you can accept it through the link below.</p>
10:22:03 web.1  | 
10:22:03 web.1  | <p>testing here what to say</p>
10:22:03 web.1  | <p><span class="translation_missing" title="translation missing: en.testing here what to say">Testing Here What To Say</span> </p>
10:22:03 web.1  | 
10:22:03 web.1  | 
10:22:03 web.1  | 
10:22:03 web.1  | 
10:22:03 web.1  | <p><a href="http://localhost:3000/users/invitation/accept?invitation_token=4TL5Vpyjfv5CFwCLGx9y">Accept invitation</a></p>
10:22:03 web.1  | 
10:22:03 web.1  |   <p>This invitation will be due in April 21, 2022 02:22 PM.</p>
10:22:03 web.1  | 
10:22:03 web.1  | <p>If you don&#39;t want to accept the invitation, please ignore this email. Your account won&#39;t be created until you access the link above and set your password.</p>
10:22:03 web.1  | 
10:22:03 web.1  | ----==_mimepart_624ef38a28bcc_9d004ed411214--
10:22:03 web.1  | 

以下是路線:


  get 'dashboard/show'
  get 'execdashboard/show'

  devise_for :users, controllers: { registrations: "registrations" }
  devise_for :exechosts, controllers: { registrations: "exechosts/registrations", invitations: "exechosts/invitations" }

執行主機 model:

class Exechost < ApplicationRecord

  rolify :role_cname => 'ExecRole'

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  
devise :invitable, :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

end

在執行主機 controller 中:

class ExechostsController < ApplicationController

  before_action :set_exechost, only: [:show, :edit, :update, :edit_roles ,:update_roles] 
  before_action :set_exechosts, only: [:index]

  def new
    @exechost = Exechost.new
    set_exechost_choices
  end

  def create
    @exechost = Exechost.unscoped.new(exechost_params.except("role"))
    @exechost.password = "password123"

    respond_to do |format|
      begin
        if @exechost.valid? && @exechost.invite!(current_exechost)
          @exechost.add_role :moderator
          format.html {
            redirect_to exechosts_path,
            notice: 'Moderator was successfully invited.'
          }
        else
          set_exechost_choices
          format.html { render :new }
        end
      rescue ActiveRecord::RecordNotUnique
        flash[:alert]= 'Email must be unique'
        format.html { render :new}
      end
    end
  end


  private

   def pundit_user
     user = current_exechost
   end

   def set_exechosts
     @exechosts = Exechost.all
   end

   def set_exechost
     @exechost = Exechost.find(params[:id])
   end

   def exechost_params
     params.require(:exechost).permit(:username, :email, :role)
   end

end

在邀請函 controller 中:

class Exechosts::InvitationsController < Devise::InvitationsController

  before_action :update_sanitized_params, only: :update

  def create

    @exechost = Exechost.invite!(exechost_params[:exechost], current_exechost) do |u| 
      u.skip_invitation = true
    end

    ExechostInvitationNotificationMailer.invite_message(@exechost).deliver if @exechost.errors.empty?
    @exechost.invitation_sent_at = Time.now.utc # mark invitation as delivered

    if @exechost.errors.empty?
      flash[:notice] = "successfully sent invite to #{@exechost.email}"
      respond_with @exechost, :location => exechosts_path
    else
      render :new
    end
  end


  private

  def exechost_params
    params.require(:exechost).permit(:username, :email, :role)
  end
end


報名controller:



class Exechosts::RegistrationsController < Devise::RegistrationsController
  protect_from_forgery with: :exception, prepend: true

  prepend_before_action :require_no_authentication, only: [:cancel]

  before_action :configure_sign_up_params

  

  

  protected

  # If you have extra params to permit, append them to the sanitizer.
  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up, keys: [[:username, :email]])
  end

  # The path used after sign up.
  def after_sign_up_path_for(resource)
    exechosts_path
  end

  
end

devise controller:


class Exechosts::DeviseController < ApplicationController
  class Responder < ActionController::Responder
    def to_turbo_stream
      controller.render(options.merge(formats: :html))
    rescue ActionView::MissingTemplate => error
      if get?
        raise error
      elsif has_errors? && default_action
        render rendering_options.merge(formats: :html, status: :unprocessable_entity)
      else
        redirect_to navigation_location
      end
    end
  end

  self.responder = Responder
  respond_to :html, :turbo_stream
end

和 config/initializers/devise.rb; 只有不可避免的部分,唯一開啟的是兩周限制。



  # ==> Configuration for :invitable
  # The period the generated invitation token is valid.
  # After this period, the invited resource won't be able to accept the invitation.
  # When invite_for is 0 (the default), the invitation won't expire.
  config.invite_for = 2.weeks

  # Number of invitations users can send.
  # - If invitation_limit is nil, there is no limit for invitations, users can
  # send unlimited invitations, invitation_limit column is not used.
  # - If invitation_limit is 0, users can't send invitations by default.
  # - If invitation_limit n > 0, users can send n invitations.
  # You can change invitation_limit column for some users so they can send more
  # or less invitations, even with global invitation_limit = 0
  # Default: nil
  # config.invitation_limit = 5

  # The key to be used to check existing users when sending an invitation
  # and the regexp used to test it when validate_on_invite is not set.
  # config.invite_key = { email: /\A[^@]+@[^@]+\z/ }
  # config.invite_key = { email: /\A[^@]+@[^@]+\z/, username: nil }

  # Ensure that invited record is valid.
  # The invitation won't be sent if this check fails.
  # Default: false
  # config.validate_on_invite = true

  # Resend invitation if user with invited status is invited again
  # Default: true
  # config.resend_invitation = false

  # The class name of the inviting model. If this is nil,
  # the #invited_by association is declared to be polymorphic.
  # Default: nil
  #config.invited_by_class_name = 'User'


  # The foreign key to the inviting model (if invited_by_class_name is set)
  # Default: :invited_by_id
  # config.invited_by_foreign_key = :invited_by_id

  # The column name used for counter_cache column. If this is nil,
  # the #invited_by association is declared without counter_cache.
  # Default: nil
  # config.invited_by_counter_cache = :invitations_count

  # Auto-login after the user accepts the invite. If this is false,
  # the user will need to manually log in after accepting the invite.
  # Default: true
  # config.allow_insecure_sign_in_after_accept = false

來自用戶 controller 的創建代碼; 代碼與添加引用用戶帳戶相同。

如上所述,創建操作確實創建了一個新用戶和 email 邀請。

def create
    @user = User.unscoped.new(user_params.except("role"))
    @user.account = current_account
    @user.password = "password123"

    respond_to do |format|
      begin
        if @user.valid? && @user.invite!(current_user)
          @user.add_role :member, current_account
          format.html {
            redirect_to account_users_path,
            notice: 'User was successfully invited.'
          }
        else
          set_choices
          format.html { render :new }
        end
      rescue ActiveRecord::RecordNotUnique
        flash[:alert]= 'Email must be unique'
        format.html { render :new}
      end
    end
  end

/exechosts 轉到 Exechosts::RegistrationsController,它不是 ExechostsController,創建操作是從 Devise 開始的正常創建操作,需要密碼參數。 但是,/account/users 轉到 UsersController 請求,其中包含您的自定義代碼。

路由代碼不包含與 UsersController 或 ExechostsController 相關的任何內容。 此外,如果您有一些為用戶和 exechost 調用邀請的自定義代碼,您可能不需要到邀請 controller 的路由,並且您可能希望使用 skip 選項不為邀請生成路由。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM