Ruby on Rails: Many-to-Many Instance - ruby-on-rails

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.

Related

Rails has_many through - query through the relationship

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.

Many to many table rails

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.

Relationship between different Devise+Cancan roles

I am implementing an authentication+authorization system in my Rails 3 Application.
I have a HABTM relationship with between Users and Roles.
The roles I will have are : manager,dealer,operator,admin
Now a manager can have many dealers under him. How do I model this relationship?
It is a simple question but I could not find an answer. Also a similar question here: Role-dependent associations but it does not clear things properly.
EDIT:
I am thinking my requirement is further simple. For me a user can only be either an Admin, Operator, Dealer or Manager.
For this I can simply add a role column to User table. How will the relationship between Managers and Dealers be enforced now?
I think you're looking for something more like
class Organization < ActiveRecord::Base
has_many :users
has_many :managers
has_many :dealer
has_many :admins
has_many :operators
has_many :dealer_users, :through => :managers, :class_name=>"User"
end
class Admin < ActiveRecord::Base
has_many :organizations
belongs_to :user
end
class Dealer
has_many :organizations
belongs_to :user
end
class Operator < ActiveRecord::Base
has_many :organizations
belongs_to :user
end
class Manager < ActiveRecord::Base
has_many :dealers
belongs_to :organization
end
class User < ActiveRecord::Base
has_many :organizations
has_many :admins
has_many :operators
has_many :managers
has_many :dealers
end

Nested models with has_many in Rails

For example I have in my app model User, that has_many models Post. And Post has_many Attachment. So I can do this
user.posts
and this
post.attachment
But what if I want do smth like
user.attachments
Is there any build-in solution for this?
You would use a has_many through association. You should end up with something similar to the following structure:
class User < ActiveRecord::Base
has_many :posts
has_many :attachments, :through => :posts
end
class Post < ActiveRecord::Base
has_many :attachments
end
class Attachments < ActiveRecord::Base
belongs_to :posts
end
The relevant section from the above link:
The has_many :through association is also useful for setting up “shortcuts” through nested has_many associations...

ActiveRecord::HasManyThroughAssociationNotFoundError in UserController#welcome

I have a many to many relationship in rails. All database tables are named accordingly and appropriately. All model files are plural and use underscore to seperate words. All naming comventions are followed by ruby and rails standards. I'm using has many through in my models like this:
has_many :users, :through => :users_posts #Post model
has_many :posts, :through => :users_posts #User model
belongs_to :users #UsersSource model
belongs_to :posts #UsersSource model
What else could this error be from?
ActiveRecord::HasManyThroughAssociationNotFoundError in UsersController#welcome
Could not find the association :users_posts in model Post
You need to define the join model as a separate association when using has_many :through:
class Post < ActiveRecord::Base
has_many :user_posts
has_many :users, :through => :user_posts
end
class User < ActiveRecord::Base
has_many :user_posts
has_many :posts, :through => :user_posts
end
class UserPost < ActiveRecord::Base
belongs_to :user # foreign_key is user_id
belongs_to :post # foreign_key is post_id
end
This works best when you need to keep data that pertains to the join model itself, or if you want to perform validations on the join separate from the other two models.
If you just want a simple join table, it's easier to use the old HABTM syntax:
class User < ActiveRecord::Base
has_and_belongs_to_many :posts
end
class Post < ActiveRecord::Base
has_and_belongs_to_many :users
end

Resources