Ruby on Rails four-way association tree - ruby-on-rails

The big picture: I am creating an app to track temporal events historically. I am setting it up with four main models: Users, Events, Stories and Images. The idea is that any given user can create an Event, and add Stories and/or Images to his own Event or to any other one. But both Stories and Images are always attached to a certain Event, and any other model belongs to the User who created it (for filtering and editing purposes)
The general structure of the associations would be something like this:
class User < ActiveRecord::Base
has_many :events
has_many :stories
has_many :images
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :stories
has_many :images
end
class Story < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
class Image < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
I am kind of new to Rails and I have little-to-no control over more complex associations as many_to_many, through: or as:
My question here is, is this set of associations optimal, or could it be improved by combining them in a different way?

You're in the right track, but story and image shouldn't belong to user. You're creating a redundancy in there.
class User < ActiveRecord::Base
has_many :events
has_many :stories, :through => :events
has_many :images, :through => :events
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :stories
has_many :images
end
class Story < ActiveRecord::Base
belongs_to :event
end
class Image < ActiveRecord::Base
belongs_to :event
end
This way you can still write user.stories and user.images.

Try to use nested attributes:
http://railscasts.com/episodes/196-nested-model-form-part-1
Sample code:
class User < ActiveRecord::Base
has_many :events
accepts_nested_attributes_for :events
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :stories
has_many :images
accepts_nested_attributes_for :stories, :images
end
class Story < ActiveRecord::Base
belongs_to :event
end
class Image < ActiveRecord::Base
belongs_to :event
end
Nested attributes accepts many level. In this case, there are 3 levels
user
event
story and image.
It like the sample at rails cast with 3 level (survey - question -answer).
Look at the link above and watch the part 2 to see how it work.
Or you can't look at my sample, but it work with 2 levels(subject - task).
Link at here
Login with account: duyet.vn#gmail.com/12341234

Related

when to use polymorphic associations vs STI vs another table in rails

I have taken a look at Polymorphic associations and STI but I don't really know if they apply to my specific use case. In my app I have the following relevant classes:
class Restaurant < ApplicationRecord
belongs_to :owner, class_name: "User"
has_many :menus
has_many :dishes
has_many :categories
has_many :bookings
has_many :simple_bookings
mount_uploader :photo, PhotoUploader
end
class Dish < ApplicationRecord
has_many :menu_dishes
has_many :menus, through: :menu_dishes
belongs_to :category
belongs_to :restaurant
mount_uploader :photo, PhotoUploader
end
class Menu < ApplicationRecord
belongs_to :restaurant
has_many :bookings
has_many :categories
has_many :menu_dishes
has_many :dishes, through: :menu_disheshas_many :menu_dishes
end
class MenuDish < ApplicationRecord
belongs_to :dish
belongs_to :menu
end
So far the user flow is the following:
A restaurant owner signs up and creates restaurant dishes. Then this owner creates a menu containing different MenuDishes.
Afterwards, users can search for different menus and book them.
My problem is the following:
I want to implement a feature where owners can add up to 3 MenuDishOptions (that belong to MenuDishes) so that a user can change each MenuDish with the available MenuDishOption for that MenuDish.
In other words, I want each MenuDish to contain many MenuDishOptions. Once a MenuDishOption is selected, the MenuDish passes to be a MenuDishOption and the selected MenuDishOption to a MenuDish.
Therefore the MenuDishOption class would look something like this:
class MenuDishOption < ApplicationRecord
belongs_to :menu_dish
has_one :dish
belongs_to :menu, through: menu_dishes
end
The MenuDish class would be updated to:
class MenuDish < ApplicationRecord
has_many :menu_dish_options
belongs_to :menu
belongs_to :dish
end
Please let me know if I need to share more info and thanks a million to anyone that takes the time to help this newbie.

Association between 3 models

I would like a user be able to create a course(so it should belong to one user) and also be able to join another course that it haven't created by him.What is the proper associations between the course and the user ? I want to make the following model associations:
Class User < ActiveRecord::Base
has_many :courses
has_many :comments ,through: :courses
end
Class Course < ActiveRecord::Base
has_and_belongs_to_many :users #here i am not sure
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :courses
end
I think what you should be able to do something like:
Class User < ActiveRecord::Base
has_many :courses
has_many :course_users
has_many :subscribed_courses, through: :course_users, source: :course # I think you should be able to do foreign_key: :course_id, class_name: 'Course'
has_many :comments ,through: :courses
end
Class Course < ActiveRecord::Base
belongs_to :user
has_many :course_users
has_many :participants, through: :course_users, source: :user # I think you should be able to do foreign_key: :user_id, class_name: 'User'
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :courses
end
#course_users is a join table for courses and users
class CourseUser < ActiveRecord::Base
# inside here you could have several other connections e.g grade of a user in a course within this join model
belongs_to :user
belongs_to :course
end
If I'm understanding what you're saying - you need to have a third model - you can call it enrollment
For Course you would use belongs_to :user if each course is created as a user.
Your Enrollment model with have two HABTAM
Class Enrollment < ActiveRecord::Base
has_and_belongs_to_many :users
has_and_belongs_to_many :courses
end
(An Aside, if a course is going to be offered more than once, you'll have to add an additional model for each instance of the course and the enrollment will belong to that model, and not courses)

Rails activerecord deep eager loading

Here is my models:
class User < ActiveRecord::Base
has_many :products
has_many :comments
end
class Product < ActiveRecord::Base
belongs_to :user
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :product
end
I need to get comment records from current user products only
How do I do that? thanks
If we move the relationships to use a has_many: comments, through: products you can probably get what you're after:
class User < ActiveRecord::Base
has_many :products
has_many :comments, through: products
end
class Product < ActiveRecord::Base
belongs_to :user
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :product
end
Now you can do user.comments.
The rails docs are here, which say:
A has_many :through association is often used to set up a many-to-many
connection with another model. This association indicates that the
declaring model can be matched with zero or more instances of another
model by proceeding through a third model. For example, consider a
medical practice where patients make appointments to see physicians.

Retrieve polymorphic associations in Rails from one model

class User < ActiveRecord::Base
has_many :posts
has_many :images, as: :imageable
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :images, as: :imageable
end
class Image < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
end
Is there a specific way where I can do User.images and get both the user's images and the post's images that belong to that user?
For some reason I can't wrap my head around how to do this best.
In that case you can avoid polymorphic relationship, simple has_many and belongs_to will suffice. where :
class User ActiveRecord::Base
has_many :posts
has_many :images
end
class Post ActiveRecord::Base
belongs_to :user
has_many :images
end
class Image < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
But then again I think you wanted to ask about User.last.images and not User.images
the same can be done through has_many through associations as well

Setting up a Has_Many :through Association

On the application I'm currently working on, I'm stuck on setting up the associations between 3 models to ensure referential integrity. I have an Event model, Building model, and a Room model. The association in real life is pretty intuitive. An Event can only be in one Building and one Room. A Building clearly can have multiple rooms.
Here's what I have set up now. However, how can Events specify their room if they belong to Buildings, and the foreign key for the Room is in the Events table? Is this where you use a has_many :through relationship? Is it good practice to store both the Building and Room foreign keys in the Event table, as Rooms are owned by Buildings? What about the conditional relationship that requires a building to be specified before allowing a room to be specified (some buildings have 2 rooms, others have 20, for example)
Sorry I'm so unclear on this. Thanks in advance for the help!
class Event < ActiveRecord::Base
belongs_to :building
end
class Building < ActiveRecord::Base
has_many :events
has_many :rooms
end
class Room < ActiveRecord::Base
belongs_to :building
end
I think the best way to handle this is to do something like the following:
class Event < ActiveRecord::Base
belongs_to :room
has_one :building, :through => :room
end
class Building < ActiveRecord::Base
has_many :events
has_many :rooms
end
class Room < ActiveRecord::Base
belongs_to :building
end
So you can use has_one :through to specify that an event owns a hotel
I would recommend the following:
class Event < ActiveRecord::Base
belongs_to :room
has_one :building, through: :room
end
class Building < ActiveRecord::Base
has_many :events, through: :rooms
has_many :rooms
end
class Room < ActiveRecord::Base
belongs_to :building
has_many :events
end
This way you can do #room.events, #event.building, #building.events

Resources