Загрузка файлов без обновления страницы в Ruby on Rails

(Ruby & Rails) · English (86,201 views)

Друзья часто спрашивают меня, как загружать файлы на сервер при помощи AJAX, и обычно получают ответ “никак”. Ответ, конечно, правильный, но что если действительно нужно загрузить файл без полного обновления страницы? И, конечно, в этом случае хотелось бы использовать RJS. В этой заметке я расскажу, что делать, чтобы получить эффект, похожий на загрузку файлов при помощи AJAX (кстати, Gmail использует эту технику).

Для начала, знаете ли вы, что у элемента form есть атрибут target? Если указать его, данные формы будут отправлены во фрейм, название которого указано в атрибуте target. Конечно, возможно использовать iframe, причем он может быть скрытым! Взгляните на следующий HTML:

1
2
3
4
5
<form target="upload_frame" action="/test/upload_action" id="upload_form" method="post" enctype="multipart/form-data">
  <input type="file" name="uploaded_file" /><br />
  <input type="submit" />
</form>
<iframe id="upload_frame" name="upload_frame" style="display: none"></iframe>

Когда вы нажмете кнопку “Submit”, форма будет отправлена в скрытый iframe, и будет вызван соответствующий метод контроллера на сервере. Но результирующий RJS вернется в скрытый фрейм! Необходимо получить результирующие данные и выполнить их в контексте всей страницы (родительского окна для фрейма). Существует одна интересная техника: Remote Scripting with IFRAME, и ее реализация в виде плагина Ruby on Rails здесь. Все, что необходимо, это обернуть render в блок responds_to_parent. Пример использования:

1
2
3
4
5
6
7
8
9
10
11
class TestController < ActionController::Base
  def upload_action
    # Do stuff with params[:uploaded_file]

    responds_to_parent do
      render :update do |page|
        page.replace_html 'upload_form', :partial => 'upload_form'
      end
    end
  end
end

Просто, не правда ли?

32 Responses to this entry

Subscribe to comments with RSS

Gomes
said on 06.11.2006 at 12.04 · Permalink

Классная статья, спору нет. Созрел только небольшой вопросик как отследить загрузился ли файл на сервер, ведь существует куча преград при загрузке (размер файла превышает разрешенный и т.п.). Отдавать с сервера страницу с JavaScript, который бы дернул функцию на странице как то не красиво (да и не всегда сработает), а как узнать кроссбраузерно что пришло в теле страницы с сервера для меня загадка, если не сложно прошу расширения статьи.

DEkart @
said on 20.11.2006 at 17.04 · Permalink

Попробуем применить на практике. Еще было бы интересно состыковать эту штуку с плагином upload_progress

said on 20.11.2006 at 17.10 · Permalink

Ага, были такие мысли, займусь на досуге.

said on 20.11.2006 at 21.30 · Permalink

[...] There is no way to upload files using AJAX. How Gmail does it then? Well, the answer is using <iframe>. Here is a post that describe this technique in detail. Infact we at Vinayak Solutions are using this technique from months, obviously inspired by Gmail. ;-) [...]

Anton Kirsanov @
said on 23.11.2006 at 10.35 · Permalink

Добавлю только, что для проверки статуса достаточно запустить интервалом в секунду калбэк функцию (я о javascript говорю), которая будет смотреть readyState у окна в скрытом фрейме.

DEkart @
said on 23.11.2006 at 18.44 · Permalink

Спасибо, погляжу

Maximark @
said on 23.11.2006 at 18.58 · Permalink

По поводу загрузки файлов без обновления, напоминаю прекрасную библиотеку dklab.ru
http://dklab.ru/lib/JsHttpRequest/

Версия 4.0

я уже писал как то про неё, но эффекта было ноль. И вот… получите и спокойно пользуйтесь. На сегодня я думаю это самое лучшее реализация технологии AJAX. И тем паче загрузки файлов без перезагрузки страницы !!!
Это не реклама… я сам давно пользуюсь и не я её писал.

said on 01.12.2006 at 9.36 · Permalink

[...] There is no way to upload files using AJAX. How Gmail does it then? Well, the answer is using <iframe>. Here is a post that describe this technique in detail. Infact we are using this technique from months, obviously inspired by Gmail. [...]

said on 04.01.2007 at 2.46 · Permalink

great article! its a tricky problem but your solution works like a charm ;-)

Rails Developer
said on 29.01.2007 at 21.00 · Permalink

Thanks for the help but from the Apple site, %{style=”display: none”} doesn’t work on the iframe but if you set it to %{style=”height:0;width:0;border:0;”} then it will work.

said on 12.02.2007 at 23.58 · Permalink

Hey, nice article.. I actually wrote a plugin that does this. I’m using it in a couple places, but had to write it so quickly that I wasn’t able to adequately test it on all platforms. You can check it out here: http://rubyforge.org/projects/remote-upload/

Please tell me what you think

John
said on 16.02.2007 at 19.20 · Permalink

I’m using your code almost exactly and most of it seems to be working, but when i try to do something with the uploaded_file all it has is the filename, not the actual file data. Any ideas?

said on 13.03.2007 at 19.17 · Permalink

Great article! Thanks! I’ve combined your solution with attachment_fu plugin and result is awesome! Thanks!

said on 23.04.2007 at 11.37 · Permalink

Спасибо а идею реализации. Думаю что этой техникой можно пользотаться и в других случаях.

jeffguroo @
said on 11.12.2007 at 0.22 · Permalink

Seems as though the problem with the lack of data being transfered is a problem with Firefox. When I use ff the files are always empty, however when I use Exploder, the data is carried over.

jeffguroo @
said on 11.12.2007 at 0.24 · Permalink

this solution only seems to work on txt files. Formatting for PDFs and Word Docs were hosed.

jeffguroo @
said on 12.12.2007 at 0.26 · Permalink

Alright, that was because I was trying to do it with remote_form instead of a form_for. Only the text was making it through. BTW what was the name of the plugin that was used for returning js to the iframe? That link is dead.

jeffguroo @
said on 12.12.2007 at 2.46 · Permalink

The above mentioned plugin is: respondes_to_parent

said on 12.12.2007 at 6.35 · Permalink

jeffguroo, you right
It’s impossible to upload file using AJAX’s XMLHttpRequest. So I have written this post to show how to do it using iframe.

Thanks for comment about broken link, I have fixed it.

jeffguroo @
said on 12.12.2007 at 7.34 · Permalink

after beeting my head against this all day, I have found that doing a simple

1
render :partial => "successful_attachment"

also works quite well in Rails v1.2.3 and the acts_as_attachment plugin. Thanks for the file upload/AJAX workaround… a lifesaver.

said on 07.01.2008 at 4.08 · Permalink

All you really need is the first part. The form’s target=”IFrameName” is all that really matters.

As far as the IFrame. You can give it a width and height, and then any text that you generate in the php upload file will show there.

Really simple.

Venkat @
said on 05.02.2008 at 16.45 · Permalink

Hi I have tried this in my app. In my app, I have a partial to display my form to upload files and in another partial i am listing the files uploaded. right now I have to redirect the page after uploading the files. But how display my file list partial initially and update it with adding the newly added file info every time i upload a new file…
any help appreciated

regards,
venkat

exip
said on 21.11.2008 at 18.31 · Permalink

Есть плугин для jQuery, который использует похожую технику.

Comments are closed

Comments for this entry are closed for a while. If you have anything to say – use a contact form. Thank you for your patience.