Not sure how to setup the tables and the relationships for what I'm trying to achieve. I thought I need a has_one through relationship but I saw a few posts advising against that.
What I'm trying to achieve is a shop creates a list of their services and their staff select the services they do from this list.
Here's what I have so far:
class User
has_many :staff
# user and shop have relationship via roles (not shown for simplicity)
end
class Shop
has_many :staff
has_many :services
# user and shop have relationship via roles (not shown for simplicity)
end
class Service
belongs_to :shop
has_many :staff through: :staff_services
end
class Staff
belongs_to :shop
belongs_to :user
has_many :services through: :staff_services
end
class StaffService
belongs_to :staff
# ? has_one :service through: :shop
# ? belongs_to :service
end
I'm not sure how to set the relationship for StaffServices so that a staff is only able to select services from the shop they are a staff member of.
Any help would be appreciated. Thanks!
If I understand you correctly you want a many-to-many associations between Staff and Services. I believe you want belongs_to :service in your StaffService table. This can be simplified to isolate the association you're working with as such:
class Service
has_many :staff, through: :staff_services
end
class Staff
has_many :services, through: :staff_services
end
class StaffService
belongs_to :staff
belongs_to :service
end
I don't mean to suggest the other associations you've got in your example are invalid or wrong in any way--I just wanted to show only the many-to-many part. The associations you already have up there between Shop & Staff, and Shop & Services will allow you to build scopes easily that will restrict the set of Staff and Services involved.
If you haven't already, I suggest giving the Rails Guide to Associations a careful read.
Related
I have three models - Company, User and CompanyUser. The associations are as follows.
Company.rb
has_many :company_users
has_many :users, :through => :company_users
User.rb
has_many :company_users, :dependent => :destroy
belongs_to :company
CompanyUser.rb
belongs_to :company
belongs_to :user
For fetching current_user.company, what moddifications are to be made in the model association?
Any help would be appreciated.
It should be:
has_many :companies, through: :company_users
A has_many :through association is often used to set up a many-to-many
connection with another model. This association indicates that the
declaring model can be matched with zero or more instances of another
model by proceeding through a third model.
So if you are creating three models and making a has_many :through association I believe that User will have many Companies and Company will have many Users.
But if you need that the user belongs to only one company instead of creating the third model save the company_id in the users table itself.
Update:
Now as your scenario is A company can have may users and User belongs to a single company, you need two models: User and Company. Your User model should have an attribute company_id and then company_id should be saved in users table only. Then the associations as follows:
class User < ActiveRecord::Base
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :users
end
Then you can do current_user.company
You can get more information on associations in the RailsGuides
According to the associations you have taken,
user already have as association with the company through the Company User model, so user may have many companies according to your associations.
so,
class User < ActiveRecord::Base
has_many :company_users, :dependent => :destroy
has_many :companies, :through => :company_users
end
current_user.companies will give you the companies.
But if you need only one company for a user then,
class User < ActiveRecord::Base
belongs_to :company
end
take belongs_to company and save company_id in users table,
then you can call,
`current_user.company`
According to your logic,
I think you may need to create a new variable session current_company_user which is object CompanyUser.
And then, to fetch company by :
current_company_user.company
I have searched and searched and found only partial solutions to my current question.
The thing is, I'd like to know if it is possible to use has_many :through along with a polymorphic association in Ruby on Rails.
I have a system where students can create travel plans (that can belong to many students) and refund claims (that can belong to only one student) for their projects. In this system, both admin users and students are able to comment on the plans and claims.
My associations are:
class Student < ActiveRecord::Base
has_and_belongs_to_many :travel_plans
has_many :refund_claims
has_many :comments, through: :travel_plans
has_many :comments, through: :refund_claims
end
class AdminUser < ActiveRecord::Base
has_many :comments
end
class TravelPlan < ActiveRecord::Base
has_and_belongs_to_many :students
has_many :comments, as: :commentable
end
class RefundClaim < ActiveRecord::Base
belongs_to :student
has_many :comments, as: :commentable
end
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
My questions are:
Is it correct to associate comments twice in the Student model?
I don't want the AdminUsers to have travel plans and refund claims, how can I identify their comments as being made on a travel plan or on a refund claim?
Would there be a better approach?
Thanks a lot in advance for everyone!
Cheers,
You probably want to add an polymorphic author attribute to the Comment model. Than you just need has_many :comments, as: :author to the Student and AdminUser model.
If this is a new application and you are starting on the green field you might want to rethink your models a bit and add a Role and a User model. Student would than be a role of user as would AdminUser be.
Is it correct to associate comments twice in the Student model?
No, not really. If you have duplicate association name, you can only use one of them. If you want to use both, you have to name them differently.
My app has 5 core models. I'm trying to figure out the best way to associate the models. How many tables should I build and which kind etc?
Here are the associations I would like to include and their respective models:
User
Has many boards
Has many lists
Has many cards
Has many comments
Board
Has many users
Has many lists
Has many cards
List
Belongs to board
Has many cards
Card
Belongs to board
Belongs to list
Has many comments
Comment
Belongs to card
Belongs to user
class User < ActiveRecord::Base
has_and_belongs_to_many :boards
has_many :lists, as: listable
has_many :cards, as: cardable
has_may :comments, as: commentable
end
class Board < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :lists, as: listable
has_many :cards, as: cardable
end
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class List < ActiveRecord::Base
belongs_to :listable, :polymorphic => true
has_many :cards, as: cardable
end
class Card < ActiveRecord::Base
belongs_to :cardable, :polymorphic => true
has_many :comments, as:commentable
end
To establish HABTM relation you have to create a table named 'users_boards'
As Board and User are having many to many relationship, there will be a new table for it, if you want HABTM you can use it.
User(id, name, other_attributes...)
Board(id, name,...)
List(id, name, user_id(fk),...)
Card(id, name, user_id(fk), list_id(fk), board_id(fk),...)
Comment(id, comment_msg, user_id(fk), card_id(fk),...)
Board_User(board_id(fk), user_if(fk)) --- M-M relation
Few attributes might change if there is a has_many through relation.
FK-- Foreign key, you can use has_many through depending on your requirements.
Using polymorphic associations has some limitations, so please do through it then decide to use a polymorphic association
http://codeblow.com/questions/pros-and-cons-for-ruby-on-rails-polymorphic-associations/
I'm beginning a project with rails where there are products, clients and sellers. Each seller has_many products. Each Client has_many products. (And in my case, each client only buys one product at a time).
I want to know who are my clients' seller and my Seller's clients, knowing that, they'll be linked by, the purchase, of one product.
Should I use a has_and_belongs_to_many association between clients and sellers ? Or a double has_many through :products, like :
Seller :
has_many :clients through :products
Belongs_to :products
Client :
has_many :sellers through :products
Belongs_to :products
In order to avoid two belongs_to in the product class, could this work ?
class Client < ActiveRecord::Base
has_many :products, as: :productable
has_many :sellers, through: :products
end
class Seller < ActiveRecord::Base
has_many :products, as: :productable
has_many :clients, through: :products
end
class Product < ActiveRecord::Base
belongs_to :productable, polymorphic: true
end
Thanks in advance for your answer.
I would go with has_many :through here.
class Client < ActiveRecord::Base
has_many :products
has_many :sellers, through: :products
end
class Seller < ActiveRecord::Base
has_many :prodcuts
has_many :clients, through: :products
end
class Product < ActiveRecord::Base
belongs_to :client
belongs_to :seller
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.
And also see these Guides for choosing between HABTM and a has_many :through
I want to approach your question from the other end: let us start from the product. I think this will clarify a lot of things.
So you have three models: Seller, Client and Product.
A Product has a seller and client. In your model that would like this:
class Product
belongs_to :seller
belongs_to :client
end
This means that in the products table we have a column seller_id and client_id.
Afaik a product needs to have both, always. So this also means you cannot use a polymorphic association here. At least not the way you proposed it. If you write
belongs_to :productable, polymorphic: true
you will add the fields productable_id and productable_typeto yourProduct` model. But that is only 1 link (so either a seller or a client, but never both). You could introduce a link table here, so a product could be linked to many "productables" but in your case i think it is besides the point. You know a product has one seller and one client.
Secondly, now this is established, your Product is exactly the link-table between clients and sellers. So you do not have to introduce a new link-table, just use the one already there.
class Seller
has_many :products
has_many :clients, through: :products
end
class Client
has_many :products
has_many :sellers, through: :products
end
So in conclusion:
use the has_many :through because you already have the link table as a model. Only use a habtm if you do not care about the join-table (link-table).
you can't use a polymorphic association here, as you need two links (without introducing a link-table, which seems overkill imho). I like the explicitness, clarity, readability of having an explicit seller_id and client_id, and it is also easier to manage.
I have 3 models: Guardian, Student and Organization. Guardian is connected to Student through a linking model and similarly Student is connected to Organization through a linking model. I need to get for every guardian, a list of (distinct) organizations and am wondering what the best way to do so is.
Currently I do it at the application level in the Guardian class
def organizations
orgs = []
students.each do |s|
s.organizations.each do |o|
orgs << o if !orgs.include?(o)
end
end
orgs
end
I wonder if there's a better way to do this, preferably at the database level. Any help will be appreciated.
Edit: here's a more detailed description of my models
class Person < ActiveRecord::Base
end
class Guardian < Person
has_many :student_guardian_links, inverse_of: :guardian, dependent: :destroy
has_many :students, through: :student_guardian_links, inverse_of: :guardians
end
class Student < Person
has_many :student_guardian_links, inverse_of: :student, dependent: :destroy
has_many :guardians, through: :student_guardian_links, inverse_of: :students
has_many :student_organization_links, inverse_of: :student, dependent: :destroy
has_many :organizations, through: :student_organization_links
end
class Organization < ActiveRecord::Base
has_many :student_organization_links, inverse_of: :organization, dependent: :destroy
has_many :students, through: :student_organization_links, inverse_of: :organizations
end
With relational databases is often better to think from the target set. So you want organisations with specific conditions (they have students connected to a specific guardian)
In ActiveRecord we have joins for this. It is a misnamer, as you still get only Organisation objects, it only uses a SQL-join to get them from the database, and you can specify conditions on the joined object.
Look at http://guides.rubyonrails.org/active_record_querying.html at "Joining Nested Associations" and "Specifying Conditions on the Joined Tables"
So depending on your exact model (remember you need the backward connections) it may look like this:
Organinisation.joins(:students).where('student.guardian_id' => mygivenguardian.id).distinct()
distinct is important when the join can lead to multiplications of the rows, as when a guardian is connected with more then one student to the organisation.
This should work:
students.map { |student| student.orgs }.flatten.uniq
Really the same approach you are taking. Just using a more functional approach.
Try this:
class Guardian < ActiveRecord::Base
has_many :organizations,
:through => :students
# Your existing relationships go here
end
This way you can simply call guardian.organizations.uniq to get a list of distinct organizations associated with a specific Guardian object.