Using :through

Sorry, cause this is the second post in trying to solve the same problem. Since that other post hasn't received any replies and I have a slightly better understanding I'm trying it again.

In my Position model I have the method company_id In my Cdetail model I have a method company_id and another company_name.

When I'm pulling up queries on the Position table I want to translate the company_id in Position to the company_name in Cdetail.

Is this something to use the :through option with or is there another way ?

Stuart

I assume that Cdetail belongs_to Position?

If so, you could redefine the company_id method

def company_id     self.Cdetail.company_name end

Would this work?

Also, if you wanted to use :select in your Find call, you could do

    Position.find(:all, :select =>'[other fields..], cdetails.company_name as company_id', :include => 'cdetails')

But now that I'm thinking about it, do you really want to use the field used for the foreign key to do this? That could cause problems.

Jason

Dark Ambient wrote:

I can't quite say I followed all of that. I'd recommend posting a copy of the fixture data for both models or a class definition of each model listing the attributes.

Dark Ambient wrote:

Model: (showing only relevant lines)

class Position < ActiveRecord::Base belongs_to :cdetail

attribute: company_id

class Cdetail < ActiveRecord::Base

has_many :positions

attributes: company_id, company_name

Stuart

I assume that Cdetail belongs_to Position?

The other way around , Position belong_to Cdetail

If so, you could redefine the company_id method

def company_id     self.Cdetail.company_name end

Would this work?

Also, if you wanted to use :select in your Find call, you could do

    Position.find(:all, :select =>'[other fields..], cdetails.company_name as company_id', :include => 'cdetails')

It might work, what is the [other fields] mean ? or can i just exclude that option ?

But now that I'm thinking about it, do you really want to use the field used for the foreign key to do this? That could cause problems.

Jason

I'm not sure , but in looking through my options I thought perhaps I could use it to define the correct association.

Stuart

Maybe this will help, because it seems I like my explanations are not conveying my issue . I created a sql query in mysql to extract the correct information - this query works , so now I need to figure out a way for Rails to perform it.

SELECT cdetails.company_name FROM positions Inner Join cdetails ON positions.company_id = cdetails.company_id

Hope this helps

Stuart

Like 5MileRadius said, posting your models and possible some controller code would help. But. To get rails to do that query, you could do

Position.find(:all, :select => 'cdetails.company_name as whatever', :include => 'cdetails') that will return an array of Position objects.

When you use :select, the string you pass is what is used in Rails' "SELECT" statement, so only those fields will be queried. If you want other things to be retrieved, you must include them in your :select

Jason

Dark Ambient wrote:

Could someone explain what posting the models means ? I'm not trying to be funny, but what I posted was pretty much them. Anyway I'll post them here again.

class Position < ActiveRecord::Base     belongs_to :state     belongs_to :category     belongs_to :edureq     belongs_to :expreq     belongs_to :pay     belongs_to :postlength     belongs_to :securityclear     belongs_to :term     belongs_to :travreq     belongs_to :wage     belongs_to :user     belongs_to :cdetail

  def self.current_openings   find(:all)   end end

class Cdetail < ActiveRecord::Base   belongs_to :user   has_many :positions

end

I thought I could put something into the Position associations like this:

belongs_to:comp_name, :class_name=> "Cdetail", :foreign_key => "company_name and although it wasn't returning an error it wasn't giving me the name.

Stuart

This is one messy thread. Anyway , I worked out this problem using find_by_sql. Why I can't do it through the AR associations is beyond me. I don't know if I feel right using find_by_sql, as it doesn't really take advantage of the associations that are in place. Does it have a downside ? I've posted my models as requested below anyway.

Stuart

I think your original question was, how do I get the the cdetails's company_name, given a position. Why can't you just do:

position.cdetail.company_name

?

No, that is just giving me "undefined method `cdetail' for #<Position:0x4c56748>"

"belongs_to :cdetail" adds an accessor method to Position which results in the Cdetail referenced by the cdetail_id field in Position (you can change the name of the field with :foreign_key, if your field is named something other than cdetail_id).

Well , I've been trying this and it seems to have no effect - continuing to get undefined method - "cdetail"

Here is the relationship defined in Position model belongs_to :cdetail, :foreign_key => :company_id

So, in the Position model , the attribute is company_id and in the Cdetail model, the attribute is company_id , perhaps having both columns with the same name is confusing the issue.

if you wanted to access users directly from cdetail (use :foreign_key and :source if the field names are weird).

I haven't gotten a good feel for the :source option. Reading through the doc it seems to reference another model ?

Tangent: Is there a reason you're using an unintuitive reference like "cdetail"? Why not just call it a "company", with fields "id" and "name"? Or even "company_detail"?

Because I didn't think it through and I'm being hard headed :slight_smile: Actually company_detail maybe a better idea, if that would truly help the association problem. The c in cdetail obviously stands for company. Just in case it seemed my model naming is totally irrelevant.

For the time being I solved the issue by adding the :join option to the find. It's not totally ugly and seems to give me the results. However I'd like to do it, as said above position.cdetail.company_name.

Stuart

Hi --

David wrote: > It seems a little over-engineered, perhaps. Since you have a > companies table, why not just put the details of the companies in that > table? Then each position could have a company, which in turn would > have a name:

Stuart, just to clarify: Do you have a companies table, which Position and Cdetail reference with their company_id field? Or is Position.company_id referencing a Cdetail record identified by it's company_id field? Or is company_id not a record id at all, and some other id (like, from another database)?

--

So many choices :slight_smile: .. It is Position.company_id is referencing a Cdetail record with a company_id field. For sanity sake here are the tables:

cdetails

If company_id holds a value you're getting from somewhere else, then don't make it your primary key.

The problem is that you have two "unique" ids for a cdetail, a record id and a company id. Rails uses record ids to build relationship accessor methods, but you have a valid reason to want to use the company id in creating positions, I'm guessing, that the user who creates new positions knows and can input the company id to which the position should belong, but not its record id in the database (and why should they?)

Actually without sounding too screwey, I'm grabbing it out of the session information.

To keep your database normalized, I would remove the company_id field from Position and replace it with a cdetail_id, so you can use all of Rails' relationship goodness. Then override Position's initialize method to get the correct cdetail_id from a company_id:

if cdetail_id.nil? and company_id   cdetail = Cdetail.find_by_company_id company_id   cdetail_id = cdetail.id unless cdetail.nil? end

I'm thinking all this wouldn't be necessary. All I'm really doing is taking the user_id out of the session information and calling that the company_id. Renaming the position.company_id to cdetail_id shouldn't effect the creation of the position. btw, if it means anything, I'm using a hidden field to input this id. You did say the magic words though "normalize the database". Yes that is important.

Then when you save, the position will refer to the correct Cdetail record (the save will ignore the company_id property in the Position if there's no corresponding field in the table). Maybe add a validation for cdetail_id which complains about company_id?

Then when you need the company_id (or, silimlarly, company_name) for a position, you do:

position.cdetail.company_id

K. that makes sense. I'll be trying it shortly and let you know how it works out.

Again, for clarity, where does the content for the company_id field come from? If it's entirely internal, I would get rid of it and just use the cdetails' id field as the unique identifier and present the user with a menu of company names (or something).

Again, company_id in both the positions table and the cdetails table comes from the user id in the session information.

Stuart

Got to run out , but will work on this in a few hours.   Let you know how things work out a little later.

Stuart

Followed through a was returned You have a nil object when you didn't expect it! The error occurred while evaluating nil.cdetail

Forget what I said before. I would set up a has_one/belongs_to relationship between User and Cdetail, and a has_many/belongs_to relationship between User and Position. That's it. Then to get the Cdetail from a Position, I would do this:

position.user.cdetail

So here is the models just to show that i followed above correctly: Actually all these relationships existed already.

class User < ActiveRecord::Base   has_one :cdetail   has_many :positions   before_create :make_activation_code

class Position < ActiveRecord::Base

    belongs_to :user     belongs_to :cdetail

class Cdetail < ActiveRecord::Base   belongs_to :user   has_many :positions

Maybe I'm doing something wrong here .

stuart

I'm not sure I understand why I need to go through User to get what I need out of Cdetail. Anyway, before explaining , let me try and understand it first on my own. However, as suggested I've made some changes, renaming Cdetail to Company

Company has these relevant attributes: id : auto_incrementing company_id name

Position has this relevant attribute: company_id

So what I thought made sense here was to add association like this to Position belongs_to: company, :foreign_key => company_id

Then in show, list position.company.name

Maybe it makes sense to go through User but truthfully it's not giving me any better results.

Stuart

bump :slight_smile:

Stuart

Stuart Fellowes wrote: > Again, company_id in both the positions table and the cdetails table > comes from the user id in the session information.

Stuart Fellowes wrote: > Company > company_id > > Position > company_id > > So what I thought made sense here was to add association like this to > Position > belongs_to: company, :foreign_key => company_id

I think your own naming conventions are confusing you (they're confusing me). As you said before, company_id holds the id of a record in the users table (so please, please rename it user_id -- you'll be thankful you did in three months). When you say "Position belongs_to :company, : foreign_key => :company_id", you're telling Rails that company_id holds an id of a record in the companies table, which is not the case.

company_id DOES hold a record in the companies table. companies:

id | company_id | company_name | address | city | so on ............

So why can I just connect these two tables , even though I realize the id in the companies table is not the standard id as far as AR goes ? Am I crazy and beating a dead horse or can this not be done. I am under the impression there are ways to let AR know of these unusual attribute names ?

Stuart

I know by now ya think I'm crazy but I put it together exactly how recommended. I'm still getting an undefined method for company.

class Company < ActiveRecord::Base   belongs_to :user end

class User < ActiveRecord::Base   has_one :company end

class Position < ActiveRecord::Base ...........    belongs_to :user end

companies table:

id | user_id | name |

users table:

id | company_id | # I also tried changing this to user_id

(rebooted server) no dice

I added this to the position.rb controller: def company user.company end

Calling it through: position.company.name %>

Stuart

Since I tried everything suggested, read and googled with no end in site - I came up with what I think is a viable solution, I made the company id attribute not to auto increment but to use the company id in that column. Seems to work , any possible problems ?

Stuart