how to use activemodel collection.build for a has_many :through association

Hi all,

In my controller I am doing the following to populate a nested form for a has_many through association:

def new

@specification = Specification.new

Component.find_each.each do |component|

@specification.component_specifications.build(:component_id => component.id)

end

The idea being whenever someone creates or edits a form, it will be populated with all components at that time so that when they save those components that specification will be associated with the newly created specification. The problem I am having is I can’t work out how to pass component name to display in my form for the as yet nonexistent component_specification as it is not accessible through the ComponentSpecification model.

My models:

class Specification < ActiveRecord::Base

attr_accessible :description, :name, :component_specifications_attributes

validates :name, :presence => true, :uniqueness => true

has_many :component_specifications

has_many :components, :through => :component_specifications

accepts_nested_attributes_for :component_specifications, :allow_destroy => true

end

class ComponentSpecification < ActiveRecord::Base

attr_accessible :note, :colour, :brand, :components

has_many :components

belongs_to :specification

end

class Component < ActiveRecord::Base

attr_accessible :description, :name

belongs_to :component_specifications

validates :name, :presence => true, :uniqueness => true

end

Thanks in advance,

James

Hi all,

In my controller I am doing the following to populate a nested form for a has_many through association:

    def new        @specification = Specification.new

    Component.find_each.each do |component|       @specification.component_specifications.build(:component_id => component.id)

Don't use .new or .build in the view, do it in the controller so that everything is prepared before rendering the view. The view code should only be concerned with displaying the data.

    end

The idea being whenever someone creates or edits a form, it will be populated with all components at that time so that when they save those components that specification will be associated with the newly created specification. The problem I am having is I can't work out how to pass component name to display in my form for the as yet nonexistent component_specification as it is not accessible through the ComponentSpecification model.

I have no idea what you mean by the last sentence. But as I said above you should be doing this in the controller anyway.

My models:

class Specification < ActiveRecord::Base

You said in the title ActiveModel, (well actually you said activemodel wihch would be something different again) but I see you meant ActiveRecord. When asking questions it is important to get the details right.

Colin

Hi all,

In my controller I am doing the following to populate a nested form for a has_many through association:

    def new        @specification = Specification.new

    Component.find_each.each do |component|       @specification.component_specifications.build(:component_id => component.id)

Don't use .new or .build in the view, do it in the controller so that everything is prepared before rendering the view. The view code should only be concerned with displaying the data.

Sorry, I seem to have suffered from brain fade when I wrote the above code, it is in the controller. You might want to put the second part in a method of the Specification model however. I am not sure why you are using find_each but that is a different issue.

    end

The idea being whenever someone creates or edits a form, it will be populated with all components at that time so that when they save those components that specification will be associated with the newly created specification. The problem I am having is I can't work out how to pass component name to display in my form for the as yet nonexistent component_specification as it is not accessible through the ComponentSpecification model.

I have no idea what you mean by the last sentence. But as I said above you should be doing this in the controller anyway.

I still don't understand what the problem you are describing is here though. Why can't you just say @specification.component_specifications?

Colin

Hi all,

In my controller I am doing the following to populate a nested form for a has_many through association:

    def new        @specification = Specification.new

    Component.find_each.each do |component|       @specification.component_specifications.build(:component_id => component.id)     end

The idea being whenever someone creates or edits a form, it will be populated with all components at that time so that when they save those components that specification will be associated with the newly created specification. The problem I am having is I can't work out how to pass component name to display in my form for the as yet nonexistent component_specification as it is not accessible through the ComponentSpecification model.

My models:

class Specification < ActiveRecord::Base   attr_accessible :description, :name, :component_specifications_attributes

  validates :name, :presence => true, :uniqueness => true

  has_many :component_specifications   has_many :components, :through => :component_specifications

  accepts_nested_attributes_for :component_specifications, :allow_destroy => true end

class ComponentSpecification < ActiveRecord::Base   attr_accessible :note, :colour, :brand, :components

  has_many :components

I think that should be belongs_to :component, unless my brain is fading again.

  belongs_to :specification end

class Component < ActiveRecord::Base   attr_accessible :description, :name

  belongs_to :component_specifications

and that should be has_many

Colin

Hi all,

In my controller I am doing the following to populate a nested form for a has_many through association:

def new

@specification = Specification.new

Component.find_each.each do |component|

@specification.component_specifications.build(:component_id => component.id)

end

One note on this: I’m not sure what the find_each is getting you here. If there are enough records to make it important to find them in batches, building a new ComponentSpecification for each is going to be a bad idea.

The idea being whenever someone creates or edits a form, it will be populated with all components at that time so that when they save those components that specification will be associated with the newly created specification. The problem I am having is I can’t work out how to pass component name to display in my form for the as yet nonexistent component_specification as it is not accessible through the ComponentSpecification model.

My models:

class Specification < ActiveRecord::Base

attr_accessible :description, :name, :component_specifications_attributes

validates :name, :presence => true, :uniqueness => true

has_many :component_specifications

has_many :components, :through => :component_specifications

accepts_nested_attributes_for :component_specifications, :allow_destroy => true

end

class ComponentSpecification < ActiveRecord::Base

attr_accessible :note, :colour, :brand, :components

has_many :components

This doesn’t match the code you’re using above - setting component_id isn’t going to load this association. Is it possible this should be a belongs_to :component instead?

class Component < ActiveRecord::Base

attr_accessible :description, :name

belongs_to :component_specifications

Again, I think this is the wrong way round - I’m guessing your intended data model is that one Specification can have many Components, with ComponentSpecifications acting as a join table…

–Matt Jones