Ruby on Rails Migration with Primary and Foreign Key - sql

I am just starting ROR and making different tables for the SQLite database and am running into some trouble in relation to automatically generated id's of tables and foreign keys. To create my tables I used the "rails generate scaffold" command followed by the attributes that I needed. I went to the db/migrate directory and looked at what I had just defined. But I don't understand how I am supposed to explicitly reference foreign keys. I'm used to using Oracle so I'd normally do this process in the very first step during creation and be done with it already.
For example, I have a users table with some general attributes such as a username, password, etc. I also have an orders table with attributes transactionID (auto generated), userID (I want to this to be an FK), PartNo (FK key from the Products table). What I don't understand is how to use the auto generated key from the Users table and include it as a foreign key in the Orders table.
Also, I read somewhere else that if I put a line of code such as
t.integer user_id
in my create_orders.rb file then it would automatically know that this is a foreign key!?
I feel like this is probably really easy and I'm missing something. This is my first time using rails and I thought I got to define the foreign keys straight away via SQL. Any help would be greatly appreciated. If I could figure this out it would save me a lot of time.

After you do this, on your Order model, you'd use a belongs_to :user to generate the relationship and utilize the foreign key.
If you want to be able to go from User to Order, you'll likely be a one-to-many, so you'd have to do has_many :orders on User.
Here is the documentation for associations in Rails. And here is the specific documentation for belongs_to vs has_one.

Related

Ruby Foreign Key Constraints in Database vs Model

I have the following models in a Rails app. This setup has worked fine since normally when I would like to add a new VendorPromo to a vendor, there's a dropdown in the view of available Promos to choose from. Now, I'm enabling the creation of new VendorPromos via an API. However, this current set up will allow the creation of a VendorPromo with any promo_id, even if it doesn't exist in Promo. I've seen the belongs_to :promo, foreign_key: :promo, and I know you can add a foreign key constraint via the DB as well. What I'd like to know is the difference between these two approaches and if one is better?
Edit: I recognize that application constraints are different than DB constraints, but when I apply the constraint in the app, i.e. the belongs_to :promo, foreign_key: :promo it doesn't actually seem to enforce the constraint at all. Specifically, I can create a new VendorPromo with a promo_id of, say, 13, even though Promo only has IDs between 1 and 8.
class Vendor
has_many :vendor_promos
end
class VendorPromo
belongs_to :vendor
belongs_to :promo
end
class Promo
end
The foreign_key attribute in the belongs_to method is not actually defining a foreign key, it's specifying for rails's internals which field holds the foreign key.
The Ruby on Rails Guide warns you about it here: https://guides.rubyonrails.org/association_basics.html#options-for-has-many-foreign-key
In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations.
Juan Carlos's answer was part of the way there. It's true that the foreign_key attribute in belongs_to does not enforce any database or application level foreign key. What I was looking for was the belongs_to :promo, optional: false flag does in fact enforces an application level foreign key. That flag, in addition to a DB level foreign key constraint resolved my issue.

rails3 and the proper way to use associations

I'm doing my first rails(3) application.
Associations don't make sense. First, even the rails guides don't
really explain what they do, they just explain how to use them.
From what I gather, associations do two things:
a) Allow ActiveRecord to optimize the structure of the database.
b) Allow ActiveRecord to offer an alternate ruby syntax for
joins and the like (SQL queries). I want this.
I'm trying to understand associations, and how to properly use them. Based
on the example below, it seems like associations are 'broken' or at least
the documentation is.
Consider a trivial version of my application. A teacher modifying wordlists
for study.
There are 3 relevant tables for this discussion. For clarity, I've simply
included the annotate(1) tool's definition of the table, and removed
unnecessary fields/columns.
A wordlist management table:
Table name: wordlist_mgmnt_records
id :integer not null, primary key
byline_id :integer(8) not null
A table that maps words to a word list:
Table name: wordlists
wordlist_mgmnt_id :integer not null
word_id :integer not null
We don't actually care about the words themselves. But we do care about
the last table, the bylines:
Table name: bylines
id :integer(8) not null, primary key
teacher_id :integer not null
comment :text not null
Bylines record who, what tool was used, where, when, etc. Bylines are
mainly used to trouble shoot what happened so I can explain to users what
they should have done (and/or repair their mistakes).
A teacher may modify one or more word list management records at a time
(aka single byline). Said another way, a single change may update multiple
word lists.
For wordlist_mgmnt_records the associations would be:
has_many :bylines # the same byline id can exist
# in many wordlist_mgmnt_records
But what's the corresponding entry for bylines?
The Beginning Rails 3 (Carneiro, et al) book says:
"Note: For has_one and has_many associations, adding a belongs_to
on the other side of the association is always recommended. The
rule of thumb is that the belongs_to declaration always goes in
the class with the foreign key."
[ Yes, I've also looked at the online rails guide(s) for this. Didn't
help. ]
For the bylines table/class do I really want to say?
belongs_to :wordlist_mgmnt_records
That really doesn't make sense. the bylines table basically belongs_to
every table in the data base with a bylines_id. So would I really say
belongs_to all of them? Wouldn't that set up foreign keys in all of the
other tables? That in turn would make changes more expensive (too many
CPU cycles) than I really want. Some changes hit lots of tables, some of
them very large. I prize speed in normal use, and am willing to wait to
find bylines without foreign keys when using bylines for cleanup/repair.
Which brings us full circle. What are associations really doing in rails,
and how does one use them intelligently?
Just using associations because you can doesn't seem to be the right
answer, but how do you get the added join syntax otherwise?
I'll try to help your confusion....
A byline can have multiple wordlist_mgmnt_records, so defining the has_many there seems to make sense.
I'm not sure I understand your confusion in the other direction. Since you have defined the attribute wordlist_mgmnt_records.byline_id, any given wordlist_mgmnt_record can only 'have' (belong_to) a single byline. You're simply defining the crows foot via ruby (if you like database diagrams):
wordlist_msgmnt_records (many)>>----------(one) byline
Or read in english: "One byline can have many wordlist_mgmnts, and many individual wordlist_mgmnt's can belong to a single byline"
Adding the belongs_to definition to the wordlist_mgmnt model doesn't affect the performance of the queries, it just let's you do things like:
#record = WordlistMgmntRecord.find(8)
#record_byline = #record.byline
Additionally you're able to do joins on tables like:
#records = WordlistMgmntRecord.joins(:byline).where({:byline => {:teacher_id => current_user.id}})
Which will execute this SQL:
SELECT wordlist_mgmnt_records.*
FROM wordlist_mgmnt_records
INNER JOIN bylines
ON wordlist_mgmnt_records.byline_id = bylines.id
WHERE bylines.teacher_id = 25
(Assuming current_user.id returned 25)
This is based off of your current DB design. If you find that there's a way you can implement the functionality you want without having byline_id as a foreign key in the wordlist_mgmnt_records table then you would modify your models to accomodate it. However this seems to be how a normalized database should look, and I'm not really sure what other way you would do it.

NHibernate - how to configure associations not to use primary key

I'm working with a legacy database put together by some very strange people. I'm writing an NHibernate DAL over the top of it but running into some odd mapping scenarios.
In one example, I have a table with a number of fields including LE_RECNUM (integer primary key) and LE_CODE (string).
However, all relationships throughout the database join onto LE_CODE, not LE_RECNUM, for some unfathomable reason.
I need to specify that LE_RECNUM is the Id in my mapping file, because I need the primary key to be generated when I insert records. However, I want all associations to use LE_CODE instead of LE_RECNUM.
Can anyone suggest how I might do this?
References(x => x.SomeProperty).Column("LE_CODE").PropertyRef(x => x.SomePropertyInParent);

Moving from a one-to-one relationship into a many-to-many relationship in rails

Like the title says, I want to move from a one-to-one relationship into a many-to-many relationship in my rails 3 app.
I'm fairly good with rails now but I lack a good understanding of databases and migrations.
Currently, I have a Project and User model. A Project belongs_to a User and a User has_many Projects.
I want to move into a situation where a project can have many users collaborating on it at once.
I'm pretty sure I need to set up a has_many :through type of relationship, but I am also curious as to how I can migrate all of my existing projects and users into this type of system.
Thanks!
You need another table that links the two tables together. This is how to support many to many relationships.
e.g. Say you have two tables like this:
Projects
----------
projectid
{other columns}
Users
-------
userid
{other columns}
The new table will look something like this:
New Table
Projects_Users
--------------
projectid
userid
Now you can add another user to a project by simply adding the userid and projectid to
the Projects_Users table. Similarly you will be able to add several users to the one project in the same table.
The primary key on that table is the composite key projectid & userid.
Right, I have the relationship set up now. How do I migrate all of my existing projects and users into this new format table ?
Well, it depends on how you have set the tables up now; how the two existing relations are implemented; where the ProjectUser data is sitting in the old table. Post your DDL. You should be able to simply INSERT ProjectUser SELECT FROM .... We need to complete that FROM.
Also the number of rows is relevant; if it is large, you may have to break it into batches.

NHibernate SchemaUpdate adding existing foreign keys again?

I'm using SchemaUpdate to synchronize my hbms with existing database. Database has recently created based on hbms and is completely up-to-date. But SchemaUpdate generates all foreign key constraints again.
For example suppose you have Student and Teacher. Student has association to Teacher with name ArtTeacher. ArtTeacher is a foreign key from Student to Teacher. Suppose database is up-to-date and currently holde Student, Teacher and their foreign key relation. So HBM and Database are equivalent. Know SchemaUpdate must not do anything but when I see its generated scripts, it re-produce that foreign key again.
Why this happens? Is there any way to avoid it?
The secret is to ensure that you specify names for the foreign keys, or else NHibernate will generate a random name which won't match the existing schema.
(I fished this answer out of the Google Cache of Afshar's blog post).