Why Rails hides the existence of id column? - ruby-on-rails

I don't quite understand the need to hide the existence of id column in Rails.
It is neither reflected in migration file nor the schema.rb file.
There is no way for a newbie to know for the fact that a column named id has been created by default as a primary key.
Unless they go and check the actual schema of the table in database (rails dbconsole).
I can see the timestamps macro included by default in the migration file as well as in schema.rb as two fields created_at and updated_at. Here, a developer at least gets a clue. Rails could have done the same for id column too. But it doesn't.
Why the secrecy around id column? Is it a part of the famous convention over configuration? Or is it a norm across all MVC frameworks?

In database design it is generally accepted that numeric id's are preferred, because
they are easier to index, and thus easier to "follow" or check when creating links (foreign keys).
when editing/updating records, you have a unique (and efficient) identifier
So therefore it is advised to give all tables a unique numeric key, always.
Now this numeric key has no meaning whatsoever to your application, it is a "implementation detail" of your database layer. Also to make sure every table has an id, unless you explicitly ask not to.
I think this would indeed fall under the "convention over configuration" nomer: why explicitly specify an id for each table if you each table should have one.
The timestamps is different: this is interesting for some tables, but for same tables it is not important at all. It also depends on your application.
Note that this is not at all related to MVC. The M in MVC is a container for data, but in MVC it is actually not really important how the Model gets filled. In other words: the ORM part is not part of MVC. You will see that in most MVC implementations there is no ORM, or definitely not as tightly integrated as with Rails.
So in short: imho ommitting the 'id' from the migration is not a secret, it is just to make life easier, saves you some more typing, and it makes sure you follow a good convention unless you explicitly do not want to.

This is probably due to the fact that relational databases tend to use integer primary keys, and doing otherwise introduces complexities. I guess the reason it's hidden in rails is so that creating tables with integer primary keys does not require any special configuration, and having to write it into rails migrations invites inexperienced developers to play around with it (which is probable not a good idea).
Additionally, I think rails tries to abstract away things like numeric ids, if you want to create associations in a migration you do not need to specify foreign keys, you can simply write the name of the object you want to relate the table to.

I never thinked about the id field because almost every table have an id....
Check the documentation about migrations where they say:
A primary key column called id will also be added implicitly, as it's
the default primary key for all Active Record models. The timestamps
macro adds two columns, created_at and updated_at. These special
columns are automatically managed by Active Record if they exist.
If you want to check your table columns, just go to rails console and type Model.column_names

I think it's clear that if you don't add a primary key, then rails will add one generic key for you so that it can index your record and have a control over it, so basically it isn't stating that there WILL be an ID field, since I don't believe this has to be imperative, but rather optional in the event you do not provide a primary key.

It's a Rails convention to hide the I'd attribute to discourage and remove temptation of playing with it.
id attr is automatically generated with auto_increment to ad normalization to your data(to make each record unique an accessible). Injecting your own values would eventually corrupt and break the magic of ActiveRecord.

Related

Rails: Foreign Keys and when to index

Three questions:
When you create a model, is a foreign_key automatically created as well?
I'm thinking I should add_index when a column is unique to the table or unique in general, or when the column will relate to other databases, Amirite?
What will an index look like? Will it just use the contents of the cell?
1) Do you mean when using a generator? Generally speaking, you should generate migrations, rather than use a generator for the whole model/scaffolding. And then, no, a foreign key is not automatically created, only if you specify it.
2) add_index is going to come in handy for columns on big tables that need to be accessed quickly by your database. Let's say you've got a users table with an email column that must be unique, but isn't indexed. And your service grows, now you have millions of users, and you need to go User.find_by_email "someone#example.com". Without an index, that's going to take you a while. With an index, it'll be quick. That's when an index comes in handy.
3) Really depends on your database engine afaik. Not something that will affect your day-to-day imho (though if you have a specific database engine in mind, you can certainly find out). Here's the info on MySQL, straight from the source: https://dev.mysql.com/doc/refman/5.5/en/column-indexes.html

Can I add an identity column (non-PK) to table for use in application?

I am building a db in sql server, then I will build the web app. The data has some pretty good natural key columns that I will use as the PKs. However, several of them are composite keys, which will be a bit unwieldy in the application side.
For example, a golf course can have 1, 2, or 3 courses at one location. The location has a number (32201) and each course has a name (bayou front, bayou back, bayou exec) so I would make a composite key from the number and name.
However, in the application (asp mvc) the internal routing allows for passing a single integer id from controller to view, etc for use in identifying stuff. So I am thinking of adding an non-key identity column to the Golf Course table, and others like it, so I can us the identity filed in the app. So someone can select the bayou back course on the index page of the app, and I would pass the non-key identity id number to the controller to select the details for the course from the DB and pass them to the view.
It seems at first, like I would be bypassing the purpose of the primary key by using this non-key integer, but the PK would come into play for things like referential integrity when doing updates, inserts, etc.
Thoughts?
What you're talking about sounds like a surrogate key (as opposed to a natural key). There are pros and cons to using each, and both approaches have been discussed before, rather extensively, I think.
From the answer here: go ahead and use both. They are both tools, and each one should be used when it is the best tool for the job.
The only thing I'd add for your situation is that, since your tables would have both a surrogate and natural key on the same table, make sure that one (natural key or surrogate key) is the actual PK and that the other has a unique key or index on it. That way, either one can be used to uniquely identify rows in your tables.

If we need to use a custom ID in Rails, should we use FriendlyID or Primary Key?

I need to create a product code which will be generated with a custom function. It will start with a letter, have the id of the category and then have a random 7 digit number. For this, I can set the primary_key to a string and generate the code or I can use FriendlyID. What might be the best for this situation?
Short answer: Use something like friendly_id
The story now:
Choosing a natural key for the primary_key of a table should always be measured well, it has an impact on your data model.
The first issue is regarding related records in other tables. If you will have related tables, the foreign key in those tables should also be VARCHAR and match your generated primary key. If you are not sure what to do, avoid custom primary keys.
Another issue in your question may be:
It will start with a letter, have the id of the category
Is this id the primary key of a Category model? If it's the case, you are generating a key with DB isolation in mind, but re-tighting with this one. Think again for this one.
Go for a slug generated by your function, you will be free for the future. You may create a brand new algorithm and thus only do a once for all change of the slugs. You may even have 2 slugs, the old one which redirects to the new one, and the new one.

Does ActiveRecord assign a key to every table using the naming convention "ID", and if so, why?

My understanding is that Actice Record is based on a object-relational mapping (ORM) pattern described by Martin Fowler in his book Pattern of Enterprise Application Architecture (Addison-Wesley, 2002); which states a one-to-one mapping relationship exists between a database record and the object that represents it in an object-oriented program (OOP). When Rails creator David Heinemeier sought to implement an ORM for his Rails framework, he based it on Fowler's pattern.
Here's the problem, does ActiveRecord assign a surrogate primary key to every table using the naming convention "ID", and if so, why? Reason I ask is that it appears it'd make more sense to assign a a surrogate primary key using the naming convention "tablename_ID"; as in fact it appears ActiveRecord does when creating foreign keys. Further, is it possible to override the default config, and assign a surrogate primary key using the naming convention "tablename_ID"; reason being that especially in the case of primary keys, it appears to be a good idea not to use a shared name, since telling the difference between two columns ID's is not possible if simply looking at the column namesing: ID, ID, ID. As a use case example of where this appears there would be a problem, if I export data to a single table from two tables, there will be two columns with the ID name; when I import that document with updates, it would appear that there's no way to map the ID columns by default.
It's already obvious to see what the ID is, because it is in a certain table. You don't have table_name.table_name_id but table_name.id. I like the distinction between foreign keys and primary keys this way, but admittedly, it's a matter of opinion.
Unless you have a really good reason to use anything other, you should stick to the convention. That's what conventions are for. ActiveRecord gives you the option to change it, like so:
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
This sets the way primary keys are generated globally. products.id becomes products.product_id.

Thinking Sphinx - Foreign key with different type - Association problem

I have two tables on mysql: users, and management. The users table has a numeric id, and the management table has a varchar foreign key which is the primary key of the other table. The types are not the same, and this seems to be the main problem when I build an index from the User model, and try to include one column from the management table. The join that thinkinx sphinx generates takes too much damn time to execute, and thus the index never gets done.
I know the best solution is to change the management table and use a numeric id, but right now that seems to be too expensive. Is there a way to just tell thinking sphinx that the varchar field is in fact a numeric id, so the index could be generated without altering the tables?
If this is not clear, please ask me to clarify whatever seems too obscure.
Thanks!
I'd make sure you have a database index on your foreign key.
Also, if you want to edit the generated configuration, you can do so, and then process the index using one of the two options, which doesn't automatically regenerate the file:
rake ts:index INDEX_ONLY=true
rake ts:reindex # this was only added the other day

Resources