Forum: Ruby on Rails how to use activemodel collection.build for a has_many :through association

45098d22acb280baa0836cc1162226c2?d=identicon&s=25 James Gray (Guest)
on 2013-07-22 23:23
(Received via mailing list)
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
5f94b9b346c2aa648a80bc259978e5bc?d=identicon&s=25 Colin Law (Guest)
on 2013-07-23 09:26
(Received via mailing list)
On 21 July 2013 18:28, James Gray <zaargy@gmail.com> wrote:
> 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
5f94b9b346c2aa648a80bc259978e5bc?d=identicon&s=25 Colin Law (Guest)
on 2013-07-23 11:25
(Received via mailing list)
On 23 July 2013 08:23, Colin Law <clanlaw@googlemail.com> wrote:
>>       @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.

>
> 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
5f94b9b346c2aa648a80bc259978e5bc?d=identicon&s=25 Colin Law (Guest)
on 2013-07-23 11:38
(Received via mailing list)
On 21 July 2013 18:28, James Gray <zaargy@gmail.com> wrote:
> component.id)
> My models:
> 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
6883e5ef03484d4fcef507d7b4f1d243?d=identicon&s=25 Matt Jones (Guest)
on 2013-07-23 19:25
(Received via mailing list)
On Sunday, 21 July 2013 13:28:38 UTC-4, James Gray wrote:
>       @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
>   attr_accessible :description, :name, :component_specifications_attributes
>
> 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
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.