Akash Tomar
Akash Tomar

Reputation: 980

Referencing model from one model instance

This is my Schema.rb

Schema.rb

ActiveRecord::Schema.define(version: 20170617073406) do

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

  create_table "posts", force: :cascade do |t|
    t.string "post_id"
    t.datetime "timestamp"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

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

end

These are my three model classes.

Action.rb

class Action < ApplicationRecord
    belongs_to :post
    has_many :users, :foreign_key => 'user_user_id'
end

Post.rb

class Post < ApplicationRecord
    has_many :actions, :foreign_key => 'action_id'
end

User.rb

class User < ApplicationRecord
    has_many :actions, :foreign_key => 'action_id'
end

I am trying to add an instance of Action object into Post model object.

post = Post.find(post_id=post_id)
current_action = post.actions.find_or_create_by(name: "like")

It gives me the following error: SQLite3::SQLException: no such column: actions.action_id: SELECT "actions".* FROM "actions" WHERE "actions"."action_id" = ? AND "actions"."name" = ? LIMIT ?

I am new to Ruby on Rails and come from Django background. Please help me figure this out.

Upvotes: 2

Views: 66

Answers (2)

Jay-Ar Polidario
Jay-Ar Polidario

Reputation: 6603

Solution:

Run migrations in command line:

rails generate migration add_post_to_actions post:belongs_to
rake db:migrate

Then update:

class Action < ApplicationRecord
  belongs_to :post
  # ...
end

class Post < ApplicationRecord
  self.primary_key = 'post_id'
  has_many :actions
  # ...
end

class User < ApplicationRecord
  self.primary_key = 'user_id'
  # ...
end

Explanation:

  • 1st line would add post_id column to actions table, and then index it with foreign constraint
  • The above migrations are independent of the contents of your current model files. You can even delete your models/action.rb or models/user.rb, and you'll see that the migrations would still even run without problems, because migrations only "do" stuff on the actual current database. The migration files also do not even care about whatever is written in your schema.rb, although it will update that schema.rb each time you run a migration (after the database has already been migrated/updated).

Upvotes: 2

Gerry
Gerry

Reputation: 10517

Action needs to be related to the user as many to many...

If you want a many-to-many association, you will need to use another table (i.e. a join model):

class Action < ApplicationRecord
    belongs_to :post
    has_many :user_actions
    has_many :users, through: :user_actions
end

class User < ApplicationRecord
    has_many :user_actions
    has_many :actions, through: :user_actions
end

class UserAction < ApplicationRecord
    belongs_to :action
    belongs_to :user
end

The ID I want to store is longer than Integer can do.

You can specify your own id in the migration and avoid adding an extra action_id:

class CreateActions < ActiveRecord::Migration[5.1]
  def change
    create_table :actions, id: false do |t|
      t.string :id, null: false

      t.timestamps
    end

    add_index :actions, :id , unique: true
  end
end

With the above setup, you don't need to specify any foreign_key in Post either, ActiveRecord will use defaults (i.e. action_id):

class Post < ApplicationRecord
    has_many :actions
end

A note about associations and foreign keys (and why you got that error):

Whenever you create an association, the foreign_key must be created in the table with the belongs_to side, since ActiveRecord will look for that key there.

Even If you don't specify a belongs_to, a has_many reference to that table will still look for that foreign_key.

So, when you add

has_many :actions, :foreign_key => 'action_id'

you are telling ActiveRecord to look for action_id column in actions table, but that columns has not being created in actions table.

In the proposed solution, the foreign keys are on the join table model (i.e. UserActions), so you must create a migration to include them:

rails g migration CreateUserActions user:references action:references

Upvotes: 3

Related Questions