Depends on how you want to interact with the things you can choose from 2 versions.
For tasks it was important to see who was the assigner/executor so I was able to sort the different (incoming/outgoing) tasks. So I could call user.assigned_tasks
or user.executed_tasks
.
For conversations I was not interested in interacting with that model. It does not matter who created it. I don't need conversation.sender
or conversation.recipient
. I need the messages (nested under conversation) to be identified based on the sender/recipient.
Version A
class Task < ActiveRecord::Base
belongs_to :assigner, class_name: "User"
belongs_to :executor, class_name: "User"
end
class User < ActiveRecord::Base
has_many :assigned_tasks, class_name: "Task", foreign_key: "assigner_id", dependent: :destroy
has_many :executed_tasks, class_name: "Task", foreign_key: "executor_id", dependent: :destroy
end
create_table "tasks", force: :cascade do |t|
t.integer "assigner_id"
t.integer "executor_id"
end
add_index "tasks", ["assigner_id"], name: "index_tasks_on_assigner_id", using: :btree
add_index "tasks", ["executor_id"], name: "index_tasks_on_executor_id", using: :btree
Version B
class User < ActiveRecord::Base
has_many :conversations, foreign_key: "sender_id", dependent: :destroy
end
class Conversation < ActiveRecord::Base
belongs_to :sender, class_name: "User", foreign_key: "sender_id"
belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
end
create_table "conversations", force: :cascade do |t|
t.integer "sender_id"
t.integer "recipient_id"
end
add_index "conversations", ["recipient_id"], name: "index_conversations_on_recipient_id", using: :btree
add_index "conversations", ["sender_id"], name: "index_conversations_on_sender_id", using: :btree
UPDATE:
If you run rails g model User
or rails g model Order
, migration will also be generated along test files, model file etc. This is the preferred way if the table does not exist yet. If table already exists and you wanna change it then you create only the migration which can be done 2 ways. The first is what you are talking about where u also pass the arguments, so when u open up the migration file the columns will already be there. But that is the hard way. You can just simply run rails g migration AddSomethingToThis
. Here the migration name does not matter, you should just choose something descriptive so you can easily recognize the migration file later on. Then you open up the migration file and you put there the columns you want. In my code u see the necessary foreign keys
. Besides that you can create price column etc., what you business logic needs. Then just run rake db:migrate
, which will change your db schema. You can always check out your current schema in schema.rb
. Never change the schema manually only by migrations.
Summing up:
- Create migration (with model if there is no table yet)
- Edit the migration file
- Run rake db:migrate so schema will be updated.
Update 2:
You can generate indexes easily by adding t.integer "recipient_id", index :true
in the migration file and then the the line that you highlighted will appear in schema.rb
(where I copied that part of my code from) after running rake db:migrate
. Check out some migration examples.
So indexes are about performance. With indexes the search in the db is faster in most cases. It's something like bookmark in a book. Usually you add it to foreign keys since those are the bridges between 2 models. If there are some attributes in a model which is queried heavily then you can add it to those as well. Don't add to too many lines. You can imagine what happens when you add let's say 20 bookmarks to a book.