one-to-one or one-to-many association - ruby-on-rails

I am creating a stock control application.
I have a table called "equipment_type" that stores a general
description of a piece of equipment. This could be for instance: Canon
60D DSLR camera.
I also have an table called "equipment" that stores all the equipment
we have with their serial numbers. There may be many Canon 60Ds and
they should refer to the "equipment_type" table for their description.
Is this a one-to-one association, because they have only one
description.
Or is this a one-to-many, because one "equipment_type" is related to
many "equipment"
Thanks for your help

It's a one-to-many relationship. That is one equipment_type for many equipment. In rails this would be defined:
class Equipment
belongs_to :equipment_type
end
class EquipmentType
has_many :equipment
end
Note: Rails should recognize that equipment is both singular and plural, so using something like equipments is incorrect. You can test this in the console using "equipment".pluralize and "equipment".singularize.

Related

Create join table using migrations or models?

As a Ruby on Rails newbie, I'm going through the Rails Guides and tonight is Active Record Migrations.
After finishing the section on Join Tables (http://guides.rubyonrails.org/active_record_migrations.html#creating-a-join-table), I'm left with the impression that using create_join_table is preferred (and simpler) than creating the Join Table via rails generate model.
Is this a correct assumption? Are there nuances I should be aware of?
Using the example in the guides of categories and products:
A join table works transparently. You only work with the two existing models (Category and Product), and the join table exists only to enable the HABTM relationship between them, so you can call category.products, or product.categories, and things just work.
Generating a model, on the other hand, would only be necessary if you need to work with that association as a distinct thing in your application (e.g. if you need to do things with a Categorization directly).
Contrast the Rails Guides description of a has_and_belongs_to_many association (read more):
A has_and_belongs_to_many association creates a direct many-to-many
connection with another model, with no intervening model. For example,
if your application includes assemblies and parts, with each assembly
having many parts and each part appearing in many assemblies, you
could declare the models this way:
with that of a has_many :through association (read more):
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. For example, consider a medical practice where patients make
appointments to see physicians. The relevant association declarations
could look like this:
So, yes, you're correct that create_join_table would be simpler than creating a model for the association. You can also see this answer for another explanation of the difference between these approaches.
As the docs mention...
Migration method create_join_table creates a HABTM join table
--
When you create a has_and_belongs_to_many relationship, you only need a join table (no model).
has_and_belongs_to_many join tables are different from has_many :through as they don't have an id (primary_key); has_many :through are meant to represent an interim model, so each "record" should have a unique identifier.
Thus, your question about whether it's better to create a join table through rails g model is false. has_and_belongs_to_many has no binding model. If you were using has_many :through, you'd be able to use the rails g model no problem.

Single Table Inheritance Alternative

I'm trying to think in a business model very similar to the one described here, using STI.
class Person < ActiveRecord::Base
# identified by email
end
class Owner < Person
end
class Customer < Person
end
class Employee < Person
end
class Store < ActiveRecord::Base
belongs_to :owner
has_many :customers
has_many :employees
end
The classes above describe what I intend to do. The problem here is that a Employee can never act as a Customer, and hire the services provided by the store he works, or even another store, unless a new record is created to represent the same person acting as the a different role in a different context. That is not very DRY, but I don't know if there is a better solution.
Is there? Anyone has any suggestion on how I could resolve this issue?
Thank you very much.
Being an owner (note that there may be several for a given store and one person may own several stores) is not part of a person's identity, it is a relationship between a person and store so subclassing isn't really appropriate here. Similarly for being a customer or employee.
This leaves us with five components:
People.
Stores.
The "person owns a store" relationship.
The "person is a customer of a store" relationship.
The "person is an employee of a store" relationship.
All three relationships are, realistically, many-to-many. Also note that there's STI anywhere in sight; this is a good thing, STI is almost always (IMO) a mistake so you should start questioning your data model and your judgement as soon as it shows up. STI does have its place of course but you should think hard to justify it whenever it comes up.
This leaves us with two fairly simple models (Person and Store) and three many-to-many relationships between people and stores. The standard ways of modelling many-to-many relationships with ActiveRecord are has_many ... :through and has_and_belongs_to_many. If you need to work with one of the person-store relationships as a separate entity (such as an employee with an employee number, hourly rate, tax records, ...) then you'd probably want has_many :through; if you only need the association then has_and_belongs_to_many would probably work.
Some references:
The has_many :through Association
The has_and_belongs_to_many Association
Choosing Between has_many :through and has_and_belongs_to_many
Actually, it is DRY from a code perspective. I actually work on a very similar project using STI where we have users, managers, and administrators, and there must be three records for each in the database. This is DRY from a Rails perspective because each of those records has their own unique attributes, methods in their own classes, etc. but share common code from a similar model to what you call Person. I actually think this is a good way to do it if you're using STI.
An alternative would be to have common code in a module which you could include in each of Customer, Employee, and Owner.
Another alternative (most likely what I would do if starting from scratch) would be to have a single Person table and use roles, using cancan and maybe even rolify. This way you have one class you're dealing with called Person where an instance of Person can have one or many roles, such as customer, employee, or owner.

Rails - one model that many others can use?

Running Rails 3.2.8 with SQLite (basic setup from current dl on rubyonrails.org)
If i have several models that I want to have an attribute of "notes" and all "notes" are String, should there only be one specific Note model, with all the other models referencing the Note model?
or
Does each model has to have its own attribute for "notes"?
If the first response, does that mean that for each relationship that references the "notes", do I need to create another class that defines that :through relationship? (ie tableOne, tableTwo, and tableThree all reference notes, then I would need to create additional classes tableOne_notes, tableTwo_notes, and tableThree_notes)
Is a polymorphic solution applicable?
If you want one 'notes' model that can serve the same purpose for many other models this would be a polymorphic relationship.
This is actually true regardless of the application framework.
In the specific case of rails implementation of polymorphic relationships for this example you would add a
note_type
column in the notes model/table and in the Note model, using database migrations plus:
belongs_to :notable, :polymorphic => true
in Note and then
has_many notes, :as => notable`
in the other models that need the notes.
See http://guides.rubyonrails.org/association_basics.html#polymorphic-associations for more.
Frequent uses for Polymorphic relationships:
notes (as you are using)
update information (timestamp, ip address, user-agent, etc)
categories that are simple key-value lookups
It depends on your needs. But basically it is possible to create a model Notice and create a 1-n relation between Notice and Other and Other2...
As I understand your question only a 1-n or multiple 1-n relationships make sense. If you add to every table a column notes, it could only be one note for each data-line. Another class which defines :through is not necessary by a 1-n relation.

Look up table, enum or a function to return value from key in Rails

I have two models, Tutor and Student. Tutor can have multiple Topics he can cover, and Student can have multiple Topics he would like to learn. There are 10 possible topics (in string).
I am thinking of creating a Topic table, which contain topic strings. But it would create unnecessary repetition of these strings (making table heavy). So I create a Topic table which contains only topic key.
However, I am undecided about how to retrieve value:
First, I can create another lookup table, which maps a key to string value. This will result in an extra merging step.
Second, I can have a class function that belongs to Topic, that returns string from value.
Which way would be more efficient in my situation? Is there a better approach that I haven't thought of?
Thank you.
It depends. IMO "topics" sounds like something that need managing, and may change.
If that's the case, there should be a topic table, with an id, name, probably a description, etc. Both tutors and students would have_many topics :through a join table. Topics would belong_to both.
There are several implementations options, including a polymorphic association of topics.
Assuming a Tutor model could be rolled into a User model with role assignments, setup a has_and_belongs_to_many relationship between Users and Topics. This sets up a join table where the foreign keys are listed to join the heavier rows together.
class User < ActiveRecord::Base
has_and_belongs_to_many :topics
end
class Topic < ActiveRecord::Base
has_and_belongs_to_many :users
end
See the Rails Guide for additional description.
The alternative is to use just a has_many association but it lacks a join table so the Topic entries will need to be duplicated for each instance.

Confusion over the tables for has_one and has_many

In the Rails ActiveRecord Associations guide, I'm confused over why the tables for has_one and has_many are identical:
Example tables for has_many:
customers(id,name)
orders(id,customer_id,order_date)
Example tables for has_one:
these tables will, at the database level, also allow a supplier to have many accounts, but we just want one account per supplier
suppliers(id,name)
accounts(id,supplier_id,account_number) #Foreign Key to supplier here??
Shouldn't the tables for has_one be like this instead:
suppliers(id,name,account_id) #Foreign Key to account here
accounts(id,account_number)
Now because the account_id is in the suppliers table, a supplier can never have more than one account.
Is the example in the Rails Guide incorrect?
Or, does Rails use the has_many kind of approach but restricts the many part from happening?
If you think about this way -- they are all the same:
1 customer can have many orders, so each order record points back to customer.
1 supplier can have one account, and it is a special case of "has many", so it equally works with account pointing back to supplier.
and it is the same case with many-to-many, with junction table pointing back to the individual records... (if a student can take many classes, and one class can have many students, then the enrollment table points back to the student and class records).
as to why account points back to supplier vs account points to supplier, that one I am not entirely sure whether we can have it either way, or one form is better than the other.
I believe it has to do with the constraints. With has_one rails will try to enforce that there is only one account per supplier. However, with a has_many, there will be no constraint enforced, so a supplier with has_many would be allowed to exist with multiple accounts.
It does take some getting used to when thinking about the relationships and their creation in rails. If you want to enforce foreign keys on the database side (since rails doesn't do this outside of the application layer), take a look at Mathew Higgins' foreigner
If I understand your question correctly, you believe there is a 1:1 relationship bi-directionally in a has_one/belongs_to relationship. That's not exactly true. You could have:
Class Account
belongs_to :supplier
belongs_to :wholesaler
belongs_to :shipper
# ...
end
account = supplier.account # Get supplier's account
wholesaler = Wholesaler.new
wholesaler.accounts << account # Tell wholesaler this is one of their suppliers
wholesaler.save
I'm not saying your app actually behaves this way, but you can see how a table -- no, let's say a model -- that "belongs to" another model is not precluded from belonging to any number of models. Right? So the relationship is really infinity:1.
I should add that has_one is really a degenerate case of has_many and just adds syntactic sugar of singularizing the association and a few other nits. Otherwise, it's pretty much the same thing and it's pretty much why they look alike.

Resources