当一个新用户注册时,我想通过使用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