Ruby On Rails custom ID - ruby-on-rails

Hi I want to have custom ids for a table and not use the default auto_increment. Is that possible? I have turned :id => false and later on I create a t.column :id, :bigint
But when I create a new record the id is set to NULL
Is there anyway to bypass this behaviour.
I could set my primary key to a field uid (it is actually facebook id) but usually it breaks for me as relations usually look for the id field

It's almost certainly going to be easier to use Rails' surrogate autoincrement ID as your primary ID.
There's no problem having a second unique column facebook_id and performing all your searches based on that field, but for the compatability reasons you mention (i.e. plugin authors making assumptions they shouldn't) I'd stick with Rails defaults as much as sensible. The performance issues relating to primary keys vs unique keys are minimal

I don't know where the problem is. Of course id is NULL when you disable auto_increment for the id column and don't insert an id value by hand.
Btw: You can define the foreign and primary keys for relations. It is no problem to use facebook_id as primary key.

Related

SQLite: Should I use Integer primary key or Integer when storing data from API?

I've inherited an iOS project that stores record ids in a column using the data type Integer primary key. This works well, however, I'm not sure why it isn't just using regular Integer. The iOS App grabs records from an API and stores it in the local SQLite database. These records from the API each have a unique id already (e.g. id:100101394).
Is there a reason or an advantage in using Integer primary key over regular integer in this situation?
Edit: The app uses the record's unique id for the Integer primary key if that makes sense, but I don't know why I can't just use a regular integer.
Edit 1: Everyone, I understand I can use a primary key to access records. What I want to understand is if there is a reason why I should use it over a regular Integer that I can store the record's id in. Each record id the API returns is unique.
Integer Primary Key is typed, you can only put in an integer. It also will guarantee an integer is inserted when null is put in. I believe it can also act as an alias as RowID If that exists for the table.
Here is a link to the documentation on it.
https://sqlite.org/lang_createtable.html#rowid
I believe you use a key when you expect to want to find the record by that identifier. I would expect that to impose additional overhead when storing the item, but if you want to access a record by the 'integer primary key' id, you can potentially save a lot of time and system overhead.

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.

Postgresql depend on record id

I am working on an application design, using Ruby on Rails and Postgresql. I have a table with the following fields
Table: account_type
Fields: id(primary key), name(String)
AccountType name is unique string (so am thinking about putting unique constraints on it). Depending on the name (type) I'm going to make some checks in my Models. Something like that:
def urban?
self.name == 'Some long type'
end
The question is: do I leave it like that? Or, as the other option, I can depend on some ID. So, assuming that my 'Some long type' is always created with ID=1, I can check for
def urban?
self.id == 1
end
Is it a good practice if I do depend on the ID? What about readability? Are there other solutions to that problem?
The second example is a text-book case of how NOT to use surrogate keys
Your real primary key is account_type and should have a unique key. There is always endless debate about the 'goodness' of using auto-inc id columns for primary keys. To query by id depends on how the rows have been inserted. Querying by account_type.name is immutable.
Readability? the id field gives no information to what the record really means.
Other Solutions? I don't really see what problem is, but you could also use an enum type (but it is much less flexible than a lookup table.)

Why Rails hides the existence of id column?

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.

Why is it not good to have a primary key on a join table?

I was watching a screencast where the author said it is not good to have a primary key on a join table but didn't explain why.
The join table in the example had two columns defined in a Rails migration and the author added an index to each of the columns but no primary key.
Why is it not good to have a primary key in this example?
create_table :categories_posts, :id => false do |t|
t.column :category_id, :integer, :null => false
t.column :post_id, :integer, :null => false
end
add_index :categories_posts, :category_id
add_index :categories_posts, :post_id
EDIT: As I mentioned to Cletus, I can understand the potential usefulness of an auto number field as a primary key even for a join table. However in the example I listed above, the author explicitly avoids creating an auto number field with the syntax ":id => false" in the "create table" statement. Normally Rails would automatically add an auto-number id field to a table created in a migration like this and this would become the primary key. But for this join table, the author specifically prevented it. I wasn't sure why he decided to follow this approach.
Some notes:
The combination of category_id and post_id is unique in of itself, so an additional ID column is redundant and wasteful
The phrase "not good to have a primary key" is incorrect in the screencast. You still have a Primary Key -- it is just made up of the two columns (e.g. CREATE TABLE foo( cid, pid, PRIMARY KEY( cid, pid ) ). For people who are used to tacking on ID values everywhere this may seem odd but in relational theory it is quite correct and natural; the screencast author would better have said it is "not good to have an implicit integer attribute called 'ID' as the primary key".
It is redundant to have the extra column because you will place a unique index on the combination of category_id and post_id anyway to ensure no duplicate rows are inserted
Finally, although common nomenclature is to call it a "composite key" this is also redundant. The term "key" in relational theory is actually the set of zero or more attributes that uniquely identify the row, so it is fine to say that the primary key is category_id, post_id
Place the MOST SELECTIVE column FIRST in the primary key declaration. A discussion of the construction of b(+/*) trees is out of the scope of this answer ( for some lower-level discussion see: http://www.akadia.com/services/ora_index_selectivity.html ) but in your case, you'd probably want it on post_id, category_id since post_id will show up less often in the table and thus make the index more useful. Of course, since the table is so small and the index will be, essentially, the data rows, this is not very important. It would be in broader cases where the table is wider.
It is a bad idea not to have a primary key on any table, period (if the DBMS is a relational DBMS - or an SQL DBMS). Primary keys are a crucial part of the integrity of your database.
I suppose if you don't mind your database being inaccurate and providing incorrect answers every so often, then you could do without...but most people want accurate answers from their DBMS and for such people, primary keys are crucial.
A DBA would tell you that the primary key in this case is actually the combination of the two FK columns. Since Rails/ActiveRecord doesn't play nice with composite PKs (by default, at least), that may be the reason.
The combination of foreign keys can be a primary key (called a composite primary key). Personally I favour using a technical primary key instead of that (auto number field, sequence, etc). Why? Well, it makes it much easier to identify the record, which you may need to do if you're going to delete it.
Think about it: if you're going to present a Webpage of all the linkages, having a primary key to identify the record makes it much easier.
Basically because there's no need for it. The combination of the two foreign key field adequately uniquely identifies any row.
But that merely says why it's not a Good Idea.... but why would it be a Bad Idea?
Consider the overhead adding a identity column would add. The table would take up 50% more disk space. Worse is the index situation. With a identity field, you have to maintain the identity count, plus a second index. You'll be tripling the disk space and tripling the work the needs to be performed on every insert. With the only advantage being a slightly shorter WHERE clause in a DELETE command.
On the other hand, If the composite key fields are the entire table, then the index can be the table.
Placing the most selective column first should only be relevant in the INDEX declaration. In the KEY declaration, it should not matter (because, as has been correctly pointed out, the KEY is a SET, and inside a set, order doesn't matter - the set {a1,a2} is the same set as {a2,a1}).
If a DBMS product is such that ordering of attributes inside a KEY declaration makes a difference, then that DBMS product is guilty of not properly distinguishing between the logical design of a database (the part where you do the KEY declaration) and the physical design of the database (the part where you do the INDEX declaration).
I wanted to comment on the following comment : "It is not correct to say zero or more".
I wanted to remark that the text to which this comment was added simply did not contain the text "zero or more", so the author of the comment I wanted to comment on was criticizing someone else for something that hadn't been said.
I also wanted to comment that it is not correct to say that it is not correct say "zero or more". Relational theory as commonly known today among the few people who still bother to study the details of that theory, actually REQUIRES the possibility of a key with no attributes.
But when I pressed the button "comment", the system responded to me that commenting requires a reputation score of 50 (or some such).
A sad illustration of how the world seems to have forgotten that science is not democracy, and that in science, the truth is not determined by whoever happens to be the majority, nor by whoever happens to have "enough reputation".
Pros of having a single PK
Uniquely identifies a row with a single value
Makes it easy to reference the relationship from elsewhere if needed
Some tools want you to have a single integer value pk
Cons of having a single PK
Uses more disk space
Need 3 indexes rather than 1
Without a unique constraint you could end up with multiple rows for the same relationship
Notes
You need to define a unique constraint if you want to avoid duplicates
In my opinion don't use the single pk if you're table is going to be huge, otherwise trade off some disk space for the convenience. Yes it's wasteful, but who cares about a few MB on disk in real world applications.

Resources