How to write foreign keys in many-to-many rich join? - ruby-on-rails

I am trying to create many-to-many rich join between AdminUser and Section with join table as SectionEdit. That is created by generating model. Inside create_section_edits, we write
create_table :section_edits do |t|
t.integer :admin_user_id
t.integer :section_id
t.timestamps
t.string :summary
end
Is there any difference in between using :admin_user_id and "admin_user_id"? Same goes for the other primary keys. admin_user_id is foreign key.

No, but it is better practice to use the symbol :admin_user_id
As an alternative consider:
create_table :section_edits do |t|
t.references :admin_user, index: true
t.references :section, index: true
t.string :summary
t.timestamps
end
Notice this way that you can index the foreign keys by adding index: true
Reference:
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-references

It should be same in this scenario.

Related

How to write belongs_to association when the foreign key can refer to either of two different columns?

cars.dealership_id can either refer to dealerships.id or dealerships.remote_id. How should I write my associations?
SCHEMA
create_table "cars", id: :serial, force: :cascade do |t|
t.string "name", limit: 255, null: false
t.integer "dealership_id", null: false
end
create_table "dealerships", id: :serial, force: :cascade do |t|
t.string "name", limit: 255, null: false
t.integer "remote_id", null: true
end
MODEL
class Car < ::ApplicationRecord
belongs_to :dealership,
class_name: '::Dealership',
foreign_key: :dealership_id,
primary_key: :remote_id
belongs_to :dealership,
class_name: '::Dealership',
foreign_key: :dealership_id,
primary_key: :id
end
cars.dealership_id can either refer to dealerships.id or dealerships.remote_id.
I'd suggest this design is problematic, and I'd recommend changing your database design as follows:
alter table cars
add constraint fk_cars_dealerships
foreign key (dealership_id)
references dealerships (id)
on update cascade
on delete restrict
;
With this change, the association becomes clear.
belongs_to :dealership
By default, create_table will create a primary key called id. You can change the name of the primary key with the :primary_key option (don’t forget to update the corresponding model) or, if you don’t want a primary key at all, you can pass the option id: false.
For creating primary key other than ID you can use the following.
class CreateContentUnits < ActiveRecord::Migration
def change
create_table :content_units, primary_key: :guoid do |t|
t.boolean :active, default: false
end
end
end
So now guoid will be used as primary key and now you can use your API ID as id in the model

Rails - DB migration best practice

I have designed the following migration and wanted to check with the community is that is meeting the best practices of rails migration. I am running a postgres db.
I am trying to achieve a db structure where the various status attached to a user is stored in a separate table. for instance, its marital status.
let me know if that sounds like a reasonably efficient table design. and what I could improve.
class CreatePrequalifications < ActiveRecord::Migration[5.2]
def change
create_table :prequalifications do |t|
t.string :attachment
t.text :description
t.integer :marital_status
t.integer :professional_status
t.integer :collateral_status
t.integer :income_direct
t.integer :income_support
t.integer :income_scolarship
t.integer :income_other
t.boolean :blacklist
t.references :user, foreign_key: true
t.timestamps
end
end
create_table :marital_status do |t|
t.string :single
t.string :married
t.string :other
t.string :divorced
t.string :with_dependants
t.references :user, foreign_key: true
t.references :prequalifications, foreign_key: true
end
create_table :professional_status do |t|
t.string :self_employed
t.string :employed
t.string :student
t.string :other
t.text :description
t.datetime :contract_created_at
t.datetime :contract_terminated_at
t.references :user, foreign_key: true
t.references :prequalifications, foreign_key: true
end
create_table :collateral_status do |t|
t.string :collateral_name
t.string :collateral_income
t.boolean :visale_collateral
t.boolean :student_collateral
t.boolean :bank_collateral
t.references :user, foreign_key: true
t.references :prequalifications, foreign_key: true
end
end
In this case, best practices would dictate:
Break each create_table into its own migration.
Your table names should be pluralized, e.g. marital_statuses.
Time stamps are a good idea.
Consider adding indexes to fields that will be queried regularly, e.g. model names, user emails, or foreign keys.
Check out the rails guide on migrations for information about best practice: https://edgeguides.rubyonrails.org/active_record_migrations.html
Let's start with:
Is it a single migration? If so, I would start with splitting it into several migrations (one for each table).
Add timestamps for each table (t.timestamps null: false). You will thank me later ;)
For statuses tables (martial_status, professional_status) create simpler tables with just name and references (no need to create column for each value). Also, you probably do not need the table for marital status, because you can use classy_enum instead.
In prequalifications you have integer columns for relations (maritial_status, professional_status). Don't do that, use references.
For boolean columns, define default values.

Rails migration - many belongs_to to same table, multiply FKs

I need some table like this one:
uid:integer
pid:integer
predesposition:integer
primary_key(uid,pid)
foreign_key(uid, user(id))
foreign_key(pid, user(id))
So, two questions:
1. How can I declare multiply FKs in migration?
2. How can I declare two (or more) columns belonged to same table in migration?
Example:
create_table :encounters, :id => false do |t|
t.belongs_to :user, :polymorphic => true
t.belongs_to :user, :polymorphic => true
t.integer :predisposition
end
If you want to refrence other table then follow the concept of foreign key . And wanna to suggest to use full table name instead of uid and pid .
create_table :table_name, {:id => false} do |t|
t.integer :user_id
t.integer :pid #suppose its procedures table
t.integer :predesposition
t.references :user
t.references :procedure
t.timestamps
end
execute "ALTER TABLE table_name ADD PRIMARY KEY (user_id,pid);"
Hope that help .

Rails: can I use polymorphic references with non-integer primary keys?

I have a database that uses UUIDs as primary keys, like this:
create_table "my_table", :id => false, :force => true do |t|
t.string "id", :limit => 36
end
However, when I try to use :references for foreign keys to that table, it generates integer columns for the ID. Can :references be instructed to deal with a non-integer ID? My migration for the referring table is like this:
create_table "child_table" :id => false, :force => true do |t|
t.string "id", :limit => 36
t.references :my_table
end
I know that I could just manually create :my_table_id and :my_table_type columns, but I'm wondering whether :references can be made to do its magic under these circumstances so that I don't have to handle the id+type explicitly throughout my code.
A :type option has been added when referencing since Rails 4.2
t.references :car, type: :uuid, index: true
For example:
def change
enable_extension 'uuid-ossp'
create_table :cars, id: :uuid do |t|
t.integer :seats
# And other car-specific things
end
create_table :wheels do |t|
t.references :car, type: :uuid, index: true
t.integer :radius
# And other wheel-specific things
end
end
source: https://github.com/rails/rails/pull/16231
Nope, references only creates integer columns as of this writing.
I'm sure you could override the references method to do what you want. But IMO you'd be better off specifying your UUID columns and type columns explicitly. That way the code is clear about what is going on behind the scenes.

Is this the correct way to set up has many with multiple associations?

I'm trying to set up a new project for a music site. I'm learning ROR and am a bit confused about how to make join models/tables. Does this look right?
I have users, playlists, songs, and comments. Users can have multiple playlists. Users can have multiple comments on their profile. Playlists can have multiple songs. Playlists can have comments. Songs can have comments.
class CreateTables < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :login
t.string :email
t.string :firstname
t.string :lastname
t.timestamps
end
create_table :playlists do |t|
t.string :title
t.text :description
t.timestamps
end
create_table :songs do |t|
t.string :title
t.string :artist
t.string :album
t.integer :duration
t.string :image
t.string :source
t.timestamps
end
create_table :comments do |t|
t.string :title
t.text :body
t.timestamps
end
create_table :users_playlists do |t|
t.integer :user_id
t.integer :playlist_id
t.timestamps
end
create_table :playlists_songs do |t|
t.integer :playlist_id
t.integer :song_id
t.integer :position
t.timestamps
end
create_table :users_comments do |t|
t.integer :user_id
t.integer :comment_id
t.timestamps
end
create_table :playlists_comments do |t|
t.integer :playlist_id
t.integer :comment_id
t.timestamps
end
create_table :songs_comments do |t|
t.integer :song_id
t.integer :comment_id
t.timestamps
end
end
def self.down
drop_table :users
drop_table :playlists
drop_table :songs
drop_table :comments
drop_table :users_playlists
drop_table :users_comments
drop_table :playlists_comments
drop_table :songs_comments
end
end
Few things:
Short version:
Join tables should be alphabetical (e.g. create_table :comments_users
This is only one half of setting up your associations. I'd like to see your model code as well
Your comments model should be setup to be a polymorphic association to the others.
Long version:
When setting up a join table (e.g. users and comments) you want to make it alphabetical. So that the users/comments table is actually create_table :comments_users. Ideally, you would want to setup a more meaningful name for this join table (since it is a model - see below) but it's your call.
Remember that you have to create models for these :has_many through associations. Most of these join tables could be created with :has_and_belongs_to_many but for future expansions, may as well use the :has_many through method. It would be wise to provide your association code in your model files as well - just as important as the creation of tables.
For comments, think about polymorphic relationships. This is because the comments are the same across all the different tables it belongs to. What this does is look for a type column in the polymorphic join table and that tells it what table the record (i.e. comment) belongs to.
Starting Resources:
Check out Ryan's brilliant (as usual) Railscast on the subject:
http://railscasts.com/episodes/47-two-many-to-many
Also, on polymorphism:
http://railscasts.com/episodes/154-polymorphic-association
http://guides.rubyonrails.org/association_basics.html
That looks ok. You seem to have the ID's in all the right place.
Couple of points though:
It's often easier to have many small migrations. I generally create each model and migration individually. You can then start building your model relationships in lock-step with your tests to ensure that your business requirements are actually being implemented.
You have some tests, right? :)

Resources