Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails belong_to has_many with a custom foreign key

I have a relationship between 2 models in my rails application. I have veered away from the standard of how to implement the relationship as I used another field as a primary key and the naming convention is different. Doing so resulted in the relationship seemingly not being established. I want to understand as to why.

This is a trimmed down version of my models:

class Player < ActiveRecord::Base   set_primary_key "alias"   attr_accessible :alias, :avatar   has_many :player_sessions, :foreign_key => "player_alias", :class_name => "PlayerSession"  end  class PlayerSession < ActiveRecord::Base   attr_accessible :player_alias, :total_score   belongs_to :player, :foreign_key  => "player_alias", :class_name => "Player"  end 

The Player model has the field alias which is the username in my application. I wanted the username to act as the primary key since it is unique and it would be easier to migrate the data and maintain relationships.

Originally I only had PlayerSession model with data already filled in, but as my application grew I added the Player model and simply inserted a row with the same alias.

In the Player's show view I have the following code:

Player Sessions: <% @player.player_sessions do |player_session| %> <ul>     <li><h4>Highest Score:</h4> <%= player_session.total_score %> </li> </ul> 

When I try to access the page it simple doesn't show the information.

Other information I can add is that I haven't added any relationships in the database itself.

I am still new to rails and still playing around with it. Any opinions that concern coding standards(outside from answering the question) are welcome.


Update I have implemented Babur Usenakunov's suggestion by adding the primary_key option in the models:

class Player < ActiveRecord::Base   set_primary_key "alias"   attr_accessible :alias, :avatar   has_many :player_sessions, :primary_key => "alias", :foreign_key => "player_alias", :class_name => "PlayerSession"  end  class PlayerSession < ActiveRecord::Base   attr_accessible :player_alias, :total_score   belongs_to :player, :primary_key => "alias", :foreign_key  => "player_alias", :class_name => "Player"  end 

Also to test out the the data is valid I acquired the PlayerSession list manually:

Code implemented in controller:

@player_sessions =  PlayerSession.where("player_alias = ?", params[:id]) 

Code implemented in view(which outputs the data):

<% @player_sessions.each do |player_session| %> <ul>     <li><h4>Highest Score:</h4> <%= player_session.total_score %> </li> </ul> <% end %> 
like image 537
Drahcir Avatar asked Jun 01 '13 19:06

Drahcir


People also ask

What is the difference between Has_one and Belongs_to?

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.

What is polymorphic association in Rails?

In Ruby on Rails, a polymorphic association is an Active Record association that can connect a model to multiple other models. For example, we can use a single association to connect the Review model with the Event and Restaurant models, allowing us to connect a review with either an event or a restaurant.

Does rails have one relationship?

Ruby on Rails ActiveRecord Associations has_oneA has_one association sets up a one-to-one connection with another model, but with different semantics. This association indicates that each instance of a model contains or possesses one instance of another model.


2 Answers

I have solved the issue, it was a matter of adding each in the loop I implemented in the view:

<% @player.player_sessions.each do |player_session| %> <ul>     <li><h4>Highest Score:</h4> <%= player_session.total_score %> </li> </ul>     <% end %> 

After playing around a bit, I realised i didn't need to add the primary_key option in either of the views, and left the foreign key option only in the Player model.

class Player < ActiveRecord::Base   set_primary_key "alias"   attr_accessible :alias, :avatar   has_many :player_sessions, :foreign_key => "player_alias", :class_name => "PlayerSession"  end  class PlayerSession < ActiveRecord::Base   attr_accessible :player_alias, :total_score   belongs_to :player, :class_name => "Player"  end 
like image 166
Drahcir Avatar answered Sep 24 '22 03:09

Drahcir


If your PlayerSession table has a column named alias then your foreign key should also be alias, not player_alias. As a token of advice I'd be wary of using an alias as a foreign_key: if your player can/decide to change his alias then all PlayerSession records within your database will become invalid and require an update. Using an immutable parameter such as player_id would be preferable to using the existing alias column IMHO.

like image 22
marcelowiermann Avatar answered Sep 22 '22 03:09

marcelowiermann