Search code examples
ruby-on-railsassociationspolymorphic-associations

How to display associations from rails console


Associations are my rails achilles heel.

I have 3 models and controllers: User, List, Item.

User can can create username and password. List can create list name, Item can create item_name

Ideally, a list belongs to a user. An item belongs to a list. List has many items. User has many lists. So I came up with:

class Item < ActiveRecord::Base
  belongs_to :list
  delegate :user, to: :list
end

class List < ActiveRecord::Base
  belongs_to :user
  has_many :items
end

class User < ActiveRecord::Base
  has_many :lists
  has_many :items, through: :lists
end

On rails console, just to make sure, I checked the columns:

2.2.1 :005 > List.column_names
 => ["id", "name", "user_id", "created_at", "updated_at"] 
2.2.1 :006 > Item.column_names
 => ["id", "item_name", "list_id", "created_at", "updated_at"]     
2.2.1 :007 > User.column_names
 => ["id", "username", "password", "created_at", "updated_at"] 

So I went to create new User, Item, and List:

User.create(username: "iggy2", password: "helloworld") 
#let's say iggy2 has user_id 2.

I want to have iggy2 to have a List named "important stuff", with Item "Wash dishes".

List.create(name: "Important", user_id: 2 ) #let's say this has id of 1

Item.create(item_name: "Wash dishes", list_id: 1)

I assumed that Item is connected to List and List is connected to User. But when I type User.last.name, instead of seeing "Important", I get a NoMethodError: undefined method 'name'. I also get similar error on List.last.item_name

This is what my schema looks like

create_table "items", force: :cascade do |t|
    t.text     "item_name"
    t.integer  "list_id"
    t.datetime "created_at",                 null: false
    t.datetime "updated_at",                 null: false
  end

  create_table "lists", force: :cascade do |t|
    t.string   "name"
    t.integer  "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "users", force: :cascade do |t|
    t.string   "username"
    t.string   "password"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

What is missing on my code? Was my assumption wrong? How can I get User.last.name or even User.last.item_name to show the last user's item name or list name?


Solution

  • Your code is correct but your assumption is wrong. User.last returns an user record so you will get NoMethodError when accessing methods in associated records.

    I suppose what you want is below:

    List.where(user_id: User.last.id).pluck(:name) # Return all list names belong to last user
    
    id = List.find_by(user_id: User.last)
    Item.where(list_id: id).pluck(:item_name) # Return all item names belong to last user