-
Notifications
You must be signed in to change notification settings - Fork 0
17b Categories Posts Migration
All we need is a foreign key column—category_id—on the posts table. You could simply add that column as an integer and be done with it.
We'll explore a cooler, and equally easy, approach.
When creating a table, you can use a column type of references to define a foreign key column.
create_table :posts do |t|
t.references :category
endYou can also add an index simultaneously (always a good idea for foreign key columns).
create_table :posts do |t|
t.references :category, index: true
endNow to put this knowledge to good use. Generate a migration as always.
$ bin/rails g migration add_category_id_to_posts
invoke active_record
create db/migrate/20141105034340_add_category_id_to_posts.rbAnd edit your migration as follows.
class AddCategoryIdToPosts < ActiveRecord::Migration
def change
add_reference :posts, :category, index: true
end
endNow migrate!
$ bin/rake db:migrate
== 20141105034340 AddCategoryIdToPosts: migrating =============================
-- add_reference(:posts, :category, {:index=>true})
-> 0.0073s
== 20141105034340 AddCategoryIdToPosts: migrated (0.0074s) ====================Let's check out the updated posts table in the database. Remember how to do that?
$ psql -d bluit_development
psql (9.3.2)
Type "help" for help.
bluit_development=# \d posts
Table "public.posts"
Column | Type | Modifiers
-------------+-----------------------------+----------------------------------------------------
id | integer | not null default nextval('posts_id_seq'::regclass)
title | character varying(255) |
link | character varying(2000) |
body | text |
created_at | timestamp without time zone |
updated_at | timestamp without time zone |
post_type | integer | default 0
category_id | integer |
Indexes:
"posts_pkey" PRIMARY KEY, btree (id)
"index_posts_on_category_id" btree (category_id)(You can quit psql with the command \q.)
Now that our database is prepared, we can add the relationships to our models.
app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :categoryapp/models/category.rb
class Category < ActiveRecord::Base
has_many :postsTry out those relationships in the console (which you'll need to restart).
Loading development environment (Rails 4.1.6)
[1] pry(main)> post = Post.first
Post Load (0.6ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" ASC LIMIT 1
=> #<Post id: 1, title: "TIL there's an immersive coding experience in Indy...", link: "https://elevenfifty.com/", body: "You should totally check this out. They have a T. ...", created_at: "2014-10-29 18:40:38", updated_at: "2014-11-05 04:03:21", post_type: 0, category_id: 1>
[2] pry(main)> category = Category.last
Category Load (0.3ms) SELECT "categories".* FROM "categories" ORDER BY "categories"."id" DESC LIMIT 1
=> #<Category id: 3, name: "todayilearned", title: "Today I Learned", description: "You learn something new every day; what did you le...", sidebar: "Submissions must be verifiable. Please link direct...", submission_text: "Please make sure your headline starts with 'TIL' a...", created_at: "2014-11-05 02:41:55", updated_at: "2014-11-05 02:41:55">
[3] pry(main)> post.category = category
=> #<Category id: 3, name: "todayilearned", title: "Today I Learned", description: "You learn something new every day; what did you le...", sidebar: "Submissions must be verifiable. Please link direct...", submission_text: "Please make sure your headline starts with 'TIL' a...", created_at: "2014-11-05 02:41:55", updated_at: "2014-11-05 02:41:55">
[4] pry(main)> post.save
(0.1ms) BEGIN
SQL (0.4ms) UPDATE "posts" SET "category_id" = $1, "updated_at" = $2 WHERE "posts"."id" = 1 [["category_id", 3], ["updated_at", "2014-11-05 04:08:08.596470"]]
(6.4ms) COMMIT
=> true
[5] pry(main)> post.reload
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT 1 [["id", 1]]
=> #<Post id: 1, title: "TIL there's an immersive coding experience in Indy...", link: "https://elevenfifty.com/", body: "You should totally check this out. They have a T. ...", created_at: "2014-10-29 18:40:38", updated_at: "2014-11-05 04:08:08", post_type: 0, category_id: 3>
[6] pry(main)> post.category
Category Load (0.3ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT 1 [["id", 3]]
=> #<Category id: 3, name: "todayilearned", title: "Today I Learned", description: "You learn something new every day; what did you le...", sidebar: "Submissions must be verifiable. Please link direct...", submission_text: "Please make sure your headline starts with 'TIL' a...", created_at: "2014-11-05 02:41:55", updated_at: "2014-11-05 02:41:55">
[7] pry(main)> category.posts
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."category_id" = $1 [["category_id", 3]]
=> [#<Post id: 1, title: "TIL there's an immersive coding experience in Indy...", link: "https://elevenfifty.com/", body: "You should totally check this out. They have a T. ...", created_at: "2014-10-29 18:40:38", updated_at: "2014-11-05 04:08:08", post_type: 0, category_id: 3>]Are both sides of the relationship working? Let's take a moment to require that all posts have a category assigned to them. Add the following to the Post model:
app/models/post.rb
validates :category_id, presence: trueYou probably have some old post records that don't yet have categories assigned them. You can quickly edit them to assign categories, or do it in bulk via the console.
[1] pry(main)> Post.where(category: nil).each {|p| p.category = Category.first; p.save}Commit!
$ git add .
$ git commit -m "Add many-to-1 relationship between Post and Category."