I have such model structure:
class User < ActiveRecord::Base
has_many :groups, :through => :user_groups
has_many :orders
has_many :user_groups
end
-
class UserGroup < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
-
class Group < ActiveRecord::Base
has_many :user_groups
has_many :users, :through => :user_groups
end
In model group i have field markup.
How can i for every user via it's user_groups get group's markup field?
I try so:
user.user_groups.each do |u|
summ += u.groups.markup
end
Sure it is not working... But how to fetch data from third model?
user.groups.map(&:markup).sum should do it just fine
EDIT:
I used #flat_map because I was thinking that it was a nested array. But has_many :through would combine it into a single result list, so #map will be fine
EDIT2:
In discussion with #VladisAzamaris, it was pointed out that the markup column is a float, so sum is more appropriate than join
First off, may as well take advantage of that has_many :through here:
user.groups # => all the groups to which this user belongs
How about something like this to get the markup? This'll put 'em all in a list, unless you actually did want them all in one big string, in which case you'd join 'em.
user.groups.map(&:markup)
Also, if there aren't any other fields on the UserGroup model, consider a has_and_belongs_to_many relationship, in which Rails handles that glue UserGroup model for you rather than having you declare it.
Related
I have two models with a relation like this:
class Ticket < ActiveRecord::Base
belongs_to :group
end
class User < ActiveRecord::Base
has_and_belongs_to_many :groups
has_many :tickets, as: :assignable
end
class Group < ActiveRecord::Base
has_many :tickets, -> { order(:created_at) }
has_and_belongs_to_many :users
end
I need to get all tickets belonging to the same groups the user has.
How can I accomplish that? Thank you so much!
As things stand, your relations are incomplete and so Rails won't work properly. If User has_many Tickets then Tickets must belong_to (or at least has_one) User. Alternatively, User can have_many Tickets through Group, which seems more likely in this case.
However, even then, it's not clear what your Group model is doing. Particularly, it's not clear how you intend it to relate to User - this looks like quite a complex relationship.
To start with, though, try and set the models up like this:
class Ticket < ApplicationRecord
belongs_to :group
end
class Group < ApplicationRecord
belongs_to :user
has_many :tickets, dependent: :destroy
end
class User < ApplicationRecord
has_many :groups, dependent: :destroy
has_many :tickets, through: :groups
end
(You'll see that I've also inherited these models from ApplicationRecord, which is how I've always done it.)
If you set it up as above, you can get your ticket records with a simple #user.tickets.
If this works, you can then add the extra HABTM relationship for Groups and Users. But be aware that HABTM relationships can be complex and there are good and bad ways to use them.
(If the primary relationship you really want is Groups > Users > Tickets then let me know and I can adjust accordingly.)
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 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
So I'm Rails n00b and I want to create a "favorites" relationship such that a User can have many favorite Item. I'm not entirely sure how to do this, this is how I'm going to try but I'm not sure if this is a good practice at all:
class User < ActiveRecord::Base
has_many :favorites
//other code
end
class Favorite < ActiveRecord::Base
belong_to :user
has_one :item
end
class Item < ActiveRecord::Base
belongs_to :item
end
Is this a good way to do it? Should I be using has_and_belongs_to_many ?
I'm specially concerned in the following scenario: Say a user has 100 favorite items.
When I do a User.find(id) will I also be retrieving the 100 favorites and the 100 Items?
In case it's important: ruby version 1.9.3, rails version 3.2.11
Can you try has_many => :through?
class User < ActiveRecord::Base
has_many :favorites
has_many :items, :through => :favorites
//other code
end
In your case has_many :through is definitely the way to go. I would recommend reading: http://guides.rubyonrails.org/association_basics.html
Of particular interest with regard to your question:
2.8 Choosing Between has_many :through and has_and_belongs_to_many
Rails offers two different ways to declare a many-to-many relationship between models. The simpler way is to use has_and_belongs_to_many, which allows you to make the association directly:
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
The second way to declare a many-to-many relationship is to use has_many :through. This makes the association indirectly, through a join model:
class Assembly < ActiveRecord::Base
has_many :manifests
has_many :parts, :through => :manifests
end
class Manifest < ActiveRecord::Base
belongs_to :assembly
belongs_to :part
end
class Part < ActiveRecord::Base
has_many :manifests
has_many :assemblies, :through => :manifests
end
The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you’ll need to remember to create the joining table in the database).
You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.
It is better than using has_and_belongs_to_many.
When I do a User.find(id) will I also be retrieving the 100 favorites
and the 100 Items?
No. You'll just get the user object.
Update:
Calling User.include(:favourites, :items).find(id) will get you joined tables in case you want to make many calls to items table from user object.
I have two models, Users and Groups. Each group can have many users and each user can be in many groups.
I currently have something simple like:
User:
has_many :groups
Group:
has_many :users
So I have a groups_users table which is just creating rows with group_id and user_id.
I want to add another column to this, (which I have), the question is how do I access it from a model without using a custom SQL call? In the group model I can go self.users and in user I can go self.groups
Is there a way to change the third column in this table from a user model?
Sorry if this is confusing, please advise on this
Here are a couple of tutorials that should help. Basically there two approaches to make many-to-many work, either has_and_belongs_to_many or has_many :through (recommended).
links:
http://blog.hasmanythrough.com/2006/4/20/many-to-many-dance-off
http://railscasts.com/episodes/47-two-many-to-many
http://railscasts.com/episodes/154-polymorphic-association
In Rails 3 you want to make a join table for many to many relationships, using the plural names of the tables you want to join in alphabetical order. So in this case it would be groups_users.
models
class GroupsUser < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class User < ActiveRecord::Base
has_many :groups_users
has_many :groups, :through => :groups_users
end
class Group < ActiveRecord::Base
has_many :groups_users
has_many :users, :through => :groups_users
end
I [added] another column to [users_groups]...The question is how do
I access it from a model without using
a custom SQL call?
It sounds like you want to access a column of your user_groups table by calling a method on your User model or your Group model.
Some suggestions:
I'd name the table "user_groups" to work with ActiveRecord's pluralization expectations, but I'm not sure if that's essential.
Following Dave's advice, you'd want to set things up using the "has_many :through" technique...
# Declare a Model based on the many-to-many linking table.
class UserGroup < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class User < ActiveRecord::Base
has_many :user_groups
has_many :groups, :through => :user_groups
end
class Group < ActiveRecord::Base
has_many :user_groups
has_many :users, :through => :user_groups
end
Is there a way to change the third column in this table from a user model?
This is a little unclear, but keep in mind that each User can have a lot of UserGroups. So if you wanted to change that third column you'd have to find the particular one you're looking for.