For the next few lessons, we're going to be setting up the backend logic for user posts. We'll take it step by step, so you won't get lost.
The first thing we want to do is generate our controller and model for our Post
object. We can name the object whatever we want, but in this case, let's name it Post
.
Naming Objects
When naming objects, make sure that the naming makes sense. For example, in our app, we need an object that will represent a post created by a user. Therefore, naming the object "Post" makes total sense.
However, if we name it something random like "Almond", it starts making no sense at all. You'll be running commands like
Almond.new
orAlmond.all
for trying to create or show user posts, which really makes no sense in this case. Instead,Post.new
orPost.all
would make much more senseFirst, let's generate the controller. We can do this by running the following command:
rails generate controller posts
Notice how we generated a "posts" controller and not a "post" controller. If we recall, by rails naming conventions, controller names must be plural in general, and model names must be singular. If you don't follow these rules, unexpected errors might pop up.
Next, let's go ahead and generate our model post with fields photo and description which belongs to the user.
rails g model post description:text user:references
This will generate a migration file where we can specify the database columns that we want to add to the Post
object.
The migration file will be a file named something like xxxxxxxxxxx_create_posts.rb
.
Let's see what database columns we need to add for the Post
object.
If we look back at our wire frames, we see that Post
will have a description
. So we need to add these columns. Let's go ahead and add this to the migration file.
class CreatePosts < ActiveRecord::Migration[6.0]
def change
create_table :posts do |t|
t.text :description
t.references :user, null: false, foreign_key: true
t.timestamps
end
end
end
Then, on running the migration using rails db:migrate
. This migration will take care of adding a new column named user_id to posts table (referencing id column in users table) and it will also add an index on the new column.
The schema after migration looks as follows:
...
create_table "posts", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
t.text "description"
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_posts_on_user_id"
end
...
Notice that description
is a text
. The difference between string and text is in the size, string should be used for shorter text, and text should be used for longer text. See this Stackoverflow post for an in-depth explanation.
The above is an easy way to add relationship between users and posts. It will also add a belongs_to
relationship with user. Another way is first creating the model and then adding the relationship. For the second way after creating a model we add the index.
rails g model post description:text
We need to do is to set up an index for the user_id
column. Let me explain what this means.
Indexing
Indexing is super important in order to maintain your rails app performance. Here's an example of how it works.
Imagine you have a list of all the words in the English language, without any labels (A~Z) whatsoever. Then, you are given a word, for instance, "Cat". Your task is to find the word "Cat" from this list.
Obviously, this would be a huge task. You would have to look through each of the words to see if there is a match.
However, let's say you have a dictionary. A dictionary has labels which allows you to skip to the letter "C", and search for the word "Cat" within that range. This significantly decreases the amount of words you have to go through.
This is essentially what indexing is all about. It makes looking up things much more efficient.
So when should you use indexes?
As a rule of thumb, you should always use indexes when you have a foreign key.
What is a foreign key?
A foreign key is a value that belongs to another object. For instance, in this case,
user_id
is a foreign key, since it references theid
of anotherUser
object from thePost
object.For a more in-depth look into indexing and how it improves performance, check out this blog post.
That means we need to add an index for the user_id
in our Post
s. Fortunately, this is quite simple. All we need to do is add add_index :posts, :user_id
after the change
method.
Your create_posts.rb
file should now look like this:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.integer :user_id
t.text :description
t.timestamps null: false
end
add_index :posts, :user_id
end
end
Finally, run rails db:migrate
to migrate the columns.
Now, for storing photos, let's add has_one_attached :photo
to the Post
model. The Post
model should look something: