2011-06-15 47 views
2

我使用mongoID 2.0.2的Rails 3.0.6。最近我遇到了保存問題!方法時重寫setter(我想創建自己的嵌套屬性)。保存!在mongoid中引用屬性的方法

因此,這裏的模型:

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] [:文件])。

問題是,當我運行此規範時,@ feed_item.audio_refs.length == 0,即audio_refs沒有保存。你能幫我解決嗎?

一番調查:

1)結合參數是由默認的「真」(這意味着我們在建設模式)

+1

我建議你接受你以前的6個問題的答案 – 2011-06-15 13:16:02

回答

1

我找到了解決我的問題,但我不明白爲什麼保存方法不工作,並沒有讓我的代碼工作。首先讓我描述一下我對這個問題的調查。在調用audio_refs =之後,會創建一個audio_refs數組,但在任何audio_ref中都不是feed_item_id。可能是因爲feed_item暫時未保存。

所以解決方案很簡單 - 虛擬屬性。要了解他們觀看corresponding railscasts

所以我的解決辦法是「after_save的」

我稍微改變了我的模型創建通過回調來audio_refs:

在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

檢查audio_refs=()實際上被調用,通過添加某種調試輸出。我的感覺是你的FeedItem.new()調用不使用audio_refs=() setter。

這裏的ActiveRecord::Base#initialize方法的源代碼,從APIdock採取:

# File activerecord/lib/active_record/base.rb, line 1396 
def initialize(attributes = nil) 
    @attributes = attributes_from_column_definition 
    @attributes_cache = {} 
    @new_record = true 
    @readonly = false 
    @destroyed = false 
    @marked_for_destruction = false 
    @previously_changed = {} 
    @changed_attributes = {} 

    ensure_proper_type 

    populate_with_current_scope_attributes 
    self.attributes = attributes unless attributes.nil? 

    result = yield self if block_given? 
    _run_initialize_callbacks 
    result 
end 

我目前沒有一個環境來測試這一點,但它看起來像它的直接設置attributes哈希不通過每個去屬性的setter。如果是這樣的話,你需要手動調用你的setter。

其實,我認爲你沒有得到一個例外的參數(binding沒有設置)的例外證明你的setter沒有被調用。

+0

感謝你的回答,奧利弗!我檢查你說的是什麼,這個setter方法被調用,綁定默認是true。我提出self.audio_refs並獲得一個合適的數組,這意味着audio_refs()實際上被調用。但問題是它不保存audio_refs。 – makaroni4 2011-06-16 07:31:15