accessing from both ends of has many through relationship

I have a 'has many through' relationship in my models. I am trying to access objects from either side of this relationship, with mixed results.Here are my models:

    class Material < ActiveRecord::Base       attr_accessible :description, :number       has_many :parts       has_many :work_tickets, :through => :parts     end

    class Part < ActiveRecord::Base       belongs_to :material       attr_accessible :description, :number, :yield, :material_id       has_many :work_tickets       has_many :operations, :dependent => :destroy     end

    class WorkTicket < ActiveRecord::Base       belongs_to :part       belongs_to :material       attr_accessible :number, :yield, :opened, :closed, :part_id       has_many :works, :dependent => :destroy     end

I can access the work_tickets from the material with:

    @work_tickets = @material.work_tickets

But, cannot access material from work_ticket:

    <%= work_ticket.material.number %>

Forcing me to use:

    <%= work_ticket.part.material.number %>

Am I expecting the wrong behaviour, or am I using the wrong relationship pattern?

I have a 'has many through' relationship in my models. I am trying to access objects from either side of this relationship, with mixed results.Here are my models:

    class Material < ActiveRecord::Base       attr_accessible :description, :number       has_many :parts       has_many :work_tickets, :through => :parts     end

    class Part < ActiveRecord::Base       belongs_to :material       attr_accessible :description, :number, :yield, :material_id       has_many :work_tickets       has_many :operations, :dependent => :destroy     end

    class WorkTicket < ActiveRecord::Base       belongs_to :part       belongs_to :material       attr_accessible :number, :yield, :opened, :closed, :part_id       has_many :works, :dependent => :destroy     end

I can access the work_tickets from the material with:

    @work_tickets = @material.work_tickets

But, cannot access material from work_ticket:

    <%= work_ticket.material.number %>

What happens when you do this? You have specified a simple WorkTicket belongs_to :material so there is nothing complex about this.

Forcing me to use:

    <%= work_ticket.part.material.number %>

Am I expecting the wrong behaviour, or am I using the wrong relationship pattern?

It appears you have two routes for getting to material, that is bad as there is redundant information somewhere and there is a danger of the two routes getting mismatched.

Colin

For <%= work_ticket.material.number %>

I get undefined method `number' for nil:NilClass

Please remember to quote the previous message so that it is easier to follow the thread, remember this is a mailing list not a forum (though you may be accessing it through a forum like interface).

Martyn W. wrote in post #1071177:

I have a 'has many through' relationship in my models. I am trying to access objects from either side of this relationship, with mixed results.Here are my models:

    class Material < ActiveRecord::Base       attr_accessible :description, :number       has_many :parts       has_many :work_tickets, :through => :parts     end

    class Part < ActiveRecord::Base       belongs_to :material       attr_accessible :description, :number, :yield, :material_id       has_many :work_tickets       has_many :operations, :dependent => :destroy     end

    class WorkTicket < ActiveRecord::Base       belongs_to :part       belongs_to :material       attr_accessible :number, :yield, :opened, :closed, :part_id       has_many :works, :dependent => :destroy     end

I can access the work_tickets from the material with:

    @work_tickets = @material.work_tickets

But, cannot access material from work_ticket:

    <%= work_ticket.material.number %>

Forcing me to use:

    <%= work_ticket.part.material.number %>

Am I expecting the wrong behaviour, or am I using the wrong relationship pattern?

The error you get is correct as your relationships are mismatched. Let's try to analyze:

    class Material < ActiveRecord::Base       attr_accessible :description, :number       has_many :parts       has_many :work_tickets, :through => :parts     end

that means when you do material.work_tickets, it will go to the parts table and look for field matierial_id = self.id, then from those results get the work_tickets_id and get the WorkTicket objects that match. Sounds ok, but might not neccessarily return you the results you want. The mySQL query will probably be something like select work_tickets.* from work_tickets inner join parts on parts.work_tickets_id = work_tickets.id inner join materials on parts.material_id = [#id]

anyway, now for the other side:

    class WorkTicket < ActiveRecord::Base       belongs_to :part       belongs_to :material       attr_accessible :number, :yield, :opened, :closed, :part_id       has_many :works, :dependent => :destroy     end

when you do work_ticket.material, rails will go to the Material model and look for the other side of the relationship. Here it will fail, because though you have has_many :work_tickets, this relationship goes through the :parts table, and NOT directly to the WorkTicket model. There can be no match.

There are a number of ways to fix this. Let's make sure we got the relationships right.

There's a one-many from materials to tickets. There's a one-many from materials to parts. There's a one-many from parts to tickets.

No need for :through table

     class Material < ActiveRecord::Base        attr_accessible :description, :number        has_many :parts        has_many :work_tickets      end

     class Part < ActiveRecord::Base        belongs_to :material        attr_accessible :description, :number, :yield        has_many :work_tickets        has_many :operations, :dependent => :destroy      end

     class WorkTicket < ActiveRecord::Base        belongs_to :part        belongs_to :material        attr_accessible :number, :yield, :opened, :closed        has_many :works, :dependent => :destroy      end

of course changing your models means your table columns will have to match.