спасти! метод ссылочных атрибутов в mongoid - PullRequest
2 голосов
/ 15 июня 2011

Я использую Rails 3.0.6 с mongoID 2.0.2.Недавно я столкнулся с проблемой сохранения!метод при переопределении сеттера (я пытаюсь создать свои собственные вложенные атрибуты).

Итак, вот модель:

class FeedItem
  include Mongoid::Document
  has_many :audio_refs

  def audio_refs=(attributes_array, binding)

    attributes_array.each do |attributes|
      if attributes[:audio_track][:id]
        self.audio_refs.build(:audio_track => AudioTrack.find(attributes[:audio_track][:id]))
      elsif attributes[:audio_track][:file]
        self.audio_refs.build(:audio_track => AudioTrack.new(:user_id => attributes[:audio_track][:user_id], :file => attributes[:audio_track][:file]))
      end
    end

    if !binding
      self.save!
    end
  end

Модель AudioRef (которая является просто буфером между audio_tracks и feed_items):

class AudioRef
  include Mongoid::Document

  belongs_to :feed_item
  belongs_to :audio_track

end

И AudioTrack:

class AudioTrack
  include Mongoid::Document
  has_many :audio_refs
  mount_uploader :file, AudioUploader
end

Итак, вот спецификация для модели FeedItem, которая не работает:

  it "Should create audio_track and add audio_ref" do
      @audio_track = Fabricate(:audio_track, :user_id => @author.id, :file => File.open("#{Rails.root}/spec/stuff/test.mp3"))
      @feed_item= FeedItem.new(
        :user => @author,
        :message => {:body => Faker::Lorem.sentence(4)},
        :audio_refs => [
            {:audio_track => {:id => @audio_track.id}},
            {:audio_track => {:user_id => @author.id, :file => File.open("#{Rails.root}/spec/stuff/test.mp3")}}
        ]
      )
      @feed_item.save!          
      @feed_item.reload
      @feed_item.audio_refs.length.should be(2)
  end

Как видите, причина, по которой я переопределяю метод audio_refs =, заключается в том, что FeedItem может быть создан изсуществующие AudioTracks (когда есть params [: audio_track] [: id]) или из загруженного файла (params [: audio_track] [: file]).

Проблема в том, что @ feed_item.audio_refs.length ==0, когда я запускаю эту спецификацию, т.е. audio_refs не сохраняются.Не могли бы вы помочь мне с этим?

Некоторые исследования:

1) обязательный параметр по умолчанию "true" (это означает, что мы находимся в режиме построения)

Ответы [ 2 ]

1 голос
/ 16 июня 2011

Я нашел решение своей проблемы, но не понял, почему метод save не работает и не заставил мой код работать.Итак, прежде всего позвольте мне описать мои исследования по проблеме.После вызова audio_refs = создается массив audio_refs, НО в любом audio_ref отсутствует feed_item_id.Вероятно, это потому, что feed_item не сохраняется на данный момент.

Так что решение довольно простое - виртуальные атрибуты.Чтобы понять их, посмотрите соответствующие Railscasts

Так что мое решение - создать audio_refs с помощью обратного вызова "after_save"

Я немного изменил свои модели:

В FeedItem.rb я добавил

attr_writer :audio_tracks #feed_item operates with audio_tracks array
after_save :assign_audio #method to be called on callback

def assign_audio
    if @audio_tracks
      @audio_tracks.each do |attributes|
        if attributes[:id]
          self.audio_refs << AudioRef.new(:audio_track => AudioTrack.find(attributes[:id]))
        elsif attributes[:file]
          self.audio_refs << AudioRef.new(:audio_track => AudioTrack.new(:user_id => attributes[:user_id], :file => attributes[:file]))
        end
      end
    end
  end

И спецификация теперь:

it "Should create audio_track and add audio_ref" do
      @audio_track = Fabricate(:audio_track, :user_id => @author.id, :file => File.open("#{Rails.root}/spec/stuff/test.mp3"))
      @feed_item= FeedItem.new(
        :user => @author,
        :message => {:body => Faker::Lorem.sentence(4)},
        :audio_tracks => [
            {:id => @audio_track.id},
            {:user_id => @author.id, :file => File.open("#{Rails.root}/spec/stuff/test.mp3")}
        ]
      )
      @feed_item.save!          
      @feed_item.reload
      @feed_item.audio_refs.length.should be(2)
  end

И это прекрасно работает !!!Удачи в кодировании)

0 голосов
/ 15 июня 2011

Убедитесь, что audio_refs=() действительно вызывается, добавив отладочные данные какого-либо вида. Мне кажется, что ваш FeedItem.new() вызов не использует установщик audio_refs=().

Вот исходный код метода ActiveRecord::Base#initialize, взятый из APIdock :

* * 1010

В настоящее время у меня нет среды для проверки этого, но похоже, что он устанавливает хэш attributes напрямую, без прохождения установки каждого атрибута. Если это так, вам нужно вызвать вашего сеттера вручную.

На самом деле, я думаю, что тот факт, что вы не получаете исключение для количества аргументов (binding не установлено), доказывает, что ваш установщик не вызывается.

...