如何在Rails 4中的控制器中的方法之间共享变量?

时间:2013-09-18 01:08:42

标签: ruby-on-rails ruby variables controller ruby-on-rails-4

我正在尝试学习Ruby on Rails,所以我正在做的一个项目是开发一个应用程序,你输入一个URL,点击提交,服务器开始从该URL下载文件,然后你看到显示下载详细信息的页面(定期从服务器更新)。我还没有了解Ruby中实例变量与类变量的一些特性,我做了一些可怕的事情:

class ProgressWebsController < ApplicationController
  layout "application"
   include ActionController::Live

  before_action :set_progress_web, only: [:edit, :update, :destroy]
  @@thread
  @@test=0
  @@clonePW

  # GET /progress_webs
  # GET /progress_webs.json
  def index
    @progress_web=ProgressWeb.new
  end

  def updateProgress
    puts "Not gonna happen"
  end

  # GET /progress_webs/1
  # GET /progress_webs/1.json
  def show
    puts "Downloading %s" % @@clonePW['url'].to_s
    @@thread = download(@@clonePW['url'].to_s)
    @progress_web=@@clonePW
    @@start = Time.now

  end

  # GET /progress_webs/new
  def new
    if( @@test.eql?("100.00"))
      puts "DOWNLOAD COMPLETE"
      @@thread.exit
      render :partial => "complete", :locals => { :progress_int => @@test, :done_int =>@@done, :elapsed_int =>@@elapsed_int }
      return
    end

    @@test= "%.2f" % @@thread[:progress].to_f 
    @@done= "%d" % @@thread[:done] 
    now = Time.now
    elapsed =now - @@start
    @@elapsed_int="%d" % elapsed
    render :partial => "progress", :locals => { :progress_int => @@test, :done_int =>@@done, :elapsed_int =>@@elapsed_int }
  end

def download(url)
Thread.new do
  thread = Thread.current
  body = thread[:body] = []
  url = URI.parse url
  Net::HTTP.new(url.host, url.port).request_get(url.path) do |response|
    length = thread[:length] = response['Content-Length'].to_i
    response.read_body do |fragment|
      body << fragment
      thread[:done] = (thread[:done] || 0) + fragment.length
      thread[:progress] = thread[:done].quo(length) * 100
    end
   end
 end
end

首先,我无法让它调用updateProgress方法,它继续显示&#34;显示&#34;,并传递&#34; updateProgress&#34;作为参数&#34; id&#34;。我没有过多地摆弄这个,而是劫持了新的&#34;方法,并让我的jQuery调用,每次它想要下载状态的更新。请原谅我,在学习基础知识之前,我可能会比我咀嚼更多。

其次,一次只能有一个人使用这个webapp,因为我必须使用类变量而不是实例变量。如果我使用了实例变量,那么当一个方法查看另一个方法应该设置的值时,它们将是零。阅读为什么会这样,我想我明白了,但解决方案是什么?是否有一种简单的方法可以在rails中的控制器中的方法之间共享值?我在这里找到了一个类似的问题,答案建议在模型中进行计算,但这对我的目的是否有效?

2 个答案:

答案 0 :(得分:3)

是的,很容易陷入Ruby on Rails的混乱局面。它有时甚至被称为“脱轨”。问题是,如果你不花一些时间“重新上路”,那么你很快就会开始训练。那些火车车轮在泥浆里运行不好;)

一旦你发现自己做了“劫持”新“方法”和“类变量而不是实例变量”之类的事情,那么你已经离开了轨道。

我会再次尝试你要做的事情。当我遇到你的情况时,我试过“修理”但它往往会变得更糟,而不是更好!

所以我会重新开始,这一次更加努力地坚持标准。使用REST作为路由和控制器方法 - 'update',而不是updateProgress。我建议你实际使用rails生成器来生成控制器和模型。另外,在添加之前,请确保您的应用程序在没有ajax的情况下以标准方式运行。不确定你是否有。

保存后,您可以使用更好的redirect_to更改“保持显示页面”等内容。请参阅api示例。 对不起,如果这不是您正在寻找的直接答案,但我认为这是一个有效的长期答案:)

发电机:http://guides.rubyonrails.org/command_line.html#rails-generate

路由:http://guides.rubyonrails.org/routing.html#这使您可以定义资源并使用标准控制器方法。

您可能也想在开始时使用脚手架,这将为您布置所有RESTful内容。这里有一篇很棒的帖子:http://viget.com/extend/rails-3-generators-scaffolding

答案 1 :(得分:2)

上面代码的问题是你试图在控制器中放入太多逻辑。

您的控制器的create应该只使用网址创建DownloadJob。仅此而已,只需创建作业并将其存储在数据库中。完成后,将用户重定向到控制器的show方法。该方法通过其DownloadJob加载id并呈现其状态或进度。这部分很简单。您可以按照任何有关CRUD控制器和基本模型的指南进行操作。

注意:您暂时不下载任何内容,因此process的{​​{1}}始终为空。

下一部分更有趣。创建DownloadJob后,它应该开始下载。无需涉及控制器。在下载DownloadJob时,它可以使用当前的DownloadJob更新自己。

process

建议阅读:http://guides.rubyonrails.org/active_record_callbacks.html

目前,下载Web资源会阻止您的控制器,因为在class DownloadJob < ActiveRecord::Base after_save :download # ... private def download uri = URI.parse url Net::HTTP.new(uri.host, uri.port).request_get(uri.path) do |response| received = 0 length = response['Content-Length'].to_i response.read_body do |fragment| body << fragment received += fragment.length self.update_attribute(:progress => (received.quo(length) * 100)) end end end end 回调完成之前new没有返回。 after_save始终会显示show 100%。

为避免阻止控制器,请在后台处理下载。使用process或类似的gem来执行此操作。这也允许同时下载多个URL,如果需要,只需启动更多delayed_jobs工作人员。

建议阅读:https://github.com/collectiveidea/delayed_job/

得到的结果:即时返回创建方法。如果您观看DelayedJob方法(通过常规JavaScript调用),您会看到下载的进度。多用户支持,多并行下载支持。