2015-08-29 38 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