I use Rails 3.0.6 with mongoID 2.0.2. Recently I encountered an issue with save! method when overriding setter (I am trying to create my own nested attributes).
So here is the model:
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 model (which is just buffer between audio_tracks and feed_items) is:
class AudioRef
include Mongoid::Document
belongs_to :feed_item
belongs_to :audio_track
end
And AudioTrack:
class AudioTrack
include Mongoid::Document
has_many :audio_refs
mount_uploader :file, AudioUploader
end
So here is the spec for the FeedItem model which doesn`t work:
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
As you can see, the reason I am overriding audio_refs= method is that FeedItem can be created from existing AudioTracks (when there is params[:audio_track][:id]) or from uploaded file (params[:audio_track][:file]).
The problem is that @feed_item.audio_refs.length == 0 when I run this spec, i.e. audio_refs are not saved. Could you please help me with that?
Some investigation:
1) binding param is “true” by default (this means we are in building mode)
I found a solution to my problem but I didnt understand why save method doesnt work and didn`t make my code work. So first of all let me describe my investigations about the problem. After audio_refs= is called an array of audio_refs is created BUT in any audio_ref is no feed_item_id. Probably it is because the feed_item is not saved by the moment.
So the solution is quite simple – Virtual Attributes. To understand them watch corresponding railscasts
So my solution is to create audio_refs by means of callback “after_save”
I slightly changed my models:
In FeedItem.rb I added
And the spec is now:
And it works fine!!! Good luck with your coding)