Ruby data modellng has_many relationship two way - ruby-on-rails-3

I've got a question about a certain data model in Ruby. I've got a set of business requirements:
User can create many Workshops
User can attend many workshops
Workshop has one owner (user)
Workshop has many attendees (users)
The first part of this relationship is easy to setup:
#user.rb
class User < ActiveRecord::Base
has_many :workshops
end
#workshop.rb
class Workshop < ActiveRecord::Base
belongs_to :user
end
But how will i make the "other has_many" relationship from workshops to Users. Can i do something like a workshop belongs_to :user, :as :owner. and a workshop has_many :users, :as :attendees?
What are your thoughts about this? To make it worse a Workshop has a attendee limit so i need validations...
Thanks,
Daniel

You have a has_many to has_many relationship, so you'll need to create a new associative table to associate the relationships (lets call it attendances):
create a db migration:
rails g model attendance
Then in your migration do something like:
create_table :attendances do |t|
t.integer :attendee_id
t.integer :workshop_id
end
add_index :attendances, :attendee_id
add_index :attendances, :workshop_id
add_index :attendances, [:workshop_id, :attendee_id]
So now you have a table you where you can associate many attendees to many workshops.
Now in your user model:
has_many :attending, through: :attendances, foreign_key: 'attendee_id', class_name: 'Workshop', source: :workshop
In your workshop model:
has_many :attendees, through: :attendances, class_name: 'User', source: :attendee
So now 'some_user.attending' will return the ActiveRecord relation of all the workshops some_user is attending, and 'some_workshop.attendees' will give you all the users attending some_workshop.

Related

Rails 5 query association must comply with multiple conditions

In in a Rails 5 application we have a User and a Job models which have many skills through AttachedSkills.
AttachedSkills is a polymorphic table. It saves users or jobs skills.
User Model
class User < ApplicationRecord
has_many :attached_skills, as: :skillable, dependent: :destroy
has_many :skills, through: :attached_skills
end
Job Model
class Job < ApplicationRecord
has_many :attached_skills, as: :skillable, dependent: :destroy
has_many :skills, through: :attached_skills
end
Skills Model
class Skill < ApplicationRecord
has_many :attached_skills
end
AttachedSkill Model
class AttachedSkill < ApplicationRecord
belongs_to :skill
belongs_to :skillable, polymorphic: true
end
In the skills table let's say I have skills with id 640 and 641.
I need a query that fetches all users that have both skills. They must have at least these two skills.
How can I write such a query?
Ruby 2.6.6
Rails 5.2.5
Postregesql

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

How do I set up a has_one through association through a has_many through association?

I have a User model, a Membership model, and a Club model. I have set up the following associations:
Club.rb
has_many :memberships
has_many :members, through: :memberships
Membership.rb
belongs_to :user
belongs_to :club
What I want now is to have a has_one :organizer on Club that retrieves a single User record based on the member with the organizer attribute set to true in the join model.
How do I set up this has_one association? I've tried going through the memberships association, but an exception is raised that the memberships is a collection and needs to be singular.
I think I just figured it out...but in case someone else needs to know..
has_one :membership, conditions: ['memberships.organizer = ?', true]
has_one :organizer, through: :membership, source: :user

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.

Find all records NOT in a many-to-many association

In Rails 3 with ActiveRecord, I have 2 models (Users and Tasks). These models are linked together with a has_many :through association on another model, Assignments. How can I find all Tasks that are NOT associated to a particular user?
class User < ActiveRecord::Base
has_many :assignments
has_many :tasks, :through => :assignments
end
class Tasks < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
end
class Assignments < ActiveRecord::Base
belongs_to :users
belongs_to :tasks
end
Short 'n sweet:
Task.all - user.tasks
Avoid loading user tasks:
Task.where('id not in (?)', user.task_ids)
I couldn't figure out how to do it with an outer join in AR.
I'm going to assume you want those tasks without any associated user, rather than not associated to a user in particular.
Tasks.joins('left outer join assignments on assignments.task_id = tasks.id').where('assignments.* is null')