Modeling my Database - mysql

this is my first post on here. My question is pertaining to model relationships.
I'm new to rails and a bit confused as to what type of associations I need. I checked rails associations but this confused me more. I've tried quite a few things and can't figure out exactly what I need.
I have three models/tables:
Students
Teachers
Groups (as in classes)
I have it setup as:
teacher -> belongs_to :group
student -> belongs_to :group
group -> has_many :students & has_many :teachers
This setup works okay because it allows me to make calls like:
g.students.all
s.group.name
However I would like to be able to make a view page that generates all of the Groups(classes) that a teacher has. Such as: t.groups.all or t.groups.count
One thing that makes my table unique is that a group(class) can have different teachers. I don't know if I need a has_and_belongs_to_many relationship or a has_many :through relationship.
What is the ideal setup for my 3 tables, what table id's and associations are required?

Related

How to order by relationship when the related table has an alias

We have a table called Client and client belongs to a user in two ways, a client can have an updater and has a creator. It also belongs to a company.
belongs_to :creator, class_name: 'User'
belongs_to :updater, class_name: 'User'
I am trying to grab all clients for the current parent object company they belong to and then order them alphabetically by the name of their creator
Here is what I currently have tried
current_company.clients.includes(:creator).order("creator.name #{sort_dir}")
If I put :user in the includes it throws an error that user is not on the table.
Association named 'user' was not found on Client;
This was the closest I was able to get with what I found online.
The easiest way to see how the query looks like is to call .to_sql.
You will see that when the join is performed it uses the table name, users, instead of the relation name, creator.
This should work:
current_company.clients.includes(:creator).order("users.name #{sort_dir}")

Optional relation between two model objects in rails

I have two objects A and B in my Rails model which have an optional one-to-one relationship. Say, A can have 0 or 1 B. In most cases A has 0 Bs.
Also, other such relationships can be introduced between A and other objects X, Y, Z later.
Given that these are one-to-one relations, a has-a relationship between A and B makes sense. But given that it is an optional and infrequent relationship, and also that other such relationships can be introduced later with A, adding a new column for each new relationship seems questionable.
How can I model this relationship better? Should using a correlation table between A and B make better sense in this particular case?
You would add the id of Model A to all the other models, and Model A would has_one for each of them.
Each other would belong_to Model A
I would go with the presented solution, that is adding a new column b_id to A.
Else you could create a third model C which holds both a_id and b_id and then have A access B through C.
# Pluralization is off here. Remember to pluralize has_many
class A < ActiveRecord::Base
has_many :c
has_many :b, through: :c
end
class B < ActiveRecord::Base
has_many :c
has_many :a, through: :c
end
class C < ActiveRecord::Base
belongs_to :a
belongs_to :b
end
This would prevent any null values in the database. This is the solution I use most often when I will build something around the relation, since now you have a place to store more information about the relation.
You could also make C polymorphic so that it can store any model (not only A). http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

How to add link a table to a row

I'm developing a Ruby on Rails application with MySQL and i have a Categories table in my Database.
I want to add sub categories to one of the categories.
i thought of creating a new table for sub categories or just add them to the same Categories table. can anyone help?
As sub_category is nothing but a category with a parent association, you could just store both categories and sub_categories in one table and wire up the association. This type of association is referred as self join association.
Try the following:
class Category < ActiveRecord::Base
has_many :sub_categories, class_name: 'Category', foreign_key: :parent_id
belongs_to :parent, class_name: 'Category'
end
Refer to Self Joins Association for more info.
You need to setup the following migration:
class AddParentIdToCategories < ActiveRecord::Migration
def change
add_column(:categories, :parent_id, :integer)
end
end
And run the migration:
bundle exec rake db:migrate
If you are expecting your tree structure to be more complex, for example, sub_categories having sub_sub_categories and more, then you could take a look at several gems that abstract this feature.
Refer to acts_as_tree, and ancestry fore more info,

Rails activerecord associations

I apologize for a beginner question, but I'm trying to wrap my head around ActiveRecord associations for the project I'm trying to start.
I'm beginning to expand my knowledge in Rails and I'm a bit confused with the available ActiveRecord associations, that is which one should I pick and how to structure the models.
This is the general concept:
You would first define a Company - that is the first part of the tree
Secondly, you need to define the Departments. They should belong to the Company in question, and have a simple name and description.
And finally - Employees - each employee can be in one Department and fall under one Company.
What I'm looking is the best way to create the models for Company, Departments and Employees, so I can assign Employees to the correct Company and Department.
If you could point me to the right direction, book or tutorial/article to ease up these database table joins in my head and pick the right route for the project!
Any help is appreciated!
Seems straight forward.
Your Company model should show the following:
has_many :departments
has_many :employees
One could argue you could change the employees to a "has_many :employees, through: :departments". I don't suspect it matters too greatly.
Your Department model should have:
belongs_to :company
has_many :employees
Your Employee model should have:
belongs_to :company
belongs_to :department
You don't technically need the company line if you use the through departments for that relationship. But if you do this you can then run things like:
Employee.first.company
Employee.first.department
Department.first.business
Department.first.employees.first (notice this is plural as it's has_many)
Company.first.employees.first (will work if you have a through or if you assign it directly)
Company.first.departments.first
A "belongs_to" relationship means the model declaring it holds a foreign key for the model it belongs to. So, Department belongs_to Company. Thus, :company_id is created inside Department when you type, say, rails generate model Department company:references....etc.
In the example above, your Employee will have a :department_id and a :company_id, though, again, you may skip the company one and just declare it as a through and you will look up your employees through the departments they are in.
You could, in theory, also use a has_one instead of a belongs_to for employee. But I find those harder to work with.

How can I delete an entry from a HABTM join table in rails?

Through many iterations of testing, I just noticed that my join table that represents a HABTM relationship between two models isn't removing entries when instances of these models get deleted. Do I need to do something special when removing an instance of a model that has HABTM relationships?
Upon closer inspection HABTM relationships should be removing join table entries. However neither HABTM relationships or the relationship I described in the original version (see post history) of this solution will remove those join table entries when you eliminate the record with the delete method. ActiveRecord::Base#delete does not trigger any callbacks, such as the ones a HABTM relationship establishes to remove orphaned entries from the join table. Instead you should be using ActiveRecord::Base#destroy.
You will have to use raw SQL to remove the unneeded entries. If you decide to create a join model, you can iterate through entries in the join model, deleting those without an association.
Example:
class Foo < ActiveRecord::Base
has_many :foo_bars, :dependent => :destroy
has_many :bars, :through => :foo_bars
end
class FooBar < ActiveRecord::Base
belongs_to :foo
belongs_to :bar
end
class Bar < ActiveRecord::Base
has_many :foo_bars, :dependent => :destroy
has_many :foos, :through => :foo_bars
end
FooBar.all.each{|fb| fb.destroy? if fb.foo.nil? || fb.bar.nil? }
The entries in the join table should be getting deleted without you doing anything special. You can add the :delete_sql option to your code to change the behavior if you have a weird situation. Deleting the object on the other side of the join is not a default behavior.