несколько вложений скрепки с процессором водяных знаков

У меня масса проблем с загрузкой нескольких вложений с помощью скрепки и их обработкой водяным знаком.

У меня есть 2 модели, объявление и фото. Объявление has_many :photos и Фотография принадлежит :ad.

Точнее в /models/ad.rb у меня есть:

class Ad < ActiveRecord::Base

  has_many :photos, :dependent => :destroy
  accepts_nested_attributes_for :photos, :allow_destroy => true  
end

и мой файл photo.rb выглядит так:

class Photo < ActiveRecord::Base

belongs_to :ad

has_attached_file :data,
:styles => {
  :thumb => "100x100#",
  :first => {
    :processors => [:watermark],
    :geometry => '300x250#',
    :watermark_path => ':rails_root/public/images/watermark.png',
    :position => 'SouthEast' },
  :large => {
    :processors => [:watermark],
    :geometry => '640x480#',
    :watermark_path => ':rails_root/public/images/watermark.png',
    :position => 'SouthEast' }
}
end

На мой взгляд, я использую это, чтобы добавить поля файла

<% f.fields_for :photos do |p| %>

  <%= p.label :data, 'Poza:' %> <%= p.file_field :data %>

<% end %>

В моем контроллере в действии редактирования я использую 4.times {@ad.photos.build} для создания полей файла.

Все это работает отлично и денди, если я не использую обработчик водяных знаков, если я использую обычное объявление has_attached_file, например:

has_attached_file :data,
:styles => {
  :thumb => "100x100#",
  :first => '300x250#',
  :large => '640x480#'
}

Но когда я использую процессор водяных знаков, я всегда получаю эту ошибку:

 NoMethodError in PublicController#update_ad

 You have a nil object when you didn't expect it!
 You might have expected an instance of ActiveRecord::Base.
 The error occurred while evaluating nil.[]
  ..............................
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:350:in `assign_nested_attributes_for_collection_association'
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:345:in `each'
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:345:in `assign_nested_attributes_for_collection_association'
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:243:in `photos_attributes='
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2746:in `send'
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2746:in `attributes='
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2742:in `each'
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2742:in `attributes='
 /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2628:in `update_attributes'
 /home/alexg/Sites/vandmasina/app/controllers/public_controller.rb:217
 /home/alexg/Sites/vandmasina/app/controllers/public_controller.rb:216:in `update_ad'

Параметры в порядке, насколько я могу судить

 Parameters:

 {"commit"=>"Salveaza modificarile",
  "ad"=>{"price"=>"6000",
  "oras"=>"9",
  "photos_attributes"=>{"0"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-b42noe-0>},
  "1"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-r0ukcr-0>},
  "2"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-mb23ei-0>},
  "3"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-1bpkm3b-0>}},

Процессор водяных знаков /lib/paperclip_processors/watermark.rb выглядит так:

  module Paperclip
class Watermark < Processor

class InstanceNotGiven < ArgumentError; 
end

def initialize(file, options = {},attachment = nil)
  super
  @file = file
  @current_format = File.extname(@file.path)
  @basename = File.basename(@file.path, @current_format)
  @watermark = ':rails_root/public/images/watermark.png'
  @current_geometry = Geometry.from_file file # This is pretty slow
  @watermark_geometry = watermark_dimensions
end

def watermark_dimensions
  return @watermark_dimensions if @watermark_dimensions
  @watermark_dimensions = Geometry.from_file @watermark
end

def make
  dst = Tempfile.new([@basename, @format].compact.join("."))
  watermark = " \\( #{@watermark} -extract #{@current_geometry.width.to_i}x#{@current_geometry.height.to_i}+#{@watermark_geometry.height.to_i /
                2}+#{@watermark_geometry.width.to_i / 2} \\) "
  command = "-gravity center " + watermark + File.expand_path(@file.path) + " " +File.expand_path(dst.path)

  begin
    success = Paperclip.run("composite", command.gsub(/\s+/, " "))
  rescue PaperclipCommandLineError
    raise PaperclipError, "There was an error processing the watermark for #{@basename}" if @whiny_thumbnails
  end
  dst
end

end
end

Я попробовал процессор в обычном приложении, без нескольких вложений, и он работает отлично. Насколько я могу судить, это не работает с вложенными_атрибутами.

Приложение представляет собой rails 2.3.5 с ruby ​​1.8.7 и скрепкой 2.3.11.

Если вы можете оказать какую-либо помощь, это будет очень признательно, так как я пытаюсь понять это уже 2 дня :)


person v3rt1go    schedule 28.09.2010    source источник


Ответы (3)


О, чувак, это было тяжело!

В вашем коде мало ошибок, и ни одна из них не связана с вложенными моделями. Мое объяснение для Rails 3 и Paperclip 2.3.3

а) :rails_root не работает. Эта интерполяция используется только в URL/пути, а не в пользовательских параметрах. Поэтому вы должны заменить его на Rails.root.join("public/images...")

б) вы просто игнорируете параметр :watermark_path и используете только жестко заданный путь (в методе инициализации). Так что не имеет значения, что у вас есть в вашем :styles, так как это всегда означает .../images/watermark.png. Штука :rails_root снова там, поэтому она не может работать.

c) когда вы передаете параметр Paperclip.run("composite", "foo bar there"), он фактически выполняет эту команду:

composite 'foo bar there'

вы видите одинарные кавычки? Из-за этого составная команда видит ваши параметры как один огромный параметр и совершенно его не понимает. Если вы передаете его как массив, то каждый элемент заключен в кавычки, а не массив в целом.

Итак, вот улучшенная версия процессора водяных знаков:

module Paperclip
  class Watermark < Processor

  class InstanceNotGiven < ArgumentError;
  end

  def initialize(file, options = {},attachment = nil)
    super
    @file = file
    @current_format = File.extname(@file.path)
    @basename = File.basename(@file.path, @current_format)
    # PAWIEN: use default value only if option is not specified
    @watermark = options[:watermark_path] || Rails.root.join('public/images/watermark.png')
    @current_geometry = Geometry.from_file file # This is pretty slow
    @watermark_geometry = watermark_dimensions
  end

  def watermark_dimensions
    return @watermark_dimensions if @watermark_dimensions
    @watermark_dimensions = Geometry.from_file @watermark
  end

  def make
    dst = Tempfile.new([@basename, @format].compact.join("."))
    dst.binmode

    begin
      # PAWIEN: change original "stringy" approach to arrayish approach
      # inspired by the thumbnail processor
      options = [
        "-gravity",
        "center",
        "#{@watermark}",
        "-extract",
        "#{@current_geometry.width.to_i}x#{@current_geometry.height.to_i}+#{@watermark_geometry.height.to_i / 2}+#{@watermark_geometry.width.to_i / 2}",
        File.expand_path(@file.path),
        File.expand_path(dst.path)
      ].flatten.compact.join(" ").strip.squeeze(" ")

      success = Paperclip.run("composite", options)
    rescue PaperclipCommandLineError
      raise PaperclipError, "There was an error processing the watermark for #{@basename}" if @whiny_thumbnails
    end
    dst
  end

  end
end

Надеюсь, это помогло вам!

ОБНОВЛЕНИЕ: вам необходимо использовать последнюю версию скрепки из github.

gem 'paperclip', '>= 2.3.3', :git => "http://github.com/thoughtbot/paperclip.git"

В этой версии форматы #run были снова изменены, поэтому я обновил код. Это действительно должно работать, поскольку я создал тестовое приложение, и оно делает то, что предполагалось.

ОБНОВЛЕНИЕ 2: репозиторий с рабочим примером:

git://repo.or.cz/paperclip-mass-example.git
person Radek Paviensky    schedule 28.09.2010
comment
Спасибо за ответ. Сейчас вроде лучше, но ошибка все равно появляется. - person v3rt1go; 29.09.2010
comment
неправильное количество аргументов (8 из 3) в PublicController#update_ad Трассировка выглядит следующим образом: paperclip_processors/watermark.rb:40: in run paperclip_processors/watermark.rb:40: in make controllers/public_controller.rb:217 controllers/public_controller. rb:216:in update_ad У меня действие по обновлению классическое для 2.3, никаких изменений там нет. - person v3rt1go; 29.09.2010
comment
Кажется, ошибка в строке Paperclip.run(...). В последнее время произошли некоторые изменения, и это зависит от того, какую версию скрепки вы используете. Просто откройте файл .../lib/paperclip/thumbnail.rb (из вашего гема, так что он будет где-то в ~/.rvm) и посмотрите там. Кстати, у меня нет проблем с его запуском. - person Radek Paviensky; 29.09.2010
comment
История этой штуки довольно дикая :-) github.com /thoughtbot/paperclip/commits/master/lib/paperclip/ - person Radek Paviensky; 29.09.2010
comment
аааа!!! Я взгляну. Иногда я скучаю по старому доброму багги RMagick :)) Большое спасибо m8, я вернусь с отзывами - person v3rt1go; 29.09.2010
comment
Обновление до paperclip 2.3.3 вернуло исходную ошибку NoMethodError in PublicController#update_ad Это наводит меня на мысль, что изменения, внесенные в watermark.rb, обновили команду для работы с paperclip 2.3.3, но не исправили первоначальную ошибку. Теперь происходит то же самое, он теряет photo_attributes после обработки. - person v3rt1go; 29.09.2010
comment
Я попытаюсь создать приложение rails 3 с несколькими вложениями скрепки 2.3.3 и этим файлом водяного знака. Если это сработает, я обновлю основное приложение до rails 3. В любом случае это нужно было сделать давным-давно. - person v3rt1go; 29.09.2010
comment
быстрое обновление - проблема в том, что вы должны использовать головную версию из git, например: gem 'скрепка', '›= 2.3.3', :git =› github.com/thoughtbot/paperclip.git Я просмотрел свой проект, в котором используется скрепка для массового назначения, и это было так (есть некоторая ошибка который удаляет параметры при доступе к ним) - person Radek Paviensky; 29.09.2010
comment
Та же ошибка m8 на рельсах 2.3.5. Я использовал драгоценный камень скрепки 2.3.3, но безрезультатно. Мне придется обновить приложение до rails 3.0, прежде чем пытаться что-то еще. Спасибо за огромные усилия, я вернусь с новостями после обновления - person v3rt1go; 29.09.2010
comment
Я подготовил рабочий пример (только для Rails 3). Работает как шарм... git clone repo.or.cz/r/paperclip -mass-example.git - person Radek Paviensky; 29.09.2010
comment
Да, работает как рекламируется. Правильный URL-адрес git для вашего репозитория: git://repo.or.cz/paperclip-mass-example.git . Я сделал то же самое с новым приложением rails 3.0, и оно отлично работает. Мне просто нужно обновить приложение до 3.0, но это такое огромное приложение, что я никогда не нахожу времени, чтобы обновить его :) Что касается примера с массой скрепки, я думал добавить к нему некоторые дополнительные функции, например обрезка изображения, генерация динамического поля, возможно, немного магии AJAX и выложите это на GitHub, если вы согласны, то есть :) - person v3rt1go; 29.09.2010
comment
Единственное приложение для водяных знаков на GitHub — очень старое, 2009 года выпуска, и оно не работает с массовым назначением, так что людям это может понадобиться. - person v3rt1go; 29.09.2010
comment
супер! Я надеюсь, что ваше обновление будет гладким. Конечно, вы можете использовать этот пример по своему усмотрению — я очень рад, что наши усилия приведут к чему-то полезному для всех. - person Radek Paviensky; 30.09.2010

Если вы используете рельсы 3 и скрепку > 2.3.3, попробуйте https://gist.github.com/843418 источник.

person Ovcharenko Vladimir    schedule 06.10.2011

На первый взгляд кажется, что путь к водяному знаку должен быть "#{Rails.root}/...", хотя похоже, что здесь происходит много всего.

Кроме того, я не вижу вашу форму, как в form_for. Убедитесь, что у вас есть {:multipart => true}

person abdollar    schedule 28.09.2010
comment
Если вы имеете в виду объявление в файле модели, я попробую, хотя до этого все равно не доходит. - person v3rt1go; 28.09.2010
comment
В watermark.rb по пути @atermark у меня был RAILS_ROOT+'/public/images/watermark.png', но это ничего не изменило. Насколько я знаю, символ :rails_root работает так же. - person v3rt1go; 28.09.2010
comment
Помещение чего-либо в кавычки — это буквальная строка ':rails_root' не является символом — это строка - person abdollar; 28.09.2010
comment
Хех ты прав. Пропустил кавычки там, просто чертовски устал. Собираюсь изменить его обратно и сообщить вам результаты, хотя я не думаю, что это причина. - person v3rt1go; 28.09.2010
comment
Пробовал, как я уже сказал, разницы нет. Он даже не доходит до части пути водяного знака. Проблема связана с вложенными_атрибутами. Почему-то процессор скрепок с ними плохо работает. - person v3rt1go; 29.09.2010
comment
проверьте, что ваша форма имеет составной набор - person abdollar; 29.09.2010
comment
Это здесь. Если я не использую процессорную часть, фотографии отправляются, и все работает. Проблемы начинаются, когда я пытаюсь использовать процессор водяных знаков. - person v3rt1go; 29.09.2010