Яндекс.Фотки+Carrierwave на Rails 3
Использовать свой сервер для хранения больших фото порой бывает дорого, а если вы хотите еще и хранить разные версии одного и того же изображения (например: иконка, средний размер и оригинал), то часто проделывание стольких преобразований над каждым файлом требует большого количества процессорного времени. Яндекс.Фотки предоставляет API, которые, конечно не идеальны (в смысле я бы расширил их функционал), однако, могут решить вышеуказанные проблемы. Ниже будет описано как интегрировать Яндекс.Фотки в Rails 3 через Carrierwave.
Для начала нужно зарегистрироваться на Яндексе. И дальше есть 2 способа: самому разобраться в API или воспользоваться готовым гемом под Carrierwave. Я воспользусь вторым способом.
gem carrierwave-yandexfotki
Гем придумал и написал nicck, за что ему огромное спасибо, уважение и почет. Однако, гем был написан в начале прошлого года, поэтому немного устарел, а точнее стал чуть-чуть не совместим с текущей версией Rails и Ruby.
установка
Добавляем в Gemfile:
gem 'carrierwave' gem 'carrierwave-yandexfotki' |
Причем именно в таком порядке иначе будет ошибка.
Теперь по традиции бандлим:
bundle install |
Тут могут возникнуть проблемы с зависимостями для Nokogiri:
... Installing curb (0.8.0) with native extensions Installing nokogiri (1.5.4) with native extensions Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension. /usr/local/rvm/rubies/ruby-1.9.2-p290/bin/ruby extconf.rb checking for libxml/parser.h... no ----- libxml2 is missing. please visit ... for help with installing dependencies. ----- *** extconf.rb failed *** ... |
В таком случае надо пройти по предложенной ссылке и устранить зависимости, после чего повторить bundle install
.
Для RedHat-линуксов зависимости устраняются так:
yum install -y libxml2 libxml2-devel libxslt libxslt-devel |
carrierwave
Теперь также как и в случае с Uploadify нужно сгенерировать аплодер carrierwave:
$ rails g uploader image |
У меня модель с фотографией называется Picture
и у нее есть текстовое поле Image
, все дальше описанное будет описываться в этим условием.
Теперь надо открыть сгенерированный аплодер (app/uploaders/image_uploader.rb) и привести его к такому же виду как и на странице гема на гитхабе:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class ImageUploader < CarrierWave::Uploader::Base storage CarrierWave::Storage::YandexFotki yandex_login 'login' yandex_password 'password' before :cache, :remove_old_file_before_cache def remove_old_file_before_cache(new_file) remove! unless blank? end end |
Теперь надо примонтировать аплодер к модели (у меня Picture):
1 2 3 | class Picture < ActiveRecord::Base mount_before_save_uploader :image, ImageUploader end |
И тут вроде бы все, казалось бы уже можно открыть консоль:
$ rails c Loading development environment (Rails 3.1.1) > pic=Picture.new > pic.remote_image_url='http://kremlin.ru/putin-platit-churovu-za-vybory.jpg' > picture.save NameError: uninitialized constant YandexFotki::Connection::Nokogiri from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/carrierwave-yandexfotki-0.0.1/lib/yandexfotki/connection.rb:67:in `block in get_token' ... |
Чтобы устранить этот косяк нужно открыть тот самый файл из ошибки (у меня /usr/local/rvm/gems/ruby-1.9.2-p290/gems/carrierwave-yandexfotki-0.0.1/lib/yandexfotki/connection.rb), найти строчку № 67:
1 | xml = Nokogiri::XML(key_xml) |
После чего вернуться в начало файла и дописать (выделено фиолетовым):
1 2 3 4 5 | require "yandexfotki/encryptor" require 'nokogiri' module YandexFotki ... |
После этого у меня все заработало.
эксплуатация
В принципе она описана здесь, но я ее повторю.
Загрузка файла может осуществляться как и в обычном варианте Carrierwave, я имею ввиду код в контроллере/моделе:
1 2 3 4 | pic = Picture.new pic.image = params[:file] pic.save! pic.image.url |
Варианты изображений можно получить так:
1 2 | pic.image.url # ссылка на оригинал pic.image.url(:xl) # ссылка на 800x800 |
Таблица соответсвий аргументов к методу url и версии изображения:
Если нужно помимо яндекс.фоток сделать еще один аплодер и возникает ошибка типа:
TypeError: can’t convert nil into String
from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/carrierwave-0.5.8/lib/carrierwave/uploader/url.rb:18:in `expand_path’
То нужно в настройке второго аплодера путь хранилища сделать:
Rails.root.to_s + “/public/”+”uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}”
И для получения url изображения от второго аплодера обращаться как-то так:
Picture.last.slider_image.thumb.path
Обычное обращение: Picture.last.slider_image.thumb выдаст ошибку
Если соединение между сервером и ЯФ часто обрывается, чтобы как-то снизить процент отказов можно сделать вот так в /usr/local/rvm/gems/ruby-/gems/carrierwave-yandexfotki-0.0.1/lib/yandexfotki/connection.rb:
…
def get_token
@token ||= Rails.cache.fetch “YandexFotki:token:#{@login}” do
url = “http://auth.mobile.yandex.ru/yamrsa/key/”
key_xml = http.get(url) while !defined?(key_xml) || key_xml.include?(“502 Bad Gateway”)
xml = Nokogiri::XML(key_xml)
…