I am finding it hard to understand some of the association defined in the code base.
class Patient < ApplicationRecord
belongs_to :g_district, class_name: "District", primary_key: "id", foreign_key: 'district_id', optional: true
belongs_to :g_perm_district, class_name: "District", primary_key: "id", foreign_key: 'permanent_district_id', optional: true
belongs_to :g_workplc_district, class_name: "District", primary_key: "id", foreign_key: 'workplace_district_id', optional: true
end
class District
belongs_to :province #, optional: true
belongs_to :division, optional: true
has_many :hospitals
has_many :tehsils
has_many :ucs
has_many :mobile_users
has_many :labs
has_many :insecticides
end
I am not clearly getting these kind of associations defined her.(belongs_to :g_district, class_name: "District", primary_key: "id", foreign_key: 'district_id', optional: true).
In my code, there are no models like g_district, g_perm_district, g_workplc_district.
Sure.
belongs_to :lab, # instances will belong to one `lab`
class_name: "Hospital", # but the model is not called `Lab` but `Hospital`
primary_key: "id", # primary key is `hospitals.id` (actually not needed)
foreign_key: 'lab_id', # the foreign key is `lab_id` (again not needed)
optional: true # okay when there is no lab assign (default: required)
Related
In my Task model, I would like to create two has_one relation with the pricer model. To do that, I added the value :client_pricer_id and :presta_pricer_id to my Task table. And now, I want to create an has_one for each of them
My code :
Migration file :
class AddPricerToTasks < ActiveRecord::Migration[6.0]
def change
add_column :tasks, :client_pricer_id, :integer, foreign_key: true
add_column :tasks, :presta_pricer_id, :integer, foreign_key: true
end
end
Task model
has_one :client_pricer, :class_name => 'Pricer', :foreign_key => 'client_pricer_id'
has_one :presta_pricer, :class_name => 'Pricer', :foreign_key => 'presta_pricer_id'
View :
#task.client_pricer
Error :
SQLException: no such column: pricers.presta_pricer_id
I certainly forgot to specify a variable in my has_one line. But I don't know which one :)
You want to use belongs_to not has_one.
class Task < ApplicationRecord
belongs_to :client_pricer, class_name: 'Pricer', inverse_of: :client_pricer_tasks
belongs_to :presta_pricer, class_name: 'Pricer', inverse_of: :presta_pricer_tasks
end
class Pricer < ApplicationRecord
has_many :client_pricer_tasks, class_name: 'Task', foreign_key: :client_pricer_id
has_many :presta_pricer_tasks, class_name: 'Task', foreign_key: :presta_pricer_id
end
This is a really common mixup due to the confusing semantics.
belongs_to places the foreign key on this models table. has_one places it on the other end.
The inverse of has_one/has_many is always a belongs_to. Otherwise the relations just point at each other in a circle.
I finally found my error have to change the has_one to belongs_to (because the key is into my Task model )
My code :
Task model :
belongs_to :client_pricer, :class_name => 'Pricer', optional: true
belongs_to :presta_pricer, :class_name => 'Pricer', optional: true
I have a simple app and I have to describe the relationship student-parent as many-to-many where the following would work:
current_user.parents
current_user.children
Currently I have the following
class User < ApplicationRecord
has_many :parent_students
has_many :students, through: :parent_students, class_name: "User"
has_many :parents, through: :parent_students, class_name: "User"
end
class ParentStudent < ApplicationRecord
belongs_to :student, class_name: "User", foreign_key: "student_id"
belongs_to :parent, class_name: "User", foreign_key: "parent_id"
end
class CreateParentStudents < ActiveRecord::Migration[5.1]
def change
create_table :parent_students do |t|
t.references :student, index: true, references: :users
t.references :parent, index: true, references: :users
t.timestamps
end
end
end
Any idea how this would work? Thank you!
probably this can help, the declaration inside User
class User < ActiveRecord::Base
# as parent
has_many: student_relations, foreign_key: :parent_id, class_name: "ParentStudent"
has_many: students, through: :student_relations, source: :student
# as student
has_many: parent_relations, foreign_key: :student_id, class_name: "ParentStudent"
has_many: parents, through: :parent_relations, source: :parent
end
class ParentStudent < ActiveRecord::Base
belongs_to :student, foreign_key: "student_id", class_name: "User"
belongs_to :parent, foreign_key: "parent_id", class_name: "User"
end
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.
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" # ...
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'
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.
So I am doing a application where I have a "Game" Model that has 4 attributes from from 4 different users. One of those attributes is the player_id, and the other 3 are users uid (String id given by facebook).
Both models go like this:
class Game < ActiveRecord::Base
belongs_to :player, class_name: "User"
belongs_to :gamer_one, class_name: "User", primary_key: "gamer_one", foreign_key: "uid"
belongs_to :gamer_two, class_name: "User", primary_key: "gamer_one", foreign_key: "uid"
belongs_to :gamer_three, class_name: "User", primary_key: "gamer_one", foreign_key: "uid"
end
class User < ActiveRecord::Base
has_many :games, foreign_key: 'player_id'
has_many :game_ones, class_name: 'Game', foreign_key: 'gamer_one', primary_key: 'uid'
has_many :game_twos, class_name: 'Game', foreign_key: 'gamer_two', primary_key: 'uid'
has_many :game_threes, class_name: 'Game', foreign_key: 'gamer_three', primary_key: 'uid'
end
When I go to the console and check for User.game_ones, User.game_twos, or User.game.threes, I get the exact relation I want, but if I make it backwards (Game.gamer_one, Game.gamer_two, Game.gamer_three) I just get null, and the query is doing is wrong.
Any idea if the belongs_to relation I'm doing is wrong in some point?
when you have matching associations, the foreign_key and primary_key for those associations are the same. so just swap the foreign_key and primary_key in the belongs_to association.
My belong_to Item -> User relationship works; however, how do I setup the corresponding relationship in my User model (has many User -> Item)?
#item.rb
belongs_to :update_user, foreign_key: :item_updated_at_user_id, class_name: "User"
belongs_to :delete_user, foreign_key: :item_deleted_at_user_id, class_name: "User"
#user.rb
has_many :update_items, class_name: "Items", inverse_of: :update_user
has_many :delete_items, class_name: "Items", inverse_of: :delete_user
The associations should look as below:
class Item < ActiveRecord::Base
belongs_to :update_user, foreign_key: :item_updated_at_user_id, class_name: "User", inverse_of: :update_items
belongs_to :delete_user, foreign_key: :item_deleted_at_user_id, class_name: "User", inverse_of: :delete_items
end
class User < ActiveRecord::Base
has_many :update_items, foreign_key: :item_updated_at_user_id, class_name: "Item", inverse_of: :update_user
has_many :delete_items, foreign_key: :item_deleted_at_user_id, class_name: "Item", inverse_of: :delete_user
end
class_name: "Items" should be class_name: "Item"(Note: Model names are Singular)
Specify foreign key option on both side of association.
Also, Its best to specify inverse_of option on both sides of association.