Reputation: 980
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
Reputation: 6603
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
post_id
column to actions
table, and then index it with foreign constraintschema.rb
, although it will update that schema.rb
each time you run a migration (after the database has already been migrated/updated).Upvotes: 2
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