Nested models with has_many in Rails - ruby-on-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...

Related

Specifying Conditions on Multiple Nested Eager Loaded Associations

I'm trying to query on ActiveRecord multiple nested eager loaded associations with conditions like so:
user.books.includes(slot: [room: :school]).where("books.slot.room.school.id = 1")
Obviously this query is wrong, but basically what I'm trying to reach is a relation of user.books for a certain school.
My model structure is:
class User < ActiveRecord::Base
has_many :books
has_many :slots, through: :books
has_many :rooms, through: :slots
has_many :schools
end
class Book < ActiveRecord::Base
belongs_to :user
belongs_to :slot
end
class Slot < ActiveRecord::Base
has_many :books
belongs_to :room
end
class Room < ActiveRecord::Base
belongs_to :school
has_many :slots
end
class School < ActiveRecord::Base
has_many :users
has_many :rooms
has_many :slots, through: :rooms
has_many :books, through: :slots
end
Any ideas? Thanks in advance.
includes eager loads association records, while joins does what you want to do.
This question has been asked here numerous times. Please make sure that you look and try to find a similar question here before you ask one.
So you want to change your code like this:
user.books.joins(slot: [room: :school]).where(schools: { id: 1 })

Rails ActiveRecord How to get array of associated models

I am using Ruby on Rails 4.0.1 and I would like to get the array of associated models. That is, I have the following models and associations:
class Post < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :likes, dependent: :destroy
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class Like < ActiveRecord::Base
belongs_to :post
end
And I would like to get the array of associated models likes following.
Post.has_many_associated
=> [:comments, :likes]
Any Idea?
Thank you for your advice.
Tae-ho.
Yes, you can do this with reflect_on_all_associations:
Post.reflect_on_all_associations(:has_many).map(&:name)

Rails association with same model

I have a model Article and model User. In users, there will be one creator of the article and many readers. How do I link these together?
I was thinking:
class Article < ActiveRecord::Base
has_and_belongs_to_many :users
has_one created_by, through: :user (????)
end
class User < ActiveRecord::Base
has_many :articles
end
You can do like this
class Article < ActiveRecord::Base
has_and_belongs_to_many :users
has_one created_by_user,:class_name => 'User'
end
If you want to specify a custom foreign_key(which is useful in these cases),you can specify a foreign_key option
class Article < ActiveRecord::Base
has_and_belongs_to_many :users
has_one created_by_user,:class_name => 'User',:foreign_key =>'your_custom_fkey'
end

Rails: stringing together multiple has_many relationships

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})

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