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