2015-08-29 35 views
3

我会继续向前道歉,因为我是红宝石和铁轨的新手,我无法为我的生活弄清楚如何在我的项目中使用哈希实现。该项目是一个简单的图像主机。我已经使用Base58来编码sql ID,然后在控制器中解码它。不过,我想让URL更加随意,因此转而使用hashids。我如何在轨道上实现红宝石哈希

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

现在的一些混乱,从这里开始。我是否需要通过

hashids = Hashids.new("mysalt") 

我发现这个职位(http://zogovic.com/post/75234760043/youtube-like-ids-for-your-activerecord-models),这使我相信我可以把它变成一个初始使用hashids.encode和hashids.decode每一页上初始化hashids这样做,我不过之后我仍然得到NameError(为的ImageManager未定义的局部变量或方法`hashids':类)

所以在我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 /解码,我很困惑如何让它工作...任何帮助将不胜感激。

回答

1

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

是的,你需要将它初始化到与盐相同的地方。建议你将盐定义为一个常量,也许在application.rb

您提供的链接将hashids注入ActiveRecord,这意味着它不会在其他任何地方工作。我不会推荐相同的方法,因为它需要高度熟悉Rails。

你可能想花一些时间来理解ActiveRecord和ActiveModel。将会为您节省大量重新发明轮子。 :)

+0

即使我在每个文件中初始化hashids方法,它仍然会导致我无法弄清楚的问题。当使用Base58类时,我可以在控制器中进行编码和解码,而不会出现问题。当使用hashids.decode它似乎没有工作相同,这给了我“未定义的方法”id'错误“。 它看起来像它不解码...我如何正确解码控制器中的ID? 我打算回去做关于railstutorials.org的教程,并且一旦解决了这个id问题,就能更好地理解rails上的ruby。 – mroth7684

+0

@ mroth7684:您在'image.html.erb'中丢失了一个大括号。这是打算吗? – fylooi

+0

是的,它进一步在页面上。我终于搞定了。问题是hashids返回一个数组而不是整数。我只需要调整代码以在解码之后使用阵列。 – mroth7684

1

之前everythink如果Hashlib包含在你的项目,你应该只是为了测试,你可以在你的项目文件夹中运行命令rails c,使只是一个小测试:如果不能正常工作

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

,加gemfile中的gem(无论如何,它使得更多的感知)。


然后,我认为你应该在你的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 
%> 

所有这些代码没有进行测试......

0

我一直在寻找的东西类似的地方我可以伪装我的记录的ID。我遇到了act_as_hashids

https://github.com/dtaniwaki/acts_as_hashids

这个小宝石无缝集成。您仍然可以通过ID找到您的记录。或与散列。在嵌套记录中,您可以使用方法with_hashids

要获得散列,请在对象本身上使用to_param,这会导致与此类似的字符串ePQgabdg

因为我刚刚实现了这一点,我不能说这个宝石是多么有用。到目前为止,我只需要调整一下我的代码。

我也给记录一个虚拟属性hashid,所以我可以很容易地访问它。

attr_accessor :hashid 
after_find :set_hashid 

private 
    def set_hashid 
     self.hashid = self.to_param 
    end