0

以下是模型关系:

class Tool < ActiveRecord::Base
  ...
  has_many :loss_ratios, :dependent => :destroy, :order => "loss_ratios.starts_at DESC"

  validates_associated :loss_ratios
  accepts_nested_attributes_for :loss_ratios, :allow_destroy => true

  attr_accessible :name, :text, :service_id, :supplier_id, :loss_ratios_attributes
end

class LossRatio < ActiveRecord::Base
  belongs_to :tool

  validates :rate, :starts_at, :tool, :presence => true
  validates_uniqueness_of :starts_at, :scope => :tool_id
  validates_numericality_of :rate
  validates_inclusion_of :rate, :in => (0..1)
  ...
end

我在创建/更新 ToolsController 操作中管理 LossRatio 关联。我想通过发布工具的属性集来测试它们(包括几个嵌套的 LossRatios,就好像它们是在表单中提交的一样)。我正在使用 FactoryGirl,但它似乎没有办法构建类似参数的属性哈希(attributes_for 忽略关联,并且看起来这种行为不会改变)。有没有办法做到这一点?

(我知道标题是一团糟,但我想不出更好更短的……)

4

1 回答 1

0

好的,这是我拉了半天头发后的想法:

def params_for(factory_name)
  exclude_params = [ "id", "created_at", "updated_at" ]
  f = FactoryGirl.build(factory_name)

  params = f.attributes.except(*exclude_params).dup

  f.reflections.select { |k,v|
    v.macro == :has_many && !v.instance_of?(ActiveRecord::Reflection::ThroughReflection)
  }.each_key do |k|
    assoc_collection = f.send(k)

    unless assoc_collection.empty?
      params["#{k.to_s}_attributes"] = {}

      assoc_collection.each_with_index do |assoc_obj,idx|
        params["#{k.to_s}_attributes"][idx.to_s] = assoc_obj.attributes.except(*exclude_params << "#{f.class.name.underscore}_id")
      end
    end
  end

  params
end

这是一个辅助方法,用于构建控制器的 CRUD 操作可消耗的参数哈希值。我在我的控制器规格中使用它,如下所示:

subject { post :create, :tool => params_for(:tool_with_lr_history) }

it "creates a new tool" do
  expect { subject }.to change(Tool, :count).by(1)
end

从片段中可以看出,该方法仅填充 has-many 关联的属性(并忽略 has-many-through 关联)。我想它可能会扩展到任何类型的关系,但到目前为止这对我有用(除非有更好的方法来做我想做的事)......

于 2012-05-04T07:28:14.980 回答