Ruby on rails many-to-many - ruby-on-rails

I have two models Type and Activity. Type has_many activities and Activity has_many types. To do this I used the has_many :through thing. This is how it looks like
Activity
has_many :typeitems
has_many :types, :through => :typeitem
Typeitem
belongs_to :activity
belongs_to :type
Type
has_many :typeitems
belongs_to :activity
This does not feel right though. I would want to query 2 things
Activities of a particular type
Types of a particular activity
When I went into rails console and typed types.activity I got a nil which means I will get a single object. Should I change the belongs_to in Type model to has_many.But then it's back to many-to-many. There should be a way.
I looked at the docs and found has_and_belongs_to_many. I also read this
You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.
I am not using it now but I might want to in the future.

Both sides need a has_many :through:
Activity
has_many :typeitems
has_many :types, :through => :typeitem
Typeitem
belongs_to :activity
belongs_to :type
Type
has_many :typeitems
has_many :activities, through: :typeitems

Related

has_one through association with condition

I have 3 relevant tables/models. I would like to retrieve the user which has organized a party, given a Party record, a join table with a boolean organized column, and a users table.
My best attempt so far (this one makes the most sense to me after much fiddling). I've omitted the irrelevant columns.
class Party
# party_id
has_many :parties_users
has_many :users, through: :parties_users, source: :user
has_one :organizer,
-> { where organizer: true },
through: :parties_users,
source: :user
class PartiesUser
# party_id
# user_id
# organized:bool
belongs_to :party
belongs_to :user
class User
# user_id
has_many : parties_users
The above setup raises the following error, which I honestly don't fully understand:
ActiveRecord::HasOneThroughCantAssociateThroughCollection (Cannot have a has_one :through association 'Party#organizer' where the :through association 'Party#parties_users' is a collection. Specify a has_one or belongs_to association in the :through option instead.)
I know I can do this via an instance method, but given the frequency types of use, my app would massively benefit from having this as an association.
As the error message says, you can't have a has_one through a has_many.
You could (instead) do it this way if the organizer flag is on the join record...
has_many :parties_users
has_many :users, through: :parties_users, source: :user
has_one :main_party_user, -> {where organizer: true}, class_name: 'PartiesUser'
has_one :organizer, through: :main_party_user, class_name: 'User'

Ruby ORM polymorphic relationships, Active Record

So I am working with the Ruby ORM and trying to understand many-to-many syntax and polymorphism.
Here are my Active Record relationships so far.
class Association < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: "User"
end
and
class User < ActiveRecord::Base
has_many :associations
has_many :friends, through: :associations
end
I can't seem to get a list of friends per user when those friends are associated with more than one user. In other words some users have friends and these friends may have more than one user association too.
First off, these are not polymorphic associations. One uses polymorphic associations when a model could belong to many models, like a Comment model. A user can comment on a post, on a picture, on a project, so the Comment model could belong to any of these, so there we use Polymorphic associations. Read here to know more about it.
Well, the thing that you are asking is about Inverse Friends, and here is how you can implement it.
class User < ActiveRecord::Base
has_many :associations
has_many :friends, through: :associations
has_many :inverse_associations, class_name: "Association", foreign_key: :friend_id
has_many :inverse_friends, through: :inverse_associations, source: :user
end
class Assocation < ActiveRecord::Base
belongs_to :user
belogns_to :friend, class_name: 'User'
belongs_to :inverse_friend, class_name: 'User', foreign_key: :friend_id
end

Rails 4 has_many through naming

I'm having problems with a Rails 4 join table. I have quite a simple setup which is working elsewhere in my application using a non-conventionally named table for users, groups and usergroupmemberships. I'm trying to set it up this time using the proper conventional naming and it's just not working.
Models involved are User, ManagementGroup and ManagementGroupsUser
db tables: management_groups_user, management_groups, users
app/models/user.rb
Class User < ActiveRecord::Base
...
has_many :management_groups, through: management_groups_users
has_many :management_groups_users
....
app/models/management_group.rb
class ManagementGroup < ActiveRecord::Base
has_many :users, through: :management_groups_users
has_many :management_groups_users
app/models/management_groups_user.rb
class ManagementGroupsUser < ActiveRecord::Base
belongs_to :users
belongs_to :management_groups
The association appears to work from with #user.management_groups_users but nothing else. I'm fairly sure this is a problem with naming / plurality but I can't figure it out.
This is the model which joins the remaining models user.rb and management_group
#app/models/management_groups_user.rb
belongs_to :user
belongs_to :management_group
Since we are going to use model above to access another model management_group then
#app/models/user.rb
has_many :user_management_groups #This should come first
has_many :management_groups, through: user_management_groups
Since we are going to use model above to access another user model then
app/models/management_group.rb
has_many :user_management_groups
has_many :users, through: :user_management_groups
Now should work
Do it this way.
app/models/user.rb
has_many :user_management_groups
has_many :management_groups, through: user_management_groups
app/models/management_group.rb
has_many :user_management_groups
has_many :users, through: :user_management_groups
app/models/management_groups_user.rb
belongs_to :user
belongs_to :management_group
I hope these associations will help you.
This is another way if you pass foreign key and class name.
app/models/user.rb
has_many :user_management_groups, :foreign_key => "key", :class_name => "ClassName"
has_many :management_groups, through: user_management_groups, :foreign_key => "key", :class_name => "ClassName"
app/models/management_group.rb
has_many :user_management_groups
has_many :users, through: :user_management_groups
app/models/management_groups_user.rb
belongs_to :user, class_name: "ClassName"
belongs_to :management_group, class_name: "ClassName"
This is another way around.
It's important to realize there is a convention rails uses for HABTM and has many through. HABTM does not have a model, so it needs to infer the table name which, as others point out, is both plural and alphabetical order.
If you are doing has many through and have a model, the convention is that it wants singular first word, plural second. See examples
User has and belongs to many groups.
HABTM: table name should be groups_users
Has Many Through: table name should be user_groups (flip order is more intuitive)
Model for the latter would be UserGroup. Has many through would specify it as through: :user_groups

Rails has_one through has_many not working

Has anybody had any luck having a has_one go through a has_many relationship in the same model. I keep getting
ActiveRecord::HasOneThroughCantAssociateThroughCollection: Cannot have a has_one :through association
It seems like it would be easy take a set of has_many results and filter it down by a specific key and call it a has_one relationship.
Using rails 3.2.12
Here is my associations right now participation is a different model.
has_one :original_participation, :through => :participation
has_one :original_participant, :through => :original_participants, :foreign_key => "organization_id"
has_many :original_participants,
:through => :original_participation,
:source => :participants
I need to go through this last association and filter it down by organization_id.
ActiveRecord::HasOneThroughCantAssociateThroughCollection: Cannot have a has_one :through association 'Surveys::Participant#original_participant' where the :through association 'Surveys::Participant#original_participants' is a collection. Specify a has_one or belongs_to association in the :through option instead.
With has_one you should not need :through There is no need for an intermediary relationship.
If I think I know what you're trying to do you have a hierarchy of tests:
has_one test_parent, :class_name => "Test", foreign_key: "child_test"
has_many tests
to call them:
#my_array_of_children = tests
#my_parents_id = test.id
etc.

How to write has_many through two objects (to the same 'destination' object)?

What is the correct way to describe the relationship between a User and the Outcomes of their Questions and Contacts? I want to be able to call User.outcomes and get all outcomes for the user, regardless of whether the outcome was for a question or a contact.
Here are my models as they stand right now. Are the has_many through relationships described correctly?
User Model
has_many :questions
has_many :contacts
has_many :outcomes, through: :questions
has_many :outcomes, through: :contacts
Question Model
has_many :outcomes
Contact Model
has_many :outcomes
Outcomes Model
belongs_to :question
belongs_to :contact
So, this is probably not the ideal solution because it returns an Array instead of an ActiveRecord::Relation. That means you lose lazy loading and the ability to further add scopes and where statements and whatnot. It's better than writing SQL and should do what you want though:
class User < ActiveRecord::Base
has_many :questions
has_many :contacts
has_many :questions_outcomes, :through => :questions, :class_name => "Outcomes"
has_many :contacts_outcomes, :through => :contacts, :class_name => "Outcomes"
def outcomes
return questions_outcomes + contacts_outcomes
end
end
Please let us know if you come up with something nicer.

Resources