我会继续道歉,因为我是ruby和rails的新手,我不能为我的生活弄清楚如何在我的项目中使用hashids实现。该项目是一个简单的图像主机。我已经使用Base58对sql ID进行编码,然后在控制器中对其进行解码。但是我想让URL更随机,因此切换到hashids。
我已将hashids.rb文件放在我的lib目录中:https://github.com/peterhellberg/hashids.rb
现在有些困惑从这里开始。我是否需要在每个使用hashids.encode和hashids.decode的页面上初始化哈希值
hashids = Hashids.new("mysalt")
我发现这篇文章(http://zogovic.com/post/75234760043/youtube-like-ids-for-your-activerecord-models)让我相信我可以把它放到初始化器中但是在这之后我仍然得到NameError(未定义的局部变量或方法`hashids' for ImageManager:Class )
所以在我的ImageManager.rb类中我有
require 'hashids'
class ImageManager
class << self
def save_image(imgpath, name)
mime = %x(/usr/bin/exiftool -MIMEType #{imgpath})[34..-1].rstrip
if mime.nil? || !VALID_MIME.include?(mime)
return { status: 'failure', message: "#{name} uses an invalid format." }
end
hash = Digest::MD5.file(imgpath).hexdigest
image = Image.find_by_imghash(hash)
if image.nil?
image = Image.new
image.mimetype = mime
image.imghash = hash
unless image.save!
return { status: 'failure', message: "Failed to save #{name}." }
end
unless File.directory?(Rails.root.join('uploads'))
Dir.mkdir(Rails.root.join('uploads'))
end
#File.open(Rails.root.join('uploads', "#{Base58.encode(image.id)}.png"), 'wb') { |f| f.write(File.open(imgpath, 'rb').read) }
File.open(Rails.root.join('uploads', "#{hashids.encode(image.id)}.png"), 'wb') { |f| f.write(File.open(imgpath, 'rb').read) }
end
link = ImageLink.new
link.image = image
link.save
#return { status: 'success', message: Base58.encode(link.id) }
return { status: 'success', message: hashids.encode(link.id) }
end
private
VALID_MIME = %w(image/png image/jpeg image/gif)
end
end
在我的控制器中,我有:
require 'hashids'
class MainController < ApplicationController
MAX_FILE_SIZE = 10 * 1024 * 1024
MAX_CACHE_SIZE = 128 * 1024 * 1024
@links = Hash.new
@files = Hash.new
@tstamps = Hash.new
@sizes = Hash.new
@cache_size = 0
class << self
attr_accessor :links
attr_accessor :files
attr_accessor :tstamps
attr_accessor :sizes
attr_accessor :cache_size
attr_accessor :hashids
end
def index
end
def transparency
end
def image
#@imglist = params[:id].split(',').map{ |id| ImageLink.find(Base58.decode(id)) }
@imglist = params[:id].split(',').map{ |id| ImageLink.find(hashids.decode(id)) }
end
def image_direct
#linkid = Base58.decode(params[:id])
linkid = hashids.decode(params[:id])
file =
if Rails.env.production?
puts "#{Base58.encode(ImageLink.find(linkid).image.id)}.png"
File.open(Rails.root.join('uploads', "#{Base58.encode(ImageLink.find(linkid).image.id)}.png"), 'rb') { |f| f.read }
else
puts "#{hashids.encode(ImageLink.find(linkid).image.id)}.png"
File.open(Rails.root.join('uploads', "#{hashids.encode(ImageLink.find(linkid).image.id)}.png"), 'rb') { |f| f.read }
end
send_data(file, type: ImageLink.find(linkid).image.mimetype, disposition: 'inline')
end
def upload
imgparam = params[:image]
if imgparam.is_a?(String)
name = File.basename(imgparam)
imgpath = save_to_tempfile(imgparam).path
else
name = imgparam.original_filename
imgpath = imgparam.tempfile.path
end
File.chmod(0666, imgpath)
%x(/usr/bin/exiftool -all= -overwrite_original #{imgpath})
logger.debug %x(which exiftool)
render json: ImageManager.save_image(imgpath, name)
end
private
def save_to_tempfile(url)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
http.start do
resp = http.get(uri.path)
file = Tempfile.new('urlupload', Dir.tmpdir, :encoding => 'ascii-8bit')
file.write(resp.body)
file.flush
return file
end
end
end
然后在我的image.html.erb视图中我有这个:
<%
@imglist.each_with_index { |link, i|
id = hashids.encode(link.id)
ext = link.image.mimetype.split('/')[1]
if ext == 'jpeg'
ext = 'jpg'
end
puts id + '.' + ext
%>
现在如果我添加
hashids = Hashids.new("mysalt")
在ImageManager.rb main_controller.rb和我的image.html.erb中我收到此错误:
ActionView::Template::Error (undefined method `id' for #<Array:0x000000062f69c0>)
所以总而言之,实现hashids.encode / decode并不像实现Base58.encode / decode那么容易,我对如何让它工作感到困惑......任何帮助都将非常感激。
答案 0 :(得分:1)
我建议将其加载到Gemfile
并运行bundle install
,将其作为宝石加载。它将为您节省在每个文件中要求它的麻烦,并允许您使用Bundler管理更新。
是的,您确实需要在将它与相同的盐一起使用的地方进行初始化。建议您将salt定义为常量,可能在application.rb
中。
您提供的链接会将hashids
注入ActiveRecord,这意味着它无法在其他任何地方使用。我不推荐使用相同的方法,因为它需要高度熟悉Rails。
您可能需要花一些时间了解ActiveRecord和ActiveModel。将为您节省大量重新发明的轮子。 :)
答案 1 :(得分:1)
在每次思考之前,您应该只测试项目中是否包含Hashlib,您可以在项目文件夹中运行命令rails c
并进行一个小测试:
>> my_id = ImageLink.last.id
>> puts Hashids.new(my_id)
如果不能正常工作,请在gemfile中添加gem(无论如何都要多得多)。
然后,我认为您应该在ImageLink模型中为hash_id添加一个getter。 即使你不想在数据库中保存你的哈希值,这个哈希在你的模型中也有它的风格。有关详细信息,请参阅虚拟财产。
记住&#34;瘦瘦的控制器,胖模型&#34;。
class ImageLink < ActiveRecord::Base
def hash_id()
# cache the hash
@hash_id ||= Hashids.new(id)
end
def extension()
# you could add the logic of extension here also.
ext = image.mimetype.split('/')[1]
if ext == 'jpeg'
'jpg'
else
ext
end
end
end
更改ImageManager#save_image
中的返回值link = ImageLink.new
link.image = image
# Be sure your image have been saved (validation errors, etc.)
if link.save
{ status: 'success', message: link.hash_id }
else
{status: 'failure', message: link.errors.join(", ")}
end
在您的模板中
<%
@imglist.each_with_index do |link, i|
puts link.hash_id + '.' + link.extension
end # <- I prefer the do..end to not forgot the ending parenthesis
%>
所有这些代码都未经过测试......
答案 2 :(得分:1)
我正在寻找类似的东西,我可以伪装我的记录的ID。我遇到了 act_as_hashids 。
https://github.com/dtaniwaki/acts_as_hashids
这个小宝石无缝集成。您仍然可以通过ID找到您的记录。或者使用哈希。在嵌套记录上,您可以使用方法with_hashids
。
要获取哈希,请在对象本身上使用to_param
,这会产生与此ePQgabdg
类似的字符串。
由于我刚刚实现了这个,我无法分辨出这个gem有多么有用。到目前为止,我只需要稍微调整一下代码。
我还给记录一个虚拟属性hashid,以便我可以轻松访问它。
attr_accessor :hashid
after_find :set_hashid
private
def set_hashid
self.hashid = self.to_param
end