保存! mongoid中引用属性的方法

时间:2011-06-15 11:28:55

标签: ruby-on-rails ruby-on-rails-3 override mongoid setter

我使用Rails 3.0.6和mongoID 2.0.2。最近我遇到了保存问题!重写setter时的方法(我正在尝试创建自己的嵌套属性)。

所以这是模型:

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)绑定参数默认为“true”(这意味着我们处于建筑模式)

2 个答案:

答案 0 :(得分: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

它工作正常!祝你的编码好运)

答案 1 :(得分:0)

通过添加某种调试输出来检查实际上是否正在调用audio_refs=()。我的感觉是您的FeedItem.new()来电不使用audio_refs=()制定者。

以下是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没有被调用。