Rails active record query basics - sql

I'm very new, and in the process of learning database stuff as well as Rails. Right now I have the following statement:
def tournaments_played
#tournaments_played = Tournament.count
end
With these models:
class User < ActiveRecord::Base
has_one :profile, dependent: :destroy
has_many :tournaments, through: :profile
class Profile < ActiveRecord::Base
belongs_to :user, class_name: "User"
has_many :tournaments
class Tournament < ActiveRecord::Base
belongs_to :profile
belongs_to :user
Obviously tournaments_played is returning a count of every record. I only want the tournaments for that user. I can paste in the scheme if needed!

I was going to give you a more specific answer, but you haven't indicated how you set up your Tournament model, so I can't give you actual code.
Take a look at this tutorial. You will find the answer to your question there.

Related

Modelling a team manager through a membership table

I have the following Rails models connecting teams and users:
class User < ActiveRecord::Base
has_many :memberships
has_many :teams, through: :memberships
end
class Team < ActiveRecord::Base
has_many :memberships
has_many :users
end
class Membership < ActiveRecord::Base
belongs_to :team
belongs_to :user
end
I want to implement a team manager via the existing memberships table.
Would it be a better idea to have a foreign key in the teams table like this:
class Team < ActiveRecord::Base
belongs_to :manager_membership, class_name: 'Membership'
has_one :manager, through: :manager_membership, source: :user
# ...
end
Or would it be better to have an extra column (with unique index) on memberships like this:
class Team < ActiveRecord::Base
has_one :manager_membership, -> where { manager: true }, class_name: 'Membership'
has_one :manager, through: :manager_membership, source: :user
# ...
end
I wonder if having foreign keys going both ways from team to a membership and back is weird? Or maybe it doesn't make much difference either way?
Based on the comments, you should be able to use a single table inheritance for both your users and managers. That would mean you get to use the same membership relationship on both models.
class User < ActiveRecord::Base
has_many :memberships
has_many :teams, through: :memberships
end
class Manager < User
# your code
end
You can now use Manager wherever needed, and add any validations directly on that model. Remember to add a type column to your User table if you decide to go this route.
EDIT
Looking at this again, you will need to have a separate table to keep the relationship between your Manager's team and the actual team they manage clear. Yourteam` should be something like:
class Team < ActiveRecord::Base
has_many :memberships
has_many :users, through: :memberships
has_many :teams_managers
has_many :managers, through: :teams_managers
end
class Manager < User
has_many :teams_managers
# note here we're aliasing for clarity and specifying a source
has_many :managed_teams, through: :teams_managers, source: :team
end
# this is your association model for managers <-> teams
class TeamsManager < ActiveRecord::Base
belongs_to :manager
belongs_to :team
end
# so now you could call something like this
manager = Manager.find 1
manager.managed_teams =>[...]
manager.teams =>[...]
You'd have to make the corresponding migrations to instantiate your TeamsManagers table as well.

Rails - Using multple has_many through: associations joining same two models. Redundant has_many through:

Would association person and company through employment AND through interviewing be bad practice?
Why, specifically?
And does that answer apply to databases in general, not just rails?
Example:
employment.rb
class Employment < ActiveRecord::Base
belongs_to :people
belongs_to :companies
end
interview.rb
class Interview < ActiveRecord::Base
belongs_to :people
belongs_to :companies
end
person.rb
class Person < ActiveRecord::Base
has_many :employments
has_many :interviews
has_many :companies, through: :employments
has_many :companies, through: :interviews
end
company.rb
class Company < ActiveRecord::Base
has_many :employments
has_many :interviews
has_many :companies, through: :employments
has_many :companies, through: :interviews
end
Person and Company are associated through Employment, but also redundantly through Interview.
There's nothing wrong with having two models having multiple associations, including multiple associations of the same type. You will want to give the associations unique names, though - otherwise when you called (for instance) #person.companies, you wouldn't know what you were going to get - companies through employments, or companies through interviews.
I believe this question has a decent example: ruby on rails has_many :through association which has two columns with same model

rails model doubts has_one, has_many, belongs_to

I have created 3 models for a small system. The intent here is to handle users, companies and their relationships. I anticipate to do a lot of lookups over the intersections and also want to have strict controls over the joins available, in that a user can only belong to one company, but company can have many users. I feel the best way to represent this is with the below. I would like some feedback on this preposition. So far my tests have worked fine validating my thesis and some small implementation efforts have gone fine, but when I look through a list of users to find their company I somehow run into issues and I have a feeling it is related to the has_one relationship, but not sure. Again thanks for constructive feedback.
class User < ActiveRecord::Base
has_one :companyrelationship, foreign_key: "user_id"
has_one :company, :through => :companyrelationship, dependent: :destroy
class Company < ActiveRecord::Base
has_many :companyrelationships
has_many :users, :through => :companyrelationships
class CompanyRelationship < ActiveRecord::Base
belongs_to :company
belongs_to :user
validates :user_id, presence: true, uniqueness: true
validates :company_id, presence: true
I do see one thing that I'm pretty sure is an error and won't work. I can also try to add a couple points of constructive criticism.
The error is that the CamelCase model name is converted to underscorey (sorry, I can't remember the term for that right now) case. All your references to companyrelationship should add an underscore. You can override the convention by setting the :class_name attribute, but I don't think that's what you wanted.
Another issue I see which isn't technically wrong, but is almost certainly not what you want is that the dependent: :destroy would delete the Company when you deleted a User. (Actually, I'm not sure dependent: :destroy works in a through: relationship.) I assume what you wanted was just to delete the CompanyRelationship. You can read the section on Dependent associations at this link:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Next point is that the default foreign_key is the model + _id so you don't need to specify it in this case.
My last point is purely a style preference. I like doing my validations by validation type. You're doing them by variable. They are functionally equivalent, so feel to take it with a grain of salt. (I'm pretty sure user and user_id are equivalent, but feel free to stick to user_id if you're more comfortable with it.)
If it were completely up to me, I would code it this way:
class User < ActiveRecord::Base
has_one :company_relationship, dependent: :destroy
has_one :company, through: :company_relationship
class Company < ActiveRecord::Base
has_many :company_relationships
has_many :users, through: :company_relationships
class CompanyRelationship < ActiveRecord::Base
belongs_to :company
belongs_to :user
validates_presence_of :user, :company
validates_uniqueness_of :user
I hope that helps you get further.

How to set up multiple aliased joins between two models?

In a Rails 3.2 app I need to set up two associations between the same two models.
For example
class User
has_many :events
has_many :attendances
has_many :attended_events, through: :attendances
end
class Event
belongs_to :event_organizer, class_name: "User"
has_many :attendances
has_many :attendees, through: :attendances, class_name: "User"
end
class Attendance
belongs_to :attended_event, class_name: "Event"
belongs_to :attendee, class_name: "User"
end
This is the first time I've experimented with aliasing class names, and I'm having trouble getting it to work. I'm not sure if the issue lies with how I've defined the associations, or elsewhere.
Do my associations look OK? Have I overlooked something needed to get this to work?
The problem I'm having is that no user ids are being set in the Attendance model. This may be a stupid question, but given my associations above, should the field name be :user_id or :event_organizer_id?
Really appreciate any suggestions on this. Thanks!
foreign_key to be specified in User and Event
class User
has_many :events
has_many :attendances, foreign_key: :attendee_id
has_many :attended_events, through: :attendances
end
class Event
belongs_to :event_organizer, class_name: "User"
# here it should be event_organizer_id
has_many :attendances, foreign_key: :attended_event_id
has_many :attendees, through: :attendances
end
class Attendance
belongs_to :attended_event, class_name: "Event"
# this should have attended_event_id
belongs_to :attendee, class_name: "User"
# this should have attendee_id because of 1st param to belongs_to here is "attendee"
# and same should be added as foreign_key in User model
# same follows for Event too
end

Rails basic association

I'm trying to do a basic model association in rails.
Basically I have a List table which stores item_id and user_id.
One user can create multiple "list-items."
Is this the correct way to do it?
Thanks.
class Item < ActiveRecord::Base
has_many :users, :through => :lists
end
class User < ActiveRecord::Base
has_many :items, :through => :lists
end
class List < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
Depending on what you want to reach, your solution is the right one (or not). I see the following cases:
You want to create an n:m association between items and users. So each item could be referenced by many users, and each user references many items. If this is the right context, then your solution is the right one. See the Rails Guides: Associations for more information on that.
An alternative for that situation could be to use the has_and_belongs_to_many Association. The situation is the same, but it does not make sense to talk about lists, there will be no model object for it.
If each users may have many lists, and each list may have many items, your solution would be wrong. This would be no n:m association with list as the join table in between, but two 1:n relations.
The code for the third example would look like that:
class User < ActiveRecord::Base
has_many :items, :through => :lists
has_many :lists
end
class List < ActiveRecord::Base
has_many :items
belongs_to :user
end
class Item < ActiveRecord::Base
belongs_to :list
end
In the first solution, you should add the relations for users to lists and items to list:
class Item < ActiveRecord::Base
has_many :lists
has_many :users, :through => :lists
end
class User < ActiveRecord::Base
has_many :lists
has_many :items, :through => :lists
end
If the "list" entity truly is a pure association/join, that is, it has no inherent attributes of its own, then you can simplify a bit and use has_and_belongs_to_many. Then you don't need a "List" class.
class Item < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :items
end
Rails will look for the references in a "items_users" table, so in your migration, you need to create it a la:
create_table :items_users, :id => false do |t|
t.references :users, :items
end
Many people will tell you to always use has_many :through, but others (like me) will disagree - use the right tool for job.