Running rails 6.0.3.2 / ruby 2.7.1
I have a has_many through-relationship that isn't behaving as expected.
My models look like this:
class Item < ApplicationRecord
has_many :item_permissions
has_many :users, :through => :item_permissions
end
class User < ApplicationRecord
has_many :item_permissions
has_many :items, :through => :item_permissions
end
class ItemPermission < ApplicationRecord
belongs_to :items
belongs_to :users
end
Now I want to retrieve all Items that a certain User has permission to:
u = User.find(1)
u.items
gives me an error:
NameError (uninitialized constant User::Items)
I can get the permission entries with
u.item_permissions
Is there any way to retrieve the items for a certain user or also the other way round receiving all users that are linked to a specific item?
The mistake is in your belongs_to declarations, in both your are using the plural word instead of the singular one to reference the associated model. Try with:
class ItemPermission < ApplicationRecord
belongs_to :item # :item instead of :items
belongs_to :user # :user instead of :users
end
More information here.
Related
New to rails. I'm creating a project with several database tables all in relation to each other. I would like to know how to add a foreign key reference to an instance after it has been created. Code below:
In schema:
class Blog < ActiveRecord::Base
has_many :posts
has_many :owners
has_many :users, through: :owners
end
class Owner < ActiveRecord::Base
belongs_to :user
belongs_to :blog
end
class User < ActiveRecord::Base
has_many :messages
has_many :posts
has_many :owners
has_many :blogs, through: :owners
end
Models:
class User < ActiveRecord::Base
has_many :messages
has_many :posts
has_many :owners
has_many :blogs, through: :owners
end
class Owner < ActiveRecord::Base
belongs_to :user
belongs_to :blog
end
class Blog < ActiveRecord::Base
has_many :posts
has_many :owners
has_many :users, through: :owners
end
In rails console:
blog1 = Blog.first
user1 = User.first
blog1.users = user1
NoMethodError: undefined method `each' for #<User:0x0000000487e9f8>
If you're trying to make it so that user1 becomes the owner of the blog, you could try
blog1 = Blog.first
user1 = User.first
Owner.create(user: user1, blog: blog1)
or
Owner.create(user: User.first, blog:Blog.first)
Hope I answered your question!
Since a Blog has many Users, .users will be a collection (Array or ActiveRecord_Relation).
Try: blog1.users << user1
<< (shovel operator) docs
When you are writing blog1.users, you are getting back an array, so doing = something wouldn't work. While you can just add to the array using << or say array.push(), it's not the best practice.
Instead, has_many (or has_one, etc), allows you to use build_ notation to create related objects. So you could do: blog1.users.build, which will create a new user referenced for the blog. Or if you want to persist it, you can call .users.create
There are many ways to go around it, but using ActiveRecord methods if available is a nice way to keep code readable and short.
I'm trying to set up a many to many table using rails. I followed these instructions from the Rails Guides and believe I have the schema set up properly.
I would like to be able to see all reviews for a specific doctor.
models:
class Doctor < ActiveRecord::Base
has_many :reviews
has_many :users, through: :reviews
end
class Review <ActiveRecord::Base
belongs_to :user
belongs_to :doctor
end
class User < ActiveRecord::Base
has_many :reviews
has_many :doctors, through: :reviews
end
I'm able to successfully query doctor.users, user.doctors, and user.reviews. However when I try to query doctor.reviews I only see an empty proxy #<ActiveRecord::Associations::CollectionProxy []>
How can I see all reviews for a doctor?
You need to change:
class User < ActiveRecord::Base
has_many :reviews
has_many :doctors, through: :reviews
end
to:
class User < ActiveRecord::Base
has_many :reviews
has_many :doctors, through: :reviews, source: :doctor
end
What is happening is that user is looking for "doctors" inside of Reviews, but you have no method to retrieve "doctors" only "doctor". If you specify the source attribute, it will name your query "doctors" but it will look under "doctor" which in this case is defined. Rails tries to guess what it should be, and usually assumes correctly, but being more explicit may solve the problem in this case.
I'm a bit new to Rails Active Record associations. I've tried to set up a relationship, but I get ActiveRecord error when I try to retrieve data. Did I associate my models incorrectly?
User has many Uploads, which has many UserGraphs:
class User < ActiveRecord::Base
has_many :uploads, through: :user_graphs
end
class Upload < ActiveRecord::Base
has_many :users, through: :user_graphs
end
class UserGraph < ActiveRecord::Base
belongs_to :user
belongs_to :upload
end
I want to get all of a user's uploads, and all of a user's graphs. The 2nd line doesn't work in rails console and gives an error
#user = User.find(1)
#uploads = #user.uploads
The error:
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :user_graphs in model User
Extra Credit:
If Users have Uploads that have UserGraphs... shouldn't it be has_many :uploads and has_many :user_graphs, through :uploads?
Add
has_many :user_graphs
to the User and Upload classes.
The :through option defines a second association on top of this one.
You didn't tell Rails that you have a user_graphs association on User, only an uploads association. So when Rails goes to follow the user_graphs association on uploads, it can't find it.
So, you need add the user_graphs association. Your models should look like this:
class User < ActiveRecord::Base
has_many :user_graphs # <<< Add this!
has_many :uploads, through: :user_graphs
end
class Upload < ActiveRecord::Base
has_many :user_graphs # <<< Add this!
has_many :users, through: :user_graphs
end
class UserGraph < ActiveRecord::Base
belongs_to :user
belongs_to :upload
end
I have three models which look something like this:
Class User < ActiveRecord::Base
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :user
has_many :votes
end
Class Vote < ActiveRecord::Base
belongs_to :comment
end
Now I want to get all the votes associated with a user's comments like so:
#user.comments.votes
But this throws the error:
undefined method `votes' for #<ActiveRecord::Relation:0x3f6f8a0>
This seems like it should work, but I suspect ActiveRecord is coughing on the deeper has_many relationship. I've hacked together an SQL query that gets the desired results, but I suspect there's a cleaner way using purely ActiveRecord. Any tips?
You should use a has_many :through association
In your case it would be
Class User < ActiveRecord::Base
has_many :comments
has_many :votes, :through => :comments
end
Class Comment < ActiveRecord::Base
belongs_to :user
has_many :votes
end
Class Vote < ActiveRecord::Base
belongs_to :comment
end
And then simply get the votes with
#user.votes
Try this:
Vote.joins(comment: :user).where(users: {id: #user.id})
How can I join the objects with the models below?
User
has_many messages
Message
belongs_to user
Thread
has_many messages
I'm trying to get all threads that belong to user X. I would like to join on message.user_id = user.user_id and thread.message_id = message.message_id. I can do this using find_by_sql but I'm trying to avoid that.
Thanks
Assuming your Message model also belongs_to :thread, then you should be able to put a has_many :threads, :through => :messages in your User model. Then you could just do user.threads to get all the associated threads.
The following should work: (note that I've added your missing message belongs_to :thread)
class User < ActiveRecord::Base
has_many :messages
has_many :threads, :through => :messages
end
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :thread
end
class Thread < ActiveRecord::Base
has_many :messages
has_many :users, :through => :messages
end
This should allow you to do my_user.threads and my_thread.users.
You can read more about has_many :through on the Rails Guides and the API.