首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在ruby on rails中实现hashids?

如何在ruby on rails中实现hashids?
EN

Stack Overflow用户
提问于 2015-08-29 17:10:16
回答 3查看 1.9K关注 0票数 3

我会提前道歉,因为我对ruby和rails还不熟悉,我无法在我的项目中找到如何使用hashids来实现。该项目是一个简单的图像主机。我已经让它使用Base58对sql进行编码,然后在控制器中解码它。然而,我想要使URL更随机,因此切换到hashids。

我已经将hashids.rb文件放在我的lib目录中:https://github.com/peterhellberg/hashids.rb

现在有些混乱就从这里开始。是否需要在每个使用hashids.encode和hashids.decode的页面上通过

代码语言:javascript
复制
hashids = Hashids.new("mysalt")

我找到了这篇文章(http://zogovic.com/post/75234760043/youtube-like-ids-for-your-activerecord-models),它让我相信我可以把它放入初始化器中,但是在这样做之后,我仍然得到NameError (用于ImageManager:Class的未定义的局部变量或方法“`hashids”)。

所以在我的ImageManager.rb课上

代码语言:javascript
复制
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

在我的控制器里我有:

代码语言:javascript
复制
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视图中,我得到了以下内容:

代码语言:javascript
复制
<%
   @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
%>

现在如果我加上

代码语言:javascript
复制
hashids = Hashids.new("mysalt")

在ImageManager.rb main_controller.rb和my image.html.erb中,我得到了以下错误:

代码语言:javascript
复制
ActionView::Template::Error (undefined method `id' for #<Array:0x000000062f69c0>)

所以总的来说,实现hashids.encode/decode并不像实现Base58那样简单。任何帮助都将不胜感激。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-08-29 17:41:35

我建议通过将其包含到Gemfile中并运行bundle install,将其作为一个gem加载。它将为您省去在每个文件中要求它的麻烦,并允许您使用Bundler管理更新。

是的,您确实需要初始化它,无论它要与相同的盐一起使用。建议您将盐定义为常数,也许在application.rb中。

您提供的链接将hashids注入到ActiveRecord中,这意味着它在其他任何地方都无法工作。我不推荐同样的方法,因为它需要对Rails有很高的熟悉程度。

您可能需要花一些时间来了解ActiveRecord和ActiveModel。会帮你省下很多新发明的轮子。:)

票数 1
EN

Stack Overflow用户

发布于 2015-08-29 20:05:17

在大家认为您应该测试项目中是否包含Hashlib之前,您可以在项目文件夹中运行命令rails c,只进行一个小的测试:

代码语言:javascript
复制
>> my_id = ImageLink.last.id
>> puts Hashids.new(my_id)

如果不起作用,请在宝石文件中添加宝石(无论如何,这会让您感觉到更多)。

然后,我认为您应该在hash_id模型中为您的ImageLink添加一个getter。即使您不想将您的哈希保存在数据库中,此散列在您的模型中也有它的优点。有关更多信息,请参见虚拟财产。

记住“瘦身控制器,胖子模型”。

代码语言:javascript
复制
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中的返回

代码语言:javascript
复制
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

在你的模板中

代码语言:javascript
复制
<%
   @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
%> 

所有这些代码都没有经过测试..。

票数 1
EN

Stack Overflow用户

发布于 2016-07-28 18:05:46

我在寻找类似的东西,在那里我可以伪装我的记录的I。我偶然发现了act_as_hashids。

hashids

这个小宝石无缝地集成在一起。您仍然可以通过ids找到您的记录。或者用哈希。在嵌套记录上,可以使用with_hashids方法。

要获取哈希,您可以在对象本身上使用to_param,这将产生一个类似于此ePQgabdg的字符串。

因为我刚刚实现了这个功能,所以我不知道这个宝石有多有用。到目前为止,我只需要稍微调整一下代码。

我还为记录提供了一个虚拟属性hashid,这样我就可以轻松地访问它。

代码语言:javascript
复制
attr_accessor :hashid
after_find :set_hashid

private
    def set_hashid
        self.hashid = self.to_param
    end
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32288671

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档