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
Related
Using Ecto v2.2.6, Phoenix 1.3
I have a table of people (who happen to be related to each other), and another table of relations for those people. The relations table lists the id of the parent in one column, and the id of the child in another.
mix phx.gen.json Accounts Person persons name:string age:integer
mix phx.gen.json Accounts Relationship relationships parent_id:references:persons child_id:references:persons
Now, I am about to add belongs_to relationships in the relationships schema (which currently looks like this)
schema "relationships" do
field :parent_id, :id
field :child_id, :id
timestamps()
end
But without the ability to set the id explicitly, it would looks like this (which doesn't seem to work)
schema "relationships" do
belongs_to :person UserRelations.Accounts.Person
belongs_to :person UserRelations.Accounts.Person
timestamps()
end
How can I write the relationships schema so that I capture these belongs_to relationships?
Edit
I have set the schema up like this, as per suggestion:
schema "relationships" do
belongs_to :parent UserRelations.Accounts.Person
belongs_to :child UserRelations.Accounts.Person
timestamps()
end
I have tried to do something similar with the Person schema as well:
schema "persons" do
field :age, :integer
field :name, :string
many_to_many :parent_of, UserRelations.Accounts.Person, join_through: "relationships"
many_to_many :child_of, UserRelations.Accounts.Person, join_through: "relationships"
timestamps()
end
However, when I try to access these relationships (I am doing this through an absinthe/graphql schema), I see that it is looking for a person_id somewhere:
[error] Task #PID<0.400.0> started from #PID<0.395.0> terminating
** (Postgrex.Error) ERROR 42703 (undefined_column): column f2.person_id does not exist
The name of the two belongs_to relationships need to be different. For example:
belongs_to :child, UserRelations.Accounts.Person
belongs_to :parent, UserRelations.Accounts.Person
With these names, Ecto will infer the foreign key correctly: child_id and parent_id.
For the many_to_many, you need to provide join_keys to both as Ecto can't infer it from the name of the relationship and the schema module.
For the first one, you need to add:
, join_keys: [parent_id: :id, child_id: :id]
And for the second one:
, join_keys: [child_id: :id, parent_id: :id]
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,
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.
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?
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.