How to setup a association through multiple models - ruby-on-rails

I've the followig three models in Rails:
class Book < ActiveRecord::Base
has_many :chapters
has_many :pages
end
class Chapter < ActiveRecord::Base
belongs_to :book
has_many :pages
end
class Page < ActiveRecord::Base
belongs_to :chapter
end
How is it possible do to a query like: Book.first.pages.count to get the number of pages of the whole book. By now I dont even know if i set my model up the right way. Would be great if you could help me out here.
Thanks in advance!

You can use a has_many through relationship as outlined here
class Book < ActiveRecord::Base
has_many :chapters
has_many :pages, through: :chapters
end
class Chapter < ActiveRecord::Base
belongs_to :book
has_many :pages
end
class Page < ActiveRecord::Base
belongs_to :chapter
end
That enables you to do book.pages.count

The issue may lie in your data model. The associations as listed seem a little odd - a Book has many Chapters and many Pages, but a Chapter can also have many Pages. How do you differentiate between the Pages in a Book compared to a Chapter?

Related

multiple belongs_to models in Rails

I have a comments model that is currently working with Articles. I would now like to have users be able to comment on the Coffeeshop reviews. Am I able to use the same comment table, or should I have a separate one (feels janky). I've not long been building with RoR (a few weeks) so still trying to get the hang of the basics.
Would I nest them in routes.rb (and how)
resources :coffeeshops do
resources :articles do
resources :comments
end
or
resources :coffeeshops do
resources :comments
end
resources :articles do
resources :comments
end
My models look like:
User
class User < ApplicationRecord
has_many :comments
end
Comments
class Comment < ApplicationRecord
belongs_to :user
belongs_to :article
belongs_to :coffeeshop
end
Articles
class Article < ApplicationRecord
has_many :comments, dependent: :destroy
end
Coffeeshops
class Coffeeshop < ApplicationRecord
has_many :comments, dependent: :destroy
I'm then assuming I need a foreign key to tie the user and comments together, and then also the comments to the article/coffeeshop.
I'd use a polymorphic association.
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
class User < ApplicationRecord
has_many :comments
end
class Comment < ApplicationRecord
belongs_to :user
belongs_to :commentable, polymorphic: true
end
class Article < ApplicationRecord
has_many :comments, as: :commentable
end
class Coffeeshop < ApplicationRecord
has_many :comments, as: :commentable
end
For some more information about setting up the routes/controller:
https://rubyplus.com/articles/3901-Polymorphic-Association-in-Rails-5
http://karimbutt.github.io/blog/2015/01/03/step-by-step-guide-to-polymorphic-associations-in-rails/
You can use comment model for both comments for articles and coffeeshops, but (because by default rails uses ids as primary and foreign keys I assume you use ids too) you will have to add column to comments table, where you set the comment type (You can create Enumerator in comment model, where you set 2 possible value types, each for article and coffeeshop models). If you don't add the column it will result in weird, hard to track bug where you can see comments for article on coffeeshop with same id and vise-versa.
UPD: he's little guide on using enums for rails models: http://www.justinweiss.com/articles/creating-easy-readable-attributes-with-activerecord-enums/ you will have to use it not in actual add comment form, but behind the scenes.

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.

Rails relationships setup for 5 table db

I'm stuck in a circle of indecision and need a shove to break free. I'm a noob with Rails and I'm attempting to translate a pre-existing database using Rails conventions. Basically, I currently have 5 models/tables: Workorders, Mileage_logs, Time_logs, Parts, & Equipment. A Workorder can have many Mileage_logs, Time_logs, and Parts, because each of them is shown on the Workorder's index page. But, that's the seemingly easy part...
I'm getting confused when the Equipment model is introduced because it seems like it's basically the same thing as the Workorder.
What is the best way to handle this relationship setup? Is this an appropriate use for the has_many :through convention? Or, is this best done with simply having the workorder_id and equipment_id in the Mileage_log, Time_log, and Part models and then:
class Part < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Mileage_log < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Time_log < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Workorder < ActiveRecord::Base
has_many :Time_logs
has_many :Parts
has_many :Mileage_logs
end
class Equipment < ActiveRecord::Base
has_many :Time_logs
has_many :Parts
has_many :Mileage_logs
end
Or, is the has_many through: relationship what I should look into for the Workorder & Equipment models?
class Workorder < ActiveRecord::Base
has_many :parts
has_many :mileage_logs
has_many :time_logs
end
class Equipment < ActiveRecord::Base
has_many :parts, through: :workorder
has_many :mileage_logs, through: :workorder
has_many :time_logs, through: :workorder
has_many :workorders
end
Any help would be greatly appreciated!
Also, any general advice on the route setup would be welcomed as well.

Use where on has_many :through to find objects with 2 certain child object from different classes (Rails 4)

What I want to do is to get all the
My model:
class User < ActiveRecord::Base
has_many :classes
has_many :professors, :through=>:classes
has_many :cars
has_many :carmodels, :through=>:cars
end
class Professor < ActiveRecord::Base
has_many :classes
has_many :users, :through=>:classes
end
class Class < ActiveRecord::Base
belongs_to :user
belongs_to: professor
end
class Car < ActiveRecord::Base
belongs_to :user
belongs_to :carmodel
end
class Carmodel
has_many :cars
has_many :users, through=>:cars
end
what I want to do is, given a certain Car and Professor, to find all users which contain them.
for example
u1=carmodel.users
u2=professor.users
result=[]
u1.each do |us|
if u2.include? us
result.push us
end
end
Of course this is just an example... I would like to keep working with ActiveRecords(avoid turning it to an array) and, of course, a more optimal solution... I can't seem to find any.
You need to do something like this:
User.joins(:carmodels).joins(:professors)
Thanks for the previous answer! Here is the resulting code:
carmodel #Variable for the wanted carmodel
professor #Variable for the wanted professor
result=User.joins(:carmodels).joins(:professors).where(carmodel:{id:carmodel.id},professors:{id:professor.id})
Thanks again!

Ruby on Rails four-way association tree

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

Resources