【问题标题】:How do I implement hashids in ruby on rails如何在 ruby​​ on rails 中实现 hashids
【发布时间】:2015-08-29 17:10:16
【问题描述】:

我将继续并预先道歉,因为我是 ruby​​ 和 rails 的新手,而且我一生都无法弄清楚如何在我的项目中使用 hashids。该项目是一个简单的图像主机。我已经使用 Base58 对 sql ID 进行编码,然后在控制器中对其进行解码。但是我想让 URL 更加随机,因此切换到 hashids。

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

现在一些混乱从这里开始。我是否需要在使用 hashids.encode 和 hashids.decode 的每个页面上初始化 hashids

hashids = Hashids.new("mysalt")

我发现这篇文章 (http://zogovic.com/post/75234760043/youtube-like-ids-for-your-activerecord-models) 让我相信我可以将它放入初始化程序中,但是在这样做之后我仍然收到 NameError (undefined local variable or method `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 那样容易,我对如何让它工作感到困惑......任何帮助将不胜感激。

【问题讨论】:

    标签: ruby ruby-on-rails-4 hashids


    【解决方案1】:

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

    是的,您确实需要在要使用相同盐的任何地方对其进行初始化。建议您将盐定义为常数,可能在application.rb 中。

    您提供的链接将hashids 注入ActiveRecord,这意味着它在其他任何地方都不起作用。我不推荐使用相同的方法,因为它需要对 Rails 非常熟悉。

    您可能想花一些时间了解 ActiveRecord 和 ActiveModel。将为您节省大量重新发明轮子的工作。 :)

    【讨论】:

    • 即使我在每个文件中初始化 hashids 方法,它仍然会导致我无法弄清楚的问题。使用 Base58 类时,我可以在控制器中进行编码和解码而不会出现问题。使用 hashids.decode 时,它​​的工作方式似乎不同,这给了我“未定义的方法 'id' 错误”。看起来它没有解码它......如何正确解码控制器中的 id?我确实计划返回并在 railstutorials.org 上学习教程,并在此 id 问题解决后更好地了解 ruby​​ on rails。
    • @mroth7684:image.html.erb 中缺少右花括号。这是故意的吗?
    • 是的,它在页面的下方。我终于让它工作了。问题是 hashids 返回一个数组而不仅仅是整数。我只需要在解码后调整代码以使用数组。
    • @mroth7684:你能添加你找到的解决方案吗?
    【解决方案2】:

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

    >> my_id = ImageLink.last.id
    >> puts Hashids.new(my_id)
    

    如果不起作用,请将 gem 添加到 gemfile 中(无论如何,这会更有意义)。


    然后,我认为您应该在 ImageLink 模型中为您的 hash_id 添加一个 getter。 即使您不想将散列保存在数据库中,此散列也可以在您的模型中放置。有关详细信息,请参阅虚拟财产。

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

    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
    %> 
    

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

    【讨论】:

      【解决方案3】:

      我一直在寻找类似的东西来伪装我的记录的 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 2021-06-11
        • 1970-01-01
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多