如何将独立的Python脚本集成到Rails应用程序中?

How to integrate a standalone Python script into a Rails application?

我有一个程序正在运行,它有一个小的文件结构,然后用

1
python do_work.py foo bar

我想让我的Rails用户按下一个按钮,让他们这样做,结果要么上传到某个地方,要么作为下载链接或者类似的东西扔给他们——EDOCX1的输出(比如说,它是result.txt)。

我还想澄清一下,脚本会在文件系统上创建3个独立的文件,这些文件不是文本文件(这不重要,也不是真正的问题)

最好的方法是什么?rake可以运行exec python吗?更重要的是,这在Heroku上可行吗?

我的系统上安装了python,但sockmamk提供的答案似乎不起作用——它返回零。注意,其他命令,如ls,似乎有效。

可能是权限问题吗?

1
2
3
4
def index
    value = %x( python --version )
    render :text => value
end

顺便说一下,在irb中尝试:

1
%x(python)

打开IRB内部的python终端。但是,无论出于什么原因,它都不会获取参数。


您的index方法不起作用,因为python --version将其版本输出到stderr,而不是stdout。如果不需要分离这些流,可以将stderr重定向到stdout:

1
value = %x(python --version 2>&1)

此调用是同步的,因此在运行脚本(python do_work.py foo bar 2>&1之后,您应该能够读取它生成的文件。

如果脚本由于某种原因无法创建文件,您现在将在value变量中看到异常,因为错误消息通常发送到stderr。

如果要将stderr与stdout分开,请使用open3模块。

请注意,运行脚本需要一些时间,因此调用可能会重叠。我会在这里排队以防发生这种情况。

别忘了检查用户输入的数据。千万不要直接传递给脚本。


这部分取决于数据的格式。如果它不太长,可以直接在浏览器中呈现,您可以在Rails控制器中执行类似的操作:

1
2
result = `python do_work.py foo bar`
render :text => result

假设结果是纯ASCII文本,结果将直接进入浏览器。如果要进行工作的参数来自用户,则必须首先验证它们,这样您就不会最终为自己造成严重的漏洞。在这种情况下,使用System()调用可能更安全。

如果您想将结果作为一个文件发送回来,请查看Ruby的tempfile类来创建该文件(以一种不会永远保留的方式),以及Rails的send_file和send_data命令,以获得一些不同的选项来以这种方式发送结果。


Utapyngo的答案几乎涵盖了你需要知道的所有内容。我会回答这一部分:

incidentally, trying this in irb:
%x(python)
Brings up the python terminal INSIDE of irb. It will not take params for whatever reason however.

要将参数传递给Python脚本,只需传递它。例子:

1
2
3
4
5
6
7
8
[fotanus@thing ~]$ python a.py
args:
['a.py']
[fotanus@thing ~]$ irb
1.8.7 :001 > %x(python a.py foo bar)
 =>"args:
['a.py', 'foo', 'bar']
"

这适用于Ruby1.8、1.9和2.0。


我会做如下的事情。

在后台异步执行此任务。一旦结果准备好,就向用户报告。

有一种方法可以通过使用open3和delayed-job-gem来实现这一点。

看看open3模块中的popen3方法。

1
2
3
4
5
Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
  pid = wait_thr.pid # pid of the started process.
  ...
  exit_status = wait_thr.value # Process::Status object returned.
}

在您的案例中,您可以将Open3.popen3语句更改为如下内容

1
2
3
4
5
Open3.popen3("python do_work.py foo bar"){
  ...
  # mechanism for reporting like setting a flag in database system
  # or queue system
}

注意:应该给出python脚本的完整路径

然后使用延迟的作业gem将其作为后台任务运行。

您还应该有一个轮询机制,该机制将轮询系统,以查看是否设置了标志,这意味着结果已经准备好,然后将其提供给用户。


这取决于您希望集成Python脚本的深度。有一些方法可以直接从Ruby调用Python模块。

网址:http://www.goto.info.waseda.ac.jp/~fukusima/ruby/python-e.html

这将使您受益于直接从Python脚本获得输出,而不是遍历I/O设备。