Rails4 create join tabel no need to add primary key in Migration? - ruby-on-rails

I use this command :
rails g migration CreateJoinTableUserPloy user ploy
And i check the Migration file:
create_join_table :Users, :Posts do |t|
#t.index [:user_id, :ploy_id]
#t.index [:ploy_id, :user_id]
end
There are 2 index is be commented by defualt.
Then i run this command:
rake db:migrate
Then i check my database structure
And i not seen primary key, Does it mean that join tabel no need add index and primary key in database structure?

Consistent with http://meta.serverfault.com/a/1931, I'm going to respond to this as an answer, even though some of the information is in the comment thread.
There is no primary key in a Rails-generated join table (i.e. as created by create_join_table, which is used by migrations with JoinTable in their name) and Rails has no inherent requirement for one. That's because most pure join tables are only accessed by the id's of the joined tables, in which case primary_key is unnecessary. You can, of course, add and designate a primary key column if you wish.
Rails does not support multiple column primary_keys, although there are multiple gems that provide that support, such as https://github.com/composite-primary-keys/composite_primary_keys.
Further, there is no fundamental need to create an index. You can create one if you wish, and it will speed up access to records at the cost of some additional time spent on record creation and update. See https://stackoverflow.com/a/3658980/1008891 for more discussion of this.

Related

What is the proper way of merging multiple postgres schemas into a single schema preserving the foreign key relationships?

We have a SAAS platform written in Rails using the postgres' schema based multitenancy and Apartment gem. The different schemas are identical, with same number of tables and same columns in each table. We want to migrate to foreign key based multitenant system where we want to merge all the records from different schemas into a single schema, identifying each record with a tenant_id. What is the proper way of merging all the records from the different schemas, and preserving the foreign key relationships.
This is a situation that will need care. I think (I could be wrong) that the best approach is to add to all tables tenant_id and original_id ... before attempting migration populate original_id in all tables with id of that record. Essentially this is to have a record of what the value of id was before the merging.
After merge you can then run a rake task that rebuilds the associations. So if you had...
class Foo
has_many :bars
Your migration script would do (after migration)
Bar.all.each do |bar|
foo = Foo.find_by(tenant_id: bar.tenant_id, original_id: bar.foo_id)
bar.update_column(:foo_id, foo.id)
end
You'd need to do something similar for every relation, so it's a bit of a slog.
Hopefully, someone else will come up with a better solution.
NOTE THIS IS NOT IDEMPOTENT. If it errors, you can't restart it except by redoing the merging completely.

Rails Migrations: Foreign key and indexing column fields

I developed a Ruby on Rails 5 application and deployed it to a production environment, after running rake db:migrate I noticed that I wasn't using foreign_key: true and neither index: true for my general relations between tables. Question is: Will this affect database performance and should I generate new migrations just to add indexes and foreign keys references to my columns? Thanks in advance.
From Ruby on Rails guide:
2.2 Schema Conventions
Active Record uses naming conventions for the columns in database tables, depending on the purpose of these columns.
Foreign keys - These fields should be named following the pattern
singularized_table_name_id (e.g., item_id, order_id). These are the
fields that Active Record will look for when you create associations
between your models.
Primary keys - By default, Active Record will use an integer column
named id as the table's primary key. When using Active Record
Migrations to create your tables, this column will be automatically
created.
You must know more about ActiveRecord Look here how it works here
I suggest you to read about belongs_to and has_many relations
Depends on what you are going to do, if you have relations where the foreign key is needed, you will need to create those migrations, otherwise you wont be able to access them.
When it comes to db performance it doesnt matter really

How to create postgres database for Rails app manually?

How can I create postgres db for Rails app properly but in psql, not via rake db:create?
I mean, one can always write CREATE DATABASE project_name, but I don't know what happens in that rake task under the hood. Maybe there are a lot of additional params.
Update
After first answer I decided to clarify: I know how to write and use migrations, they are awesome, but my question not about them. It's about rake db:create task and pg adapter.
In other words, I just want to know which command in psql is equal to rake db:create.
If you select the db on pgadmin III it will show you the sql instructions with the local things to load. They are very importanst if you have full text index on. You must run them from the database postgres.
Rails expects table names to match model names but be plural and snake_case. For example, a User model will store records in a users table and a BlogEntry model will store records in a blog_entries table.
Rails expects a table's primary key to be named id and it expects foreign keys to match model names but be snake_case and end with _id. For example, if BlogEntry belongs_to User, Rails will expect the blog_entries table to have a user_id column.
Join tables (such as used with many-to-many relations) are expected to be named with the two models' names in plural snake case and alphabetical order. For example, a join table describing a many-to-many relation between a User model and a Blog model would be expected to have the name blogs_users and have, at the least, the columns blog_id and user_id.
Those are the basics. Of course, all of this is configurable: For example, you can use the table_name class method to tell a model to use a table with a different name, and the relation methods (belongs_to, has_many, etc.) all take options letting you specify different names.
Apart from these naming conventions Rails doesn't require anything special from a database, as long as the correct credentials and configuration are specified in config/database.yml.

Model/Migration creation order matters in Rails?

I have generated 4 models in rails. Now some of them requires columns for foreign keys from each other.
Suppose I have a table User and other table Post. Now do i need to generate the models in order for ex. User and then Post, so that Posts table could contain user_id column in it?
I am not running rake db:migrate now. What I'm doing is generating models and specifying the columns that might be necessary.
I want to know is, does rake db:migrate takes care of the order automatically and i can create the models in any order? Or as migration files has timestamps attached to it in the file name, it will be processed according to the order of its creation and will give me the error for ex. user_id foreign key dependency, table Users not found?
There are no foreign key dependencies in Rails migrations, so as long as you are not creating dependent data for the models in the migrations, it will work correctly.

When to assign a foreign key and when to just create an association?

I'm learning about model associations in rails. I've learned how to give the table for a model a column to hold foreign keys of another model like so:
rails generate model User account_id:integer
I would then take the primary key of an account from an Account table and assign it to the account_id for the designated user.
However, I am also told to create the association in User.rb like so:
has_one :account
I understand the difference between these two things. One creates a column in the table (the first line after the migration), and the other generates a series of helpers (the latter).
However, what I am seeing in tutorials is that sometimes both are done, while other times, only the association (has_one :account) is done. How do I go about deciding when to create a column in the table to hold foreign keys, and when to just create the association in the model .rb file?
You will always have to create the column in the Database (1)
It is not mandatory to define the relation(s) inside the models, but it is highly recommended (2)
(1) : The Database needs this column of foreign keys to be able to retrieve the corresponding record. Without the column, the DB cannot find back the related record. You can use a Migration to create this column, not only a scaffold.
(2) : You can skip the relations declaration in the models, but it is highly recommended because:
it generate methods corresponding to the relations (ex: User belongs_to :role, then you can do user.role directly instead of Role.where(id: user.role_id).first)
not every human can remember all the associations. It is better to show/list everything that is linked to your model
You asked:
How do I go about deciding when to create a column in the table to hold foreign keys, and when to just create the association in the model .rb file?
I would answer:
Always create the column (cannot work if you don't) AND define every association(s) (relation(s)) inside the model.
Your first example is a scaffold that creates the model file and the migration.
has_one helps ActiveRecord understand the relationships between the tables so that it can, among other things, generate proper SQL queries for you.
But #1 has to be in place for #2 to even work. However, creating the db column via a scaffold command isn't necessary - it's just convenient sometimes, because it creates both the model file, and the associated migration.
You could just write the migration by hand. Just because whatever thing you're following doesn't always mention adding the db column doesn't mean it's not necessary. It's probably just assumed that you've already done it because these foreign key migrations are so common after you get up and running with Rails that they sort of go without saying after a while.

Resources