Яндекс.Фотки+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 и версии изображения:


2 Comments to “Яндекс.Фотки+Carrierwave на Rails 3”

  1. lukmus пишет:

    Если нужно помимо яндекс.фоток сделать еще один аплодер и возникает ошибка типа:
    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 выдаст ошибку

  2. lukmus пишет:

    Если соединение между сервером и ЯФ часто обрывается, чтобы как-то снизить процент отказов можно сделать вот так в /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)

Leave a Reply to lukmus

(обязательно)

(обязательно)