2013-04-30 14 views
28

私が起こっている小さなファイル構造を持つプログラムを持っているし、私はボタンを押すと、これは彼らのために起こる必要があり、その結果にするために私のRailsのユーザーがいずれかのどこかにアップロードしたいスタンドアロンのPythonスクリプトをRailsアプリケーションに統合する方法は?

python do_work.py foo bar 

を使用して実行されますまたは単にダウンロードリンクや種類のものとしてスローされた - do_work.pyの出力(例えば、result.txt

また、スクリプトが3つの別々のファイルのファイルシステムを作成することを明確にしたい。テキストファイルではありません(問題ではないはずです)。

どうすればいいですか? execでPythonを実行できますか?もっと重要なのは、これは英雄のことですか?

自分のシステムにPythonがインストールされていますが、sockmonkの回答がうまくいかないようです。これはnilを返します。あなたに気をつけてください。lsのような他のコマンドが動作するようです。

権限の問題である可能性がありますか?

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

ところで、irbでこれをしよう:

%x(python) 

は、IRBのPythonのターミナルINSIDEを表示します。しかし、何らかの理由でparamsを取ることはありません。

+0

これはRailsよりもRubyのほうが多いと思います。これを達成するにはいくつかの方法があると思われますが、ここでそれらを見つけてください - http://stackoverflow.com/questions/2232/calling-bash-commands-from-ruby –

答えて

26

python --versionがバージョンをSTDOUTではなくSTDERRに出力するため、indexメソッドが機能しません。あなたはこれらのストリームを分離する必要がない場合は、あなただけのSTDOUTにSTDERRをリダイレクトすることがあります。

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

この呼び出しは同期であるため、スクリプト(python do_work.py foo bar 2>&1)を実行した後、あなたはによって生成されたファイルを読むことができるはずですそれ。

何らかの理由でスクリプトがファイルを作成できない場合、エラーメッセージは通常STDERRに送信されるため、value変数に例外が表示されます。

STDERRとSTDOUTを分離する場合は、Open3モジュールを使用してください。

スクリプトの実行には時間がかかるので、呼び出しが重複する可能性があることに注意してください。私はこれを防ぐためにここにキューを使用します。

ユーザーが入力したデータを確認することを忘れないでください。それをスクリプトに直接渡さないでください。

+1

さて、私は今日何か新しいことを学んだ... –

+0

これをethereal/tmp/filesystemと結び付けてファイルをそこに保存する方法をコメントできますか? –

+0

一時的な書き込み可能なファイルシステム*を意味しますか?この質問を参照してください:[Herokuの一時ファイルシステムの使い方は?](http://stackoverflow.com/questions/12416738/how-to-use-herokus-ephemeral-filesystem)。 要求が処理された後に削除される可能性があるため、要求中にファイルを処理するだけで済みます。 – utapyngo

4

部分的にデータのフォーマットに依存します。それはあまりにも長くはありませんし、ブラウザで直接描画できる場合は、あなただけのレールコントローラにこのような何かを行うことができます。

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

そして、その結果はASCIIテキストで、結果がブラウザにまっすぐ行くと仮定し。 do_work.pyへのパラメータがユーザから来た場合は、最初にそれらを検証しなければならないので、あなた自身のために厄介な脆弱性を引き起こすことはありません。この場合、system()コールを使用するほうが安全でしょう。

結果をファイルとして返信したい場合は、ファイルを作成するためのRubyのTempfileクラス(永遠に残らないように)を見て、いくつかの異なるオプションのためのsend_fileとsend_dataコマンドをそのように結果を送り返す。

+0

もしそれが.exeのようなものなら?それは働くだろうか? –

+0

また、裸のレールアプリで動作するような例は得られないようです。 –

+0

'system()'がなぜ安全なのでしょうか? backtickは単に 'system()'のエイリアスです。 – Linuxios

3

utapyngoからの回答は、ほとんどあなたが知る必要があるすべてです。 IRBでこれをしようと、ついでに

:私はこの部分をお答えします %X(パイソン)を は、IRBの内側のpython端子を表示します。しかし、何らかの理由でparamsを取ることはありません。

パラメータをPythonスクリプトに渡すには、単にそれを渡します。例:

[[email protected] ~]$ python a.py 
args: 
['a.py'] 
[[email protected] ~]$ irb 
1.8.7 :001 > %x(python a.py foo bar) 
=> "args:\n['a.py', 'foo', 'bar']\n" 

これはruby 1.8,1.9および2.0で機能します。

1

これは、Pythonスクリプトをどの程度深く統合したいかによって異なります。 Rubyから実際にPythonモジュールを直接呼び出す方法があります。

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

これは、あなたのPythonスクリプトから直接出力を得る代わりに、I/Oデバイスを介して行くの利益を与えるだろう。

1

私は以下のようにします。

このタスクをバックグラウンドで非同期に実行します。そして、結果がすぐにユーザーに報告してください。

これを実現できる方法は、Open3delayed_job gemです。

Open3モジュールでpopen3メソッドを見てください。あなたはPythonスクリプトに

をフルパスを与えるそしてdelayed_jobを使用する必要があります:あなたは、次の

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

ノートのようなものにOpen3.popen3文を変更することができますあなたの場合は

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. 
} 

gemをバックグラウンドタスクとして実行する

システムをポーリングしてフラグが設定されているかどうかを確認し、結果が準備完了であることを意味するポーリングメカニズムも持っている必要があります。

関連する問題