How to organize a connection, with 2 classes - ruby-on-rails

class Category
has_many :services
end
class Service
belongs_to :category
belongs_to :order
end
class Order
has_many :services
end
How to organize a connection, where I can refer to orders from an object of the category,
It is natural that orders are specifically in this category for services that are
they have.
For example:
category = Category.first
category.orders

Use has_many :through.
class Category
has_many :services
has_many :orders, through: :services
end
I recommend you take a look at the Rails association basics guide.

Related

Rails habtm joins

I have this relationship between categories, products & brands:
class Brand < ActiveRecord::Base
has_many :products
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
belongs_to :brand
end
How can I select all categories by specified brand with this relations?
I try this but get an error
b = Brand.find(1)
Category.joins(:products).where(:products => b.products)
You did the right thing with the join, just add a more complex where definition:
Category.joins(:products).where(:products => {:brand_id => 1})
Controversially HABTM's are rarely, if ever, a good design and IMO just about the only thing Rails got wrong.
Introduce an xref table to join products and categories and use has_many :through on both sides of the relationship so you end up with
class Brand < ActiveRecord::Base
has_many :products
has_many categories :through => products # This is now allowed in Rails 3.x and above
end
class Category < ActiveRecord::Base
belongs_to :product_category
has_many :products :through => product_category
end
class Product < ActiveRecord::Base
belongs_to :brand
belongs_to :product_category
has_many :categories :through => product_category
end
class ProductCategory < ActiveRecord::Base
has_many :products
has_many :categories
end
This gives you the best flexibility with the least amount of code re-factoring for you plus a much more intuitive path to get whatever data you need on either side of the relationship and will enable you to achieve the following
b = Brand.find(1)
b.categories.all
Update
The above is totally untested code and I have just corrected a glaringly stupid mistake I made. If you have any issues implementing this then come back

Rails: Jumping across two belongs_to associations

Say I have three models...
Product
belongs_to :ProductCategory
belongs_to :Manufacturer
ProductCategory
has_many :products
Manufacturer
has_many :products
I'd like to ask an instance of ProductCategory for the set of Manufacturers for Products in that ProductCategory with a call like product_category.manufacturers.
I've currently implemented it in the Products model like this:
def manufacturers
Manufacturer.find(self.products.pluck(:manufacturer_id).uniq.to_a
end
Is there a better "rails way"?
Thanks!
Yes, this is an extremely well-solved problem and a fundamentally basic part of using Associations in Rails. You want has_many :through:
class ProductCategory
has_many :products
has_many :manufacturers, :through => :products
end

How to set up associations in Ruby on Rails?

I'm building a sample app for practice and am having trouble determining the best way to organize my models and associations. So let's just say I have 3 models:
Schools
Classes
Students
I want:
schools to have many classes
classes to have many students
classes to belong to a school
students to be enrolled in many classes in many different schools
The associations are making me dizzy, I'm not sure which ones to use. Help would be greatly appreciated.
Renamed class to course, as the class name Class is already taken. A join class such as enrollments would handle your many to many course <=> student relationship.
class School
has_many :courses
end
class Course
belongs_to :school
has_many :enrollments
has_many :students, :through => :enrollments
end
class Student
has_many :enrollments
has_many :courses, :through => :enrollments
end
class Enrollment
belongs_to :course
belongs_to :student
end
Your models should looks like this:
class School < ActiveRecord::Base
has_many :classes
has_many :students, :through => :classes
end
class Class < ActiveRecord::Base
belongs_to :school
has_and_belongs_to_many :students
end
class Student < ActiveRecord::Base
has_and_belongs_to_many :classes
end
Make sure your Student and Class tables have class_id and school_id columns respectively.
Also, Class is a reserved word in Rails, so it might cause problems (you might have to use a different name)
Though on first blush it would seem students should belong directly to class, class isn't really a true "has_and_belongs_to_many" replacement. For that I would use "enrollment". (Note with rails 3.1 you can now do nested :through calls.)
Here's a slightly more advanced implementation than the previous commenter's:
class School << ActiveRecord::Base
has_many :academic_classes
has_many :enrollments, :through => :academic_classes
has_many :students, :through => :enrollments, :uniq => true
end
class AcademicClass << ActiveRecord::Base
belongs_to :school
has_many :enrollments
end
class Enrollment << ActiveRecord::Base
belongs_to :academic_class
belongs_to :student
end
class Student << ActiveRecord::Base
has_many :enrollments
has_many :academic_classes, :through => :enrollments
has_many :schools, :through => :academic_classes, :uniq => true
end

Rails 3 Abstract Class vs Inherited Class

In my rails 3 model, I have two classes: Product, Service. I want both to be of type InventoryItem because I have another model called Store and Store has_many :InventoryItems
This is what I'm trying to get to, but I'm not sure how to model this in my InventoryItem model and my Product and Service models. Should InventoryItem just be a parent class that Product and Service inherit from, or should InventoryItem be modeled as a class abstract of which Product and Service extend from.
Thanks in advance for the advice!
Personally, I would not use inheritance. Why don't you just say
has_many :services
has_many :products
Inheritance is pretty expensive - both in terms of runtime and often in readability too. This case sounds like a very basic case for which no inheritance is required. Do you really want products and services to actually INHERIT something from a base class? What you writes indicates all you want is to establish the association.
I'd use neither, and follow what Mörre suggested to have InventoryItem be a join model:
class Store
has_many :inventory_items
has_many :products, :services, :through => :inventory_items
end
class InventoryItem
belongs_to :store
belongs_to :products, :services
end
class Product
has_many :inventory_items
has_many :stores, :through => :inventory_items
end
class Service
has_many :inventory_items
has_many :stores, :through => :inventory_items
end

How to create a has_many relationship between two models, with several models in between? (Ruby on Rails ActiveRecord)

What I'd like to do is join one model to another using two intermediary models in between..Here's the abstraction:
Country has_many Companies
Company has_many Buildings, Company belongs_to Country
Building has_many Rooms, Building belongs_to Company
Room belongs_to Building
I want to be able to do Country.first.rooms, so I thought the Country model would be as simple as:
class Country < ActiveRecord::Base
has_many :companies
has_many :buildings, :through=>:companies
has_many :rooms, :through=>:buildings
end
However, this tries to generate SQL like:
SELECT * FROM rooms INNER JOIN buildings ON rooms.building_id = building.id WHERE ((building.country_id = 1))
Obviously, building.country_id does not exist. How do I get around this?
The built in association methods won't help you here. You need to build the query explicitly using joins:
class Country - ActiveRecord::Base
has_many :companies
has_many :buildings, :through=>:companies
def rooms
Room.all :joins => { :building => { :company => :country } }, :conditions => { "countries.id" => id }
end
end
This will require the belongs_to associations to be set up on the Building and Company models
Try using nested has many through
This is possible after Rails 3.1. The below code works for me. It's important to specify the has_many at each level.
class Country
has_many :companies
has_many :buildings, through: :companies
has_many :rooms, through: buildings
end
class Company
has_many :buildings
end
class Building
has_many :rooms
end
class Room
end

Resources