I have table:
Groups
and table
Library
Now, I would like to make association, that I can set which Library records can Groups records see (basicaly a checkbox). So that If user belongs to a Group, he doesn't see certain Library records.
One suggestion before you start - don't use Group as an ActiveRecord class name as it will override certain functionality that already uses that term by convention. For now, I'll assume you are using Group.
If a Library can belong to only one Group, you need a simple has_many-belongs_to association setup:
class Group < ActiveRecord::Base
has_many :users
has_many :libraries
end
class Library < ActiveRecord::Base
belongs_to :group
end
class User < ActiveRecord::Base
belongs_to :group
has_many :libraries, :through => :group
end
If Library can belong to several Groups, you'll need a join table (and ideally a join model) to set this up:
class Group < ActiveRecord::Base
has_many :users
has_many :group_libraries
has_many :libraries, :through => :group_libraries
end
class GroupLibrary < ActiveRecord::Base
belongs_to :group
belongs_to :library
end
class Library < ActiveRecord::Base
has_many :group_libraries
has_many :groups, :through => :group_libraries
end
class User < ActiveRecord::Base
belongs_to :group
has_many :libraries, :through => :group
end
Related
I'm having trouble trying to understand/wrap my brain around this. I'm trying to create a relationship that allows this:
User has_many Groups
Item has_many Groups
Groups has_many User
Groups has_many Items
So I think I need a Join-Table here but belongs this table to three models or do I need two Join-Tables?
class Group < ActiveRecord::Base
has_many :users
has_many :items
end
class User < ActiveRecord::Base
has_and_belongs_to_many :groups
end
class Item < ActiveRecord::Base
has_and_belongs_to_many :groups
end
So what is the right migration here for my Group model?
These are two separate many-to-many associations. Each many-to-many to many association requires a join table.
For has_and_belongs_to_many you can generate the migrations with:
$ rails g migration CreateJoinTableGroupsUsers group user
$ rails g migration CreateJoinTableGroupsItems group item
However has_and_belongs_to_many is very limited and has_many through: is usually a better option.
One example of the limits of has_and_belongs_to_many is that you can't add any additional columns on the join table (metadata) and you can't query the join table directly. So you're skrewed if you want to keep track of stuff like when a user joined a group or who added an item to a group.
$ rails g model Membership user:belongs_to group:belongs_to
$ rails g model GroupItem group:belongs_to item:belongs_to
class User < ApplicationRecord
has_many :memberships
has_many :groups, through: :memberships
end
class Group < ApplicationRecord
has_many :memberships
has_many :group_items
has_many :users, through: :memberships
has_many :items, through: :group_items
end
class Membership < ApplicationRecord
belongs_to :user
belongs_to :group
end
class Item < ApplicationRecord
has_many :group_items
has_many :groups, though: :group_items
end
class GroupItem < ApplicationRecord
belongs_to :user
belongs_to :item
end
I have a model User and a model Group, between the two I want to create a many-to-many association with a join-table, using through.
user.rb:
class User < ActiveRecord::Base
has_many :groups_user
has_many :groups, :through => :groups_user
end
group.rb:
class Group < ActiveRecord::Base
has_many :groups_user
has_many :users, :through => :groups_user
end
groups_user.rb
class GroupsUser < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
I initially tried to do the same thing naming the joining model class GroupsUsers in groups_users.rb but I got an uninitialized constant error unless I used :class_name to specify the class name.
My question is: What is the logic behind pluralizing the first name, but not the second? The association is many-to-many so both models are on equal footing. In this case group comes first merely because of the lexical order. So why pluralize one and not the other? This makes no sense to me.
The more conventional naming approach would be:
#user.rb:
class User < ActiveRecord::Base
has_many :group_users
has_many :groups, :through => :group_users
end
#group.rb:
class Group < ActiveRecord::Base
has_many :group_users
has_many :users, :through => :group_users
end
#group_user.rb
class GroupUser < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
Conventionally, the model has the singular form. So GroupsUser, not GroupsUsers. But, an instance of the join model has only one Group and one User, So, GroupUser, not GroupsUser.
If you look at the The has_many :through Association section of the Active Record Associations guide, for instance, you will see that the join model (Appointment) is singular. This is the pattern you want to follow.
If you decide to do things unconventionally, then rails needs you to help it - for instance by requiring that you specify class_name.
I'm still learning how to use has_many and has_many through relationships effectly. I am currently building a system where I would like users to be able to access certain maps that they are added to.
The map model is what I need the user to be able to access if they are apart of a certain group.
class Map < ApplicationRecord
has_many :rows
has_many :mapgroups
has_many :groups, through: :mapgroups
end
Since a user can belong to many groups I have a has_many through relationship
class Usergroup < ApplicationRecord
belongs_to :user
belongs_to :group
end
class User < ApplicationRecord
has_many :usergroups
has_many :groups, through: :usergroups
end
class Group < ApplicationRecord
has_many :usergroups
has_many :users, through: :usergroups
has_many :mapgroups
has_many :maps, through: :mapgroups
end
I thought about making a mapgroup model to take care of this but, so far, I am not so sure this is going to work.
class Mapgroup < ApplicationRecord
belongs_to :map
belongs_to :group
end
I am looking for a method to check to see what groups the user is apart of and then, based on those groups, give the user access to the corresponding maps. Am I on the right track with the relationships? How could I do this?
If you want to use MapGroup model only for keeping users an map connected (ModelGroup has only foreign keys on Group and Map) it's not the best approach. In this case it's better to opt for has_and_belongs_to_many assosiation. It will let you to assosiate Groups and Maps without creating useless model.
A has_and_belongs_to_many association creates a direct many-to-many connection with another model, with no intervening model.
class Group < ApplicationRecord
...
has_and_belongs_to_many :maps
end
class Map < ApplicationRecord
...
has_and_belongs_to_many :groups
end
I have a many-to-many relationship setup for Teachers and Classrooms via has_many :through:
class Teacher < ActiveRecord::Base
has_many :classrooms, :through => :classroom_memberships
end
class Classroom < ActiveRecord::Base
has_many :students
has_many :teachers, :through => :classroom_memberships
end
class ClassroomMemberships < ActiveRecord::Base
belongs_to :teacher
belongs_to :classroom
end
Currently, Students can only belong to one Classroom:
class Student < ActiveRecord::Base
belongs_to :classroom
end
Now I have the need to track historical classroom memberships for students, creating a second many-to-many relationship for classrooms. So, while a student can only belong to one classroom at a time, I need to know that last year, student A belonged to classroom B.
I'm thinking I have two viable options:
1.) Make the classroom_memberships association polymorphic so I'd have a classroomable_id and classroomable_type that would point to either a teacher OR a student.
2.) Simplify things and add another foreign key to ClassroomMemberships called student_id, in which case, for a given row, either student_id OR teacher_id would have a value.
Which is the better option?
I would probably go the route of:
class Course < ActiveRecord::Base
# like "MATH 100"
has_many :sections
has_many :teachers, :through => :sections
end
class Term < ActiveRecord::Base
# like "Fall 2015"
has_many :sections
end
class Teacher < ActiveRecord::Base
has_many :sections
has_many :courses, :through => :sections
end
class Section < ActiveRecord::Base
# a course, in a term, taught by a teacher, with registered students
belongs_to :term
belongs_to :course
belongs_to :teacher
has_many :registrations
has_many :students, :through => :registrations
end
class Registration < ActiveRecord::Base
# a student in a specific section
belongs_to :section
belongs_to :student
end
class Student < ActiveRecord::Base
# a student's registrations are their course history
has_many :registrations
has_many :sections, through :registrations
end
As a start, since this is a fairly basic modeling of an educational system.
It sounds like maybe you want a ClassroomMembershipHistory model.
Something like
class ClassroomMembershipHistory < ActiveRecord::Base
belongs_to :student
belongs_to :classroom
end
with a year attribute, stored however is easiest to query for your use case.
I have question regarding associations in Ruby on Rails. In the application there are projects, users, roles and groups. The project belongs to a group with users, a user can belong to many different groups but can only have one specific role within that group. For example:
In one group the user is the project owner, but in another group he is a writer.
What is the best way to implement this using the built in functions in Rails?
Thanks
Here is a very quick set of models that should fulfill your requirements:
class User < ActiveRecord::Base
has_many :group_memberships
has_many :groups, :through => :group_memberships
end
class GroupMembership < ActiveRecord::Base
belongs_to :user
belongs_to :role
belongs_to :group
end
class Role < ActiveRecord::Base
has_many :group_memberships
end
class Group < ActiveRecord::Base
has_many :group_memberships
has_many :users, :through > :group_memberships
end
Basically there is a join table that has a user, group and role id in it. I'll leave the migrations as an exercise for the questioner