如何防止"翻译失踪"将Devise与自定义注册控制器一起使用时出错?

时间:2017-01-25 23:10:28

标签: ruby-on-rails ruby devise ruby-on-rails-5

我已经尝试了所有的东西,但仍然没有得到"翻译失踪"使用Devise注册时出现错误信息。

以下是一些背景信息:

  • 我正在使用Devise进行身份验证。
  • 我创建了一个" Customer"而不是" User"模型。
  • 我想在Customer模型中添加一些属性,因此我自定义了Devise Registrations控制器。我在路线中指定了这个。
  • 其中一个属性(invite_url_param)在客户模型中验证了状态和唯一性。

这是我在flash消息中收到的确切错误文字:

translation missing: en.devise.registrations.customer.Invite url param That email has already been used - please try again

我想要将错误改为:"该电子邮件已被使用 - 请再试一次" - 所以没有翻译缺失部分。

但我无法弄清楚如何摆脱缺少的翻译:en.devise.registrations.customer.Invite url param"。

它也不是特定于invite_url_param,如果我尝试创建一个密码太短的客户,我会收到此错误文字:

translation missing: en.devise.registrations.customer.Password Password is too short (minimum is 6 characters)

这是我的注册管理员:

class RegistrationsController < DeviseController
  prepend_before_action :require_no_authentication, only: [:new, :create, :cancel]
  prepend_before_action :authenticate_scope!, only: [:edit, :update, :destroy]
  prepend_before_action :set_minimum_password_length, only: [:new, :edit]

  # GET /resource/sign_up
  def new
    build_resource({})
    yield resource if block_given?
    respond_with resource
  end

  # POST /resource
  def create
    build_resource(sign_up_params)

    resource.invite_url_param = resource.email.split("@").first.tr(".", "")

    if resource.referred_by
      unless Invite.find_by_receiver_email(resource.email)
        if Customer.find_by_invite_url_param(resource.referred_by)
          @invite = Invite.new(receiver_email: resource.email)
          @invite.customer = Customer.find_by_invite_url_param(resource.referred_by)
          @invite.save
        end
      end
    end

    resource.save
    yield resource if block_given?
    if resource.persisted?
      unless SaverGuest.find_by_email(resource.email)
        CustomerMailer.signup_bill(resource).deliver
      end
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      resource.errors.full_messages.each {|x| set_flash_message :error, x}
      redirect_to after_sign_up_path_for(resource)
    end
  end

  # GET /resource/edit
  def edit
    # render :edit
  end

  # PUT /resource
  # We need to use a copy of the resource because we don't want to change
  # the current user in place.
  def update
    self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
    prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)

    resource_updated = update_resource(resource, account_update_params)
    yield resource if block_given?
    if resource_updated
      if is_flashing_format?
        flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
          :update_needs_confirmation : :updated
        set_flash_message :notice, flash_key
      end
      bypass_sign_in resource, scope: resource_name
      respond_with resource, location: after_update_path_for(resource)
    else
      # clean_up_passwords resource
      # set_minimum_password_length
      flash[:error] = "That link is already taken"
      redirect_to invite_path
    end
  end

  # DELETE /resource
  def destroy
    resource.destroy
    Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
    set_flash_message! :notice, :destroyed
    yield resource if block_given?
    respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
  end

  # GET /resource/cancel
  # Forces the session data which is usually expired after sign
  # in to be expired now. This is useful if the user wants to
  # cancel oauth signing in/up in the middle of the process,
  # removing all OAuth session data.
  def cancel
    expire_data_after_sign_in!
    redirect_to new_registration_path(resource_name)
  end

  protected

  def update_needs_confirmation?(resource, previous)
    resource.respond_to?(:pending_reconfirmation?) &&
      resource.pending_reconfirmation? &&
      previous != resource.unconfirmed_email
  end

  # By default we want to require a password checks on update.
  # You can overwrite this method in your own RegistrationsController.
  def update_resource(resource, params)
    resource.update_without_password(params)
  end

  # Build a devise resource passing in the session. Useful to move
  # temporary session data to the newly created user.
  def build_resource(hash=nil)
    self.resource = resource_class.new_with_session(hash || {}, session)
  end

  # Signs in a user on sign up. You can overwrite this method in your own
  # RegistrationsController.
  def sign_up(resource_name, resource)
    sign_in(resource_name, resource)
  end

  # The path used after sign up. You need to overwrite this method
  # in your own RegistrationsController.
  def after_sign_up_path_for(resource)
    stored_location_for(:customer) || root_path
  end

  # The path used after sign up for inactive accounts. You need to overwrite
  # this method in your own RegistrationsController.
  def after_inactive_sign_up_path_for(resource)
    scope = Devise::Mapping.find_scope!(resource)
    router_name = Devise.mappings[scope].router_name
    context = router_name ? send(router_name) : self
    context.respond_to?(:root_path) ? context.root_path : "/"
  end

  # The default url to be used after updating a resource. You need to overwrite
  # this method in your own RegistrationsController.
  def after_update_path_for(resource)
    stored_location_for(:customer) || root_path
  end

  # Authenticates the current scope and gets the current resource from the session.
  def authenticate_scope!
    send(:"authenticate_#{resource_name}!", force: true)
    self.resource = send(:"current_#{resource_name}")
  end

  def sign_up_params
    params.require(:customer).permit(:first_name, :email, :password, :referred_by)
  end

  def account_update_params
    params.require(:customer).permit(:invite_url_param)
  end

  def translation_scope
    'devise.registrations'
  end
end

这是我的客户模型:

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

   has_many :invites

   validates :invite_url_param, presence: true, uniqueness: true
end

这是我的config / locales / devise.en.yml文件:

# Additional translations at https://github.com/plataformatec/devise/wiki/I18n

en:
  devise:
    confirmations:
      confirmed: "Your email address has been successfully confirmed."
      send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
      send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
    failure:
      already_authenticated: "You are already signed in."
      inactive: "Your account is not activated yet."
      invalid: "Invalid %{authentication_keys} or password."
      locked: "Your account is locked."
      last_attempt: "You have one more attempt before your account is locked."
      not_found_in_database: "Invalid %{authentication_keys} or password."
      timeout: "Your session expired. Please sign in again to continue."
      unauthenticated: "You need to sign in or sign up before continuing."
      unconfirmed: "You have to confirm your email address before continuing."
    mailer:
      confirmation_instructions:
        subject: "Confirmation instructions"
      reset_password_instructions:
        subject: "Reset password instructions"
      unlock_instructions:
        subject: "Unlock instructions"
      password_change:
        subject: "Password Changed"
    omniauth_callbacks:
      failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
      success: "Successfully authenticated from %{kind} account."
    passwords:
      no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
      send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
      send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
      updated: "Your password has been changed successfully. You are now signed in."
      updated_not_active: "Your password has been changed successfully."
    registrations:
      destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
      signed_up: ""
      signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
      signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
      signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
      update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
      updated: ""
      customer:
        invite_url_param:
          taken: ""
          blank: ""
    sessions:
      signed_in: ""
      signed_out: ""
      already_signed_out: "Signed out successfully."
    unlocks:
      send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
      send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
      unlocked: "Your account has been unlocked successfully. Please sign in to continue."
  errors:
    messages:
      already_confirmed: "was already confirmed, please try signing in"
      confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
      expired: "has expired, please request a new one"
      not_found: "not found"
      not_locked: "was not locked"
      not_saved:
        one: "1 error prohibited this %{resource} from being saved:"
        other: "%{count} errors prohibited this %{resource} from being saved:"
      taken: "Please try again"
  activerecord:
    errors:
      models:
        customer:
          attributes:
            password:
              too_short: "Password is too short (minimum is %{count} characters)"
            email:
              taken: "That email has already been used - please try again."
            invite_url_param:
              taken: "That email has already been used - please try again."
              blank: "can't really happen"

这是我的config / locales / en.yml文件,我认为该错误文本的结尾已被提取:

en:
  activerecord:
    errors:
      models:
        customer:
          attributes:
            password:
              too_short: "Password is too short (minimum is %{count} characters)"
            email:
              taken: "That email has already been used - please try again."
            invite_url_param:
              taken: "That email has already been used - please try again."
              blank: "can't really happen"

2 个答案:

答案 0 :(得分:1)

是的,您肯定会收到该错误,请查看它在错误中提供的区域设置路径:

en.devise.registrations.customer.Invite

en.devise.registrations.customer.Password

现在请按照您的区域设置缩进路径向下,并且en.devise.registrations.customer中没有密码或邀请定义:

en:
  devise:
    registrations:
      customer:
        uh oh! no pasword!

因此它没有提供的语言环境。所以你的解决方案如下:

  1. 在该路径上创建区域设置
  2. 让Devise使用不同的区域设置来显示错误消息。
  3. 进一步阅读并更多地掌握I18n的工作原理:Take a look at the official rails apithe I18n section of the devise gem repo readme

答案 1 :(得分:0)

最终代码,以防它有类似问题的人:

修复了注册控制器中的create方法,以获取错误的消息键:

def create
    build_resource(sign_up_params)

    resource.invite_url_param = resource.email.split("@").first.tr(".", "")

    resource.save
    yield resource if block_given?
    if resource.persisted?
      if resource.referred_by
        unless Invite.find_by_receiver_email(resource.email)
          if Customer.find_by_invite_url_param(resource.referred_by)
            @invite = Invite.new(receiver_email: resource.email)
            @invite.customer = Customer.find_by_invite_url_param(resource.referred_by)
            @invite.save
          end
        end
      end
      unless SaverGuest.find_by_email(resource.email)
        CustomerMailer.signup_bill(resource).deliver
      end
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      resource.errors.messages.keys.each {|x| set_flash_message :error, x}
      redirect_to after_sign_up_path_for(resource)
    end
  end

resource.errors.messages.keys.each {|x| set_flash_message :error, x}为关键部分。

然后,正如John建议的那样,我需要在config / locales / devise.en.yml文件中的正确嵌套语言环境中使用字符串,如下所示:

en:
  devise:
    registrations:
      customer:
        invite_url_param: "That email has already been used - please try again."
        email: "That email has already been used - please try again."
        password: "Password is too short (minimum is 6 characters)"