fishy
fishy

Reputation: 5

Creating nested models in rails, through an other model

I've a stock, and a calving model.
A stock (has an id, name, and a mother_id) can have carves through a calving, so I have this in my stock model.

    has_many :stocks, through: :calvings
    has_many :calvings

In Calving model i have:

    has_many :calves, class_name: "Stock", foreign_key: "mother_id", 
    accepts_nested_attributes_for :calves

I have a form for creating Calving, where the user can:

-choose the stock_id (it will be the mother)
-add how many carves was born
-give a name for every carf (depending on the nr of carves born)

I would like to save this data, but when it creates the Stock record, it puts the carving.id into the stock.mother_id field, not the carving.stock_id.

How can i fix this?

And if it is possible, what should I do, to fill the form with the right data when I want to edit the record?

Upvotes: 0

Views: 249

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

has_many :through

If you're creating records in a has_many :through association, you first need to create the records for the join model, then pass the records through the "child" model

Here's how we do it:


Models

#app/models/stock.rb
Class Stock < ActiveRecord::Base
    has_many :calvings, class_name: "Calving"
    has_many :calves, class_name: "Calf", through: :calvings

    accepts_nested_attributes_for :calving

    #build relevant objects (DRYes up controller)
    def self.build 
        stock = self.new
        stock.calvings.build.build_calf
        stock
    end
end

#app/models/calving.rb
Class Calving < ActiveRecord::Base
   belongs_to :stock
   belongs_to :calf 

   accepts_nested_attributes_for :calf
end

#app/models/calf.rb
Class Calf < ActiveRecord::Base
   has_many :calvings, class_name: "Calving"
   has_many :stocks, class_name: "Stock", through: :calvings
end

stocks #needs to identify mother only
id | name | created_at | updated_at

calvings
id | stock_id | calf_id | extra | info | created_at | updated_at

calfs
id | name | extra | information | created_at | updated_at

Controllers

These models give you a structure where you'll have a join model (which holds the relation between stocks and calves, allowing you to populate them as required:

#app/controllers/stocks_controller.rb
def new
    @stock = Stock.build
end

def create
    @stock = Stock.new(stock_params)
    @stock.save
end

private

def stock_params
    parmas.require(:stock).permit(:name, calvings_attributes: [calf_attributes:[:info]]
end

Forms

Finally, you'll be able create the form as follows:

#app/views/stocks/new.html.erb
<%= form_for @stock do |f| %> 
    <%= f.name %>
    <%= f.fields_for :calvings do |c| %>
        <%= c.fields_for :calf do |calf| %>
            <%= calf.text_field :info %>
        <% end %>
    <% end %>
<% end %>

Update

Rails, self-referential association on the User model to define friends/followers

Might be able to do it like this:

#app/models/stocks.rb
Class Stock < ActiveRecord::Base
   has_many :calvings
   has_many :calves, class_name: "Stock", through: :calvings
end

#app/models/calvings.rb
Class Calving < ActiveRecord::Base
   belongs_to :mother, :class_name => "Stock", foreign_key: "mother_id"
end

I'm not actually sure about this to be honest -- needs more thought. Typically, you'd use a standard has_many :through relationship for it. I'll email to get a call going - we need to fix this!!!

Upvotes: 1

Related Questions