I have a table (connections) it needs to have multiple Polymorphic Relations. The first one is working but the second gets an error. Here is the layout of the tables. I get this error even if I change has_many :links, as: :linkable to has_many :connection_links, as: :linkable, thinking that it was some reserved word.
class CreateConnections < ActiveRecord::Migration
def change
create_table :connections do |t|
t.integer :connectable_id
t.string :connectable_type
t.integer :linkable_id
t.string :linkable_type
t.boolean :status_id
t.timestamps
end
end
end
class Connection < ActiveRecord::Base
# relations
belongs_to :connectable, polymorphic: true
belongs_to :linkable, polymorphic: true
end
class Person < ActiveRecord::Base
has_many :connections, as: :connectable, dependent: :destroy
has_many :links, as: :linkable, dependent: :destroy
end
class Business < ActiveRecord::Base
has_many :connections, as: :connectable, dependent: :destroy
has_many :links, as: :linkable, dependent: :destroy
end
When I try to pull the links it errors out.
[2] pry(main)> person.connections
Connection Load (0.4ms) SELECT "connections".* FROM "connections" WHERE "connections"."connectable_id" = $1 AND "connections"."connectable_type" = $2 [["connectable_id", 9], ["connectable_type", "Person"]]
=> []
[3] pry(main)> person.links
NameError: uninitialized constant Person::Link
The error is saying that there is no class called Link - doesn't seem like you have one from what you've shown.
Related
I have two has many through associations in my application which allows me to assign maps to a user through an admin dashboard.
Here are the tables I have in my application.
Mapgroups
class Mapgroup < ApplicationRecord
belongs_to :map, optional: true
belongs_to :group, optional: true
end
Usergroups
class Usergroup < ApplicationRecord
belongs_to :user, optional: true
belongs_to :group, optional: true
end
Groups
class Group < ApplicationRecord
has_many :usergroups, dependent: :destroy
has_many :users, through: :usergroups, dependent: :destroy
has_many :mapgroups, dependent: :destroy
has_many :maps, through: :mapgroups, dependent: :destroy
end
Users
class User < ApplicationRecord
has_many :groups, through: :usergroups, dependent: :destroy
end
I have been using this method to fetch the maps that the user has access to with this method:
def fetch_maps
self.groups.flat_map { |g| g.maps }
end
However, according to my logs and testing, this is a very expensive way to do this. How can I join tables on an association like this to just get the maps in this method instead?
I have tried this joins query
def fetch_maps
Map.joins(mapgroups: [:group, :user]).where(user: self)
end
But get this error
Can't join 'Mapgroup' to association named 'user'; perhaps you
misspelled it?
Any ideas on how I can join these tables to produce the maps the user has access to?
This is the usergroups table in my schema file:
create_table "usergroups", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.bigint "user_id"
t.bigint "group_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["group_id"], name: "index_usergroups_on_group_id"
t.index ["user_id"], name: "index_usergroups_on_user_id"
end
Maps model
class Map < ApplicationRecord
has_many :units, dependent: :destroy
belongs_to :subaccount, optional: true
belongs_to :term, optional: true
has_many :mapgroups, dependent: :destroy
has_many :groups, through: :mapgroups, dependent: :destroy
end
Your user.rb will be like this
class User < ApplicationRecord
has_many :usergroups
has_many :groups, through: :usergroups, dependent: :destroy
end
And reference the user with usergroups
and you don't need to dependent: :destroy use twice like
has_many :usergroups #=> remove this from this line , dependent: :destroy
has_many :users, through: :usergroups, dependent: :destroy
The has_many :through Association
Long time listener, first time caller. I'm trying to create two associations between the same database tables, Chatrooms and Users. What I have so far is a has_many through relationship where a Chatroom has many Users through Messages. This part works fine. What I want to do is to create a second join table that connects Chatrooms to Users, through a join table called Chatroom_players. So what I'd like is for Chatroom.first.users to get me users through the messages join table and Chatroom.first.players to get me everyone from the chatroom_players join table. The reason I want this is so that I can maintain user presence even if a user hasn't written any messages in the chat, also so that a user can leave the room but maintain his or her messages in the chat.
Here is what I have so far that does not work:
chatroom.rb:
class Chatroom < ApplicationRecord
has_many :messages, dependent: :destroy
has_many :users, through: :messages
has_many :chatroom_players
has_many :users, through: :chatroom_players
end
message.rb:
class Message < ApplicationRecord
belongs_to :chatroom
belongs_to :user
validates :content, presence: true, length: {minimum: 2, maximum: 200}
end
chatroom_player.rb
class ChatroomPlayer < ApplicationRecord
belongs_to :chatroom
belongs_to :user
end
user.rb
class User < ApplicationRecord
has_many :messages, dependent: :destroy
has_many :chatrooms, through: :messages
has_many :chatroom_players
has_many :chatrooms, through: :chatroom_players
end
chatroom_players migration:
class AddChatroomPlayers < ActiveRecord::Migration[5.0]
def change
create_table :chatroom_players do |t|
t.references :user, index: true, foreign_key: true, null: false
t.references :chatroom, index: true, foreign_key: true, null: false
t.boolean :creator, default: false
t.timestamps null: false
end
end
end
You need to use different names for the associations:
class Chatroom < ApplicationRecord
has_many :messages, dependent: :destroy
has_many :users, through: :messages
has_many :chatroom_players
# this is a separate association to users through the
# chatroom_players table.
has_many :participants,
through: :chatroom_players,
source: :user, # what association on chatroom_players to use
class_name: 'User' # since it cannot be deduced automatically
end
I am making a rails app where a user can post courses and also subscribe to courses.My model files are:
user.rb:
class User < ActiveRecord::Base
has_many :courses, dependent: :destroy
has_many :coursejoins, dependent: :destroy
has_many :learnables, through: :coursejoins, class_name: "Course"
has_many :comments, dependent: :destroy
...
end
course.rb:
class Course < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :coursejoins, dependent: :destroy
has_many :students, through: :coursejoins, class_name: "User"
has_many :documents, dependent: :destroy
has_many :comments, dependent: :destroy
...
end
coursejoin.rb:
class Coursejoin < ActiveRecord::Base
belongs_to :learnable, :class_name => "Course"
belongs_to :student, :class_name => "User"
end
20160219171527_create_coursejoins.rb
class CreateCoursejoins < ActiveRecord::Migration
def change
create_table :coursejoins do |t|
t.boolean :accepted
t.timestamps
end
end
end
20160219174937_add_student_id_to_coursejoins.rb
class AddStudentIdToCoursejoins < ActiveRecord::Migration
def change
add_column :coursejoins, :student_id, :integer
end
end
20160219224309_add_learnable_id_to_coursejoins.rb
class AddLearnableIdToCoursejoins < ActiveRecord::Migration
def change
add_column :coursejoins, :learnable_id, :integer
end
end
The coursejoin model is like a relation between a course and a user.
When I try to do #course.students, i get error:
SELECT "users".* FROM "users" INNER JOIN "coursejoins" ON "users"."id" = "coursejoins"."student_id" WHERE "coursejoins"."course_id" = ? [[nil, 1]]
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: coursejoins.course_id: SELECT "users".* FROM "users" INNER JOIN "coursejoins" ON "users"."id" = "coursejoins"."student_id" WHERE "coursejoins"."course_id" = ?
I don't know SQL much so I am not able to decipher the error.
I looked at questions with similar error but none seemed related.
I have been stuck with this for two days.
How do I fix this?
Okay i got this solved and thought i should post the solution for future reference. Basically all that was needed to be done was adding foreign_key: "learnable_id" to "has_many :coursejoins, dependent: :destroy" in course model and foreign_key: "student_id" to has_many :coursejoins, dependent: :destroy to user model.
I have a Users class, and a UserGroup class:
class User < ActiveRecord::Base
has_many :group_memberships
has_many :users_groups, through: :group_memberships
...
class UsersGroup < ActiveRecord::Base
has_many :group_memberships
has_many :users, through: :group_memberships
... and a GroupMembership class to join them -
class GroupMembership < ActiveRecord::Base
belongs_to :users, dependent: :destroy
belongs_to :users_groups, dependent: :destroy
My migrations look like this -
class CreateUsersGroups < ActiveRecord::Migration
def change
create_table :users_groups do |t|
t.string :title
t.string :status
t.string :about
t.timestamps null: false
end
end
end
class CreateGroupMembership < ActiveRecord::Migration
def change
create_table :group_memberships do |t|
t.integer :user_id, index: true
t.integer :users_group_id, index: true
t.boolean :owner
end
end
end
So user.group_memberships is perfectly happy, but user.users_groups returns an error -
undefined method `relation_delegate_class' for Users:Module
Similarly, users_group.group_memberships is fine, but users_group.users returns exactly the same error -
undefined method `relation_delegate_class' for Users:Module
... on the users module. I've stared at this for a couple of hours, but I'm sure it's simple syntax somewhere. What's the problem?
When using belongs_to I believe you need to use a singular format:
So not belongs_to :users but belongs_to :user
class GroupMembership < ActiveRecord::Base
belongs_to :user, dependent: :destroy
belongs_to :writers_group, dependent: :destroy
I believe that since you are using 'through' you will have to use:
user.group_memberships.users_groups
This is because users does not have users_groups or vice versa.
Instead you access the users_groups through group_memberships.
I am trying to add a "following" like functionality to my site but I am having trouble finding the right way to use a polymorphic association. A user needs to be able to follow 3 different classes, these 3 classes do not follow the user back. I have created a user following user in the past but this is proving to be more difficult.
My Migration was
class CreateRelationships < ActiveRecord::Migration
def change
create_table :relationships do |t|
t.integer :follower_id
t.integer :relations_id
t.string :relations_type
t.timestamps
end
end
end
My Relationship model is
class Relationship < ActiveRecord::Base
attr_accessible :relations_id
belongs_to :relations, :polymorphic => true
has_many :followers, :class_name => "User"
end
In my User model
has_many :relationships, :foreign_key => "supporter_id", :dependent => :destroy
and in the other 3 models
has_many :relationships, :as => :relations
Am I missing something with setting up this association?
You basically have it right, except for a few minor errors:
attr_accessible :relations_id is redundant. Remove it from your Relationship model.
Both Relationship and User models call has_many to associate with each other. Relationship should call belongs_to because it contains the foreign key.
In your User model, set :foreign_key => "follower_id".
Here is how I would do it.
Have a Follow middle class with polymorphic association on the followable content side and has_many on the follower user side (user has many follows).
First, create a follows table:
class CreateFollows < ActiveRecord::Migration
def change
create_table :follows do |t|
t.integer :follower_id
t.references :followable, :polymorphic => true
t.timestamps
end
end
end
Replace Relationship model with a Follow model:
class Follow < ActiveRecord::Base
belongs_to :followable, :polymorphic => true
belongs_to :followers, :class_name => "User"
end
Include in User model:
has_many :follows, :foreign_key => :follower_id
Include in your three followable classes:
has_many :follows, :as => :followable
You can now do this:
TheContent.follows # => [Follow,...] # Useful for counting "N followers"
User.follows # => [Follow,...]
Follow.follower # => User
Follow.followable # => TheContent