Devise:如何在注册时使用SecureRandom.hex将一个8个字符的十六进制字符串保存到users表中



当一个新用户注册时,我想通过使用SecureRandom.hex(4(创建一个随机的十六进制字符串来为他们创建一个唯一的URL。这个唯一的字符串将保存在用户表中名为URL的列中。然后我可以通过user/url(而不是user.id或user.user_name(加载特定的用户数据。我似乎可以很容易地添加新的字段供用户输入,但我很难找到如何在创建时自动将其与记录一起保存。如何使用Devise实现此功能?

这应该有效:

# This is a registered user or guest
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :confirmable, :omniauthable
  def initialize(attributes = {})
    super
    @hex ||= SecureRandom.hex(4)
  end
end

在这里,我们覆盖User类的"normal"initialize方法,调用其父级super的normal behavior,然后设置所需的值。

请注意,用户还没有保存,他只是通过这种方式初始化的。

@hex ||= SecureRandom.hex(4)表示十六进制被设置为一个新值,除非已经有一个值(intialize也用于现有记录(

只是好奇,你为什么要用hex而不是uuid来做这件事?

更新:

请注意,上面的代码不会检查是否已经使用了十六进制。要做到这一点,你必须创建一个这样检查的方法:

def initialize(attributes = {})
    super
    @hex ||= unique_hex
  end
  def unique_hex
    hex = SecureRandom.hex(4)
    return unique_hex if User.exists?(hex: hex)
    hex
  end

这样做的目的是首先创建一个新的十六进制,然后检查是否存在具有该十六进制的User,如果不存在,我们返回新十六进制,如果有用户具有此十六进制,我们再次调用unique_hex,试图再次找到唯一的十六进制。

更新2:

假设您现在要链接到您的用户。实现这一点的一种方法是在您的用户模型中定义此方法:

def to_param
  # We will use 'parameterize' here to make sure we can use it in a url
  hex.parameterize # or use uuid here
end

这样,当你使用user_path(@user)时,你会得到这样的东西:users/the-used-hex

在您的控制器中,您现在可以/必须将用户的查询替换为User.find_by(hex: params[:id])。请注意,我们没有"入侵"我们的params[:id],这可能不是很干净。您可以将"动态分段"与重写命名参数结合使用,但我认为目前您已经从to_param方法中获得了一些经验。

注2:您可能还必须更新Devise控制器的finder方法才能使用find_by(hex: params[:id]),因为现在您的用户模型将返回十六进制作为URL的id。

另一种选择是只在需要时在路径中使用十六进制。为此,您可以调用user_path('whatever_you_want'),这将返回users/whatever_you_want。在您的情况下,您可以使用user_path(@user.hex)。优点是您没有覆盖Devise控制器仍然使用的任何内容,并且您仍然可以在自己的控制器中使用User.find_by(hex: params[:id])

我个人会避免在设计中这样做。

如果你想手动

class User < ActiveRecord::Base
    before_validation :set_uuid, on: :create
    validates_uniqueness_if :uuid
    private
    def set_uuid
        self.uuid = SecureRandom.hex(4)
    end
end
class UsersController < ApplicationController
    def show
        @user = User.find_by(uuid: params[:id])
    end
end

这是宝石:

https://github.com/norman/friendly_id

最新更新