我的rails项目中有一个帖子模型,
首先,我认为暴露真实的数据库ID并不是一个好主意,我是对的吗?
如果我是对的,我希望生成一个独特的逐步增加的数字,在网址中使用它,只需链接到以下行:
https://hostname.com/posts/
的 unique_number
我搜索了SO,从下面链接,SecureRandom
可以生成随机令牌,但它不能生成逐渐增加的数字。
Best way to create unique token in Rails?
那么,如何在创建新记录之前生成逐渐增加的数字。
非常感谢。
答案 0 :(得分:3)
根据创建的帖子的频率,您可以使用纪元中的时间来获得(几乎)逐渐增加的唯一数字,以秒为单位:
Time.now.to_i
或以毫秒为单位:
(Time.now.to_f * 1000).to_i
警告:
答案 1 :(得分:3)
你可以(如果它是令人满意的)在最后一个数字生成后创建一个介于1到10_000之间的唯一数字。
为了使'to_param'正常工作,你的令牌应该是一个字符串。
迁移以创建列
add_column :posts, :unique_number, :string
然后修改模型......
class Post < ActiveRecord::Base
before_create :new_unique_number
def new_unique_number
last_number = Post.order('unique_number DESC').first.unique_number || '1'
self.unique_number = (last_number.to_i + rand(1, 10_000)).to_s
end
#.....
end
答案 2 :(得分:1)
如果您使用Post
模型,我想我们会谈论博客文章或什么?
问题是:你真的需要一些渐进的东西,或者只是一些独特的东西吗?
如果重要的是你的id是唯一的,你可以使用你想要的任何东西作为id,而不仅仅是一个整数。
例如,假设您的Post模型对标题唯一性进行了验证。您可以决定其标题将用于网址:
class Post
validates_uniqueness :title
def to_param
title
end
end
#to_param
方法允许决定将哪个属性用于网址生成:
post = Post.create( title: 'my_post' )
post_path( post ) # => /posts/my_post
请注意,如果你想使用像title这样的人类字符串,你可能需要在保存回调之前对其进行清理,并将其设置在其他字段中,例如&#34; url_title&#34; (以避免在网址中留出空格和难看的字符)。
在控制器中,您可以像往常一样在params[:id]
中获取ID:
class PostsController < ApplicationController
before_action :find_post
def show
end
private
def find_post
@post = Post.where( title: params[ :id ] ).first or redirect_to '/'
end
end
答案 3 :(得分:1)
首先,我认为暴露真实的数据库ID并不是一个好主意,我是对的吗?
取决于。
如果您的对象ID来自可预测的序列,则表示使用您的应用程序的人可以猜出可能有效的ID,并将其添加到URL,POST请求等。
如果以只读方式和公开方式访问对象,那么在生成数据库时完全没有问题。
如果您需要保护访问权限,则有多种方法可以实现。如果您在Web应用程序中拥有安全授权,并且可以判断当前用户是否应该能够查看对象,那么您已经具有足够的安全性。创建不可语言的对象id(例如uuids)并不能真正帮助你。使用其他一些序列来&#34;隐藏&#34; id并没有真正添加任何安全性,可能需要做很多工作。虽然您可以更进一步,并生成从其他内容(标题)派生的友好URL,这将是类似的努力,这通常不是安全问题。
您应该只担心直接暴露您的数据库ID,如果这会通过API提供直接链接,未经授权的用户可以猜测其他ID并访问或更改他们不应该的内容。如果由于系统中的其他限制而无法通过ID直接限制访问,则答案是不为同一对象生成一些其他直接的,可预测的索引(这将与人们产生相同的问题能够猜到),但做其中一个:
1)提供间接访问 - 例如用户只能从您为其预先选择的对象中进行选择,而是将ID分配给那些选项,并且只通过API接受这些choice_ids,而不是所选对象的数据库ID。
2)生成无法识别的ID,可能是临时的,如SecureRandom.uuid