2
votes

So, this is my first time using foreign keys, and though I think they are working properly, I don't understand the class_name portion in the syntax. Is that the class_name that the table being referred to is in?

My code:

Game Model:

belongs_to :user, foreign_key: 'white_player_id', class_name: 'User'
belongs_to :user, foreign_key: 'black_player_id', class_name: 'User'

User Model:

has_many :games, foreign_key: 'white_player_id', class_name: 'Game'
has_many :games, foreign_key: 'black_player_id', class_name: 'Game'

I was looking at: http://ricostacruz.com/cheatsheets/rails-models.html and noitced that in their example they have the class name of both belongs_to and has_many pointing to the Folder class..

belongs_to :parent, :foreign_key => 'parent_id' class_name: 'Folder'
has_many :folders, :foreign_key => 'parent_id', class_name: 'Folder'

So, that leads me to believe that the class name is supposed to point to the class that contains the foreign_key?? A little insight would be much appreciated.

3
The class_name refers to the Type that the relationship refers to. Or as you put it, the table being referred to. - Joe Essey

3 Answers

2
votes

class_name is for the class which is used in method you use, if ActiveRecord can not decide which class it is. In your example you dont need class_name because your method is user and class that will connect to is User, ActiveRecord can figure that out on its own.

You have another problem. You have two relations with same name user and user, that is not posible. You could made it like this though:

Game Model:

belongs_to :white_player, foreign_key: 'white_player_id', class_name: 'User'
belongs_to :black_player, foreign_key: 'black_player_id', class_name: 'User'

UserModel:

has_many :white_games, class_name: 'Game'
has_many :black_games, class_name: 'Game'
2
votes

If you define multiple assocations with the same name your just overwriting the same assocation.

belongs_to :white_player, foreign_key: 'white_player_id', class_name: 'User'
belongs_to :black_player, foreign_key: 'black_player_id', class_name: 'User'

class_name is the class of the related object.

foreign_key refers to the table of the model class where you are defining the relationship when defining a belongs_to relationsship.

class Game < ActiveRecord::Base
  belongs_to :white_player, foreign_key: 'white_player_id', class_name: 'User'
  # foreign_key is game.white_player_id
end

So when we do game.white_player Active Record looks for:

User.find(game.white_player_id)

added:

In your second example foreign_key in has_many refers to the related table.

belongs_to :parent, :foreign_key => 'parent_id' class_name: 'Folder'
has_many :folders, :foreign_key => 'parent_id', class_name: 'Folder'

And you would not need to specify the foreign key and class name explicitly:

class Folder < ActiveRecord::Base
  # ActiveRecord will infer that the class name is Folder
  has_many :folders, foreign_key: 'parent_id'
  # Rails will infer that the foreign_key is parent_id
  belongs_to :parent, class_name: 'Folder'
end

As you can see ActiveRecord is one smart cookie and can infer class names and foreign keys.

Here is an easier to explain example of has_many and foreign_keys:

class User < ActiveRecord::Base
  has_many :unread_messages, -> { where read: false }, 
           foreign_key: 'recipient_id', # refers to messages.recipient_id
           class_name: 'Message'
end 

user.unread_messages will query the table message:

SELECT "messages".* FROM "messages" WHERE "messages"."recipient_id" # ...
0
votes

You might want to create it with a new model, the simpliest way to do it :

Migration - 1/2 : console

rails g model Game white_player:references black_player:references

Migration - 2/2 : db/migrate/create_games.rb

In the migration file, delete the "foreign_key: true" entry, that would look like :

t.references :white_player, foreign_key: true
t.references :black_player, foreign_key: true

Run : rails db:migrate

Model files :

Game Model :

belongs_to :white_player, class_name: 'User'
belongs_to :black_player, class_name: 'User'

User Model :

has_many :white_player_games, class_name: 'Game', foreign_key: 'white_player_id'
has_many :black_player_games, class_name: 'Game', foreign_key: 'white_player_id'

Hope that helps.