For example I have 2 players game, with future to have more than one game in the same time.
I need to create associations that will give me the opportunity to simply call user.games and it will return all games where that user is involved, as first_user_id or second_user_id.
table games
desk
first_user_id
second_user_id
table users
id
Model User
has_namy ??
What I think you are asking for:
class Game < ActiveRecord::Base
has_one :first_user, foreign_key: :first_user_id, class_name: 'User'
has_one :second_user, foreign_key: :second_user_id, class_name: 'User'
end
class User < ActiveRecord::Base
has_many :first_user_games, foreign_key: :first_user_id, class_name: 'Game'
has_many :second_user_games, foreign_key: :second_user_id, class_name: 'Game'
def games
first_user_games + second_user_games
end
end
I think it is probably a bad sign that you need this though, and it will be a pain. Instead you could just add a UserGames table and UserGame join model, put a column called "player_number" on UserGame, and do has_many :games, through: :user_games on User to get all games, regardless of player number, and then use queries, filtering, scoping, etc. as needed to find only the games where the player was a certain number. Here are a few questions related to scoping/conditions for has_many ..., through: ... on columns in the join model, in case you want to be able to access lists of games in User where the player is a specific player #:
Rails complex has_many and has_many through
Scope with join on :has_many :through association
Related
I have two tables, Teams and Games. I am trying to set up the associations for these tables but running into some issues. Here is my Game model with it's associations:
# Game Model
class Game < ActiveRecord::Base
belongs_to :home_team, class_name: "Team"
belongs_to :away_team, class_name: "Team"
belongs_to :winning_team, class_name: "Team"
end
I may be overthinking this but I'm not sure how to set up my Team model to have_many Games.
With a simple has_many :games in my Team model, my tests return the following error:
Team Associations should have many games
Failure/Error: it { should have_many(:games) }
Expected Team to have a has_many association called games (Game does not have a team_id foreign key.)
I see that it's looking for team_id for Game, and since there's no team_id it errors. But in my Game table I have three foreign keys referencing the same class. So would I need to create a has_many for each home_team, away_team and winning_team?
You'll need something like:
class Team < ActiveRecord::Base
has_many :home_games, class_name: 'Game', foreign_key: 'home_team_id'
has_many :away_games, class_name: 'Game', foreign_key: 'away_team_id'
# This seems like a separate thing to me...
has_many :winning_games, class_name: 'Game', foreign_key: 'winning_team_id'
# Do not include winning games, since it would already be included
def games
self.home_games.to_a + self.away_games.to_a
end
end
Rails documentation provides a nice explanation of how to handle a self join where only a has_many-belongs_to relationship is required. In the example, an employee (as a manager) can have many employees (each, as a subordinate).
However, how do you handle a has_many-has_many self join (which I've heard referred to as a bi-directional looped association)?
For example, how do you handle the situation in which an employee can have many subordinates, in its capacity as manager, and also have many managers, in its capacity as subordinate?
Or, in other words, where a user can follow many users and be followed by many users?
A User can have many:
followers in its capacity as followee
followees in its capacity as follower.
Here's how the code for user.rb might look:
class User < ActiveRecord::Base
# follower_follows "names" the Follow join table for accessing through the follower association
has_many :follower_follows, foreign_key: :followee_id, class_name: "Follow"
# source: :follower matches with the belong_to :follower identification in the Follow model
has_many :followers, through: :follower_follows, source: :follower
# followee_follows "names" the Follow join table for accessing through the followee association
has_many :followee_follows, foreign_key: :follower_id, class_name: "Follow"
# source: :followee matches with the belong_to :followee identification in the Follow model
has_many :followees, through: :followee_follows, source: :followee
end
Here's how the code for follow.rb:
class Follow < ActiveRecord::Base
belongs_to :follower, foreign_key: "follower_id", class_name: "User"
belongs_to :followee, foreign_key: "followee_id", class_name: "User"
end
The most important things to note are probably the terms :follower_follows and :followee_follows in user.rb. To use a run of the mill (non-looped) association as an example, a Team may have many :players through :contracts. This is no different for a Player, who may have many :teams through :contracts as well (over the course of such Player's career).
But in this case, where only one named model exists (i.e. a User), naming the through: relationship identically (e.g. through: :follow) would result in a naming collision for different use cases of (or access points into) the join table. :follower_follows and :followee_follows were created to avoid such a naming collision.
Now, a User can have many :followers through :follower_follows and many :followees through :followee_follows:
To determine a User’s :followees (upon an #user.followees call to the database), Rails may now look at each instance of class_name: “Follow” where such User is the the follower (i.e. foreign_key: :follower_id) through: such User’s :followee_follows.
To determine a User’s :followers (upon an #user.followers call to the database), Rails may now look at each instance of class_name: “Follow” where such User is the the followee (i.e. foreign_key: :followee_id) through: such User’s :follower_follows.
I'm creating a simple game site where users can create games and invite other users to join their games. A User can be both an owner of a Game and a player within that Game (the owner must also be a player) through the :game_players join table. I want the players to be known as :player and the owner of the game to be known as :user. I'm trying to figure out how to set up the associations. My questions are in the comments below:
class User
has_many :games # This is the owner association
has_many :games_playing, class_name: 'Game', through: :game_players # is this right?
end
class Game
belongs_to :user # this is the owner association
has_many :players, through: :game_players
end
class GamePlayer
belongs_to :game
belongs_to :player, class_name: 'User'
# is this right? is it necessary?
end
Am I on the right track here?
You're on the right track, but in your User class, you should also set up an association for :game_players, like so:
has_many :game_players
Anytime you have a has_many through, the through: should be the name of another association in that model.
And yes, you do need the associations on the join model. Rails needs them to be present in order to make the has_many through work.
FYI, the convention for join tables is to have the first plural, the second singular, so GamesPlayer (think possessive - it is a game's player) would be the conventional name for your join model.
I would like to create a double entry table form according two models.
For now I'm able to create a simple table with the members of a communities
on the columns, I must add the informations of an other model, like this :
My models :
Community
has_many :memberships
Membership
belongs_to :user
belongs_to :community
User
has_many ::memberships
has_many :skills
Skill
belongs_to :user
belongs_to :community
I there some gem existing to make a double entry table or is it easier to make it from scratch? if so, how can I begin ?
It seems like you would benefit from a through relationship here.
Instead of referencing community directly from the skill table, you could do:
Skill
belongs_to :user
has_many :communities, :through => :user
On user, add:
has_many :communities, :through => :memberships
Wouldn't this get the link between skill and community that you would like?
As Jay mentioned, you would benefit from a has_many :through relationship, or maybe a has_and_belongs_to_many relationship; whether it's the actual solution we'll have to see:
#app/models/user.rb
Class user < ActiveRecord::Base
has_many :memberships
has_many :skill_users
has_many :skills, through: :skill_users
end
#app/models/skill_user.rb
Class SkillUser < ActiveRecord::Base
belongs_to :skill
belongs_to :user
end
#app/models/skill.rb
Class Skill < ActiveRecord::Base
has_many :skill_users
has_many :users, through: :skill_users
end
This will allow you to associate each user (note that members are different than users) with specific skills without using double-entries in your tables
Relational
The basis of what you're seeking can be found in Relational Databases
These work by storing data in single instances, and linking to other data through foreign_keys. These foreign keys are things such as user_id etc:
(more information here)
This means instead of populating the same data twice, it is correct to reference that data from other models, as required. This is where join models come in
Join Model
Join models allow you to "link" two pieces of data through a join model:
For you, it means storing your skills in its own model, and linking users with skills on a join model (I've called skill_user.rb). This means that you'll be able to call your user's skills like this:
#user.skills #-> goes through the join model
I have two models, a User and a Event, and I would to set up two different associations between them.
I want:
- a user to have many hosted events
- a user to have many attended events
- an event to belong to one user (owner / creator)
- an event to belong to many users (attendees)
It's a has and belongs to many relationship for the attended event and just has many for the hosted events, I just don't know how to set it up properly / the rails way.
I know I'd need a users_attended_events table
I think that would be something like this on the User model
has_many :events, through: :hosted_events
has_many :events, through: :attended_events
But what would I do about the Event's model?
I have:
belongs_to: user
alias_attribute :owner, :user
alias_attribute :creator, :user
has_many :users, through:???
this should be the users_attended_events table, so.. what would I put here? How do I name this "Attendees"
It doesn't sound like you need a has_many through association for users hosting events. Something like this should work sufficiently for that (in user.rb) if you have a hosted_by_id column on your events table:
has_many :hosted_events, class_name: "Event", foreign_key: "hosted_by_id"
For attending events assuming a join class with columns attendee_id and event_id:
class AttendeeEvent < ActiveRecord::Base
belongs_to :attendee, class_name: "User"
belongs_to :event
end
You can add the following association to user.rb:
has_many :attendee_events, foreign_key: "attendee_id"
has_many :attended_events, through: :attendee_events, source: :event
The source: :event option indicates that the target objects for this association are found from the event association on the joining object.
The associations in event.rb are then:
belongs_to :hosted_by, class_name: "User"
has_many :attendee_events
has_many :attendees, through: :attendee_events