What is the best way to configure inheritance in this scenario? - ruby-on-rails

So here is the scenario. Lets say that you have 10 different suppliers that provide products that you sell. Now for this scenario assume that each supplier has their own methods for order processing and each require their own class. This is a big assumption, but I am trying to simplify my real scenario without all of the details.
Solution with Single Table Inheritance (STI)
class Supplier < ActiveRecord::Base
has_many :products
# Methods that can be inherited by each supplier go here
end
class MySupplier1 < Supplier
# Custom per-supplier methods go here
end
class MySupplier2 < Supplier
# Custom per-supplier methods go here
end
What is strange about this solution is that you will have 10 rows in your suppliers table. For example, you will never have more than one instance of MySupplier1.
Here is another solution:
Alternative Modular Solution
class Supplier < ActiveRecord::Base
has_many :products
end
class Suppliers::Base
# Methods that can be inherited by each supplier go here
end
class Suppliers::MySupplier1 < Suppliers::Base
# Custom per-supplier methods go here
end
class Suppliers::MySupplier2 < Suppliers::Base
# Custom per-supplier methods go here
end
With this solution, I like that it feels more modular, but the relationship between the ActiveRecord Supplier and the Suppliers::MySupplier1 is really awkward. Basically, I have to store the supplier class in the suppliers table so I know what class to instantiate for processing.
Does anyone think there is a right or wrong or maybe even a better approach?

Related

How do I add a superclass to two classes in Rails?

In my Rails application I have two classes :
UserPost and GroupPost (inheriting from ApplicationRecord), that I want to make subclasses of a new class, Post.
What would be the best way to add this in?
Is it as simple as making the class manually, and adding in the inheritance or are there problems that could cause?
I'm making the assumption that UserPost and GroupPost are inherited from ActiveRecord::Base, i.e. you want to save them in your DB
If you have class UserPost and GroupPost inherit from Post in the following way, this is known as Single Table Inheritance
class Post < ApplicationRecord
end
class GroupPost < Post
end
class UserPost < Post
end
Rails will, by default, expect you to have a column called "type" (can be configured to any other name) in the Posts table. GroupPost and UserPost will populate their respective values in the same table, adding in "GroupPost" or "UserPost" to the type. You can read up on it here
Rails also provides you the ability to have the parent class be "abstract", i.e. it shouldn't be able to persist to the database. Perhaps you noticed it in the the app/models/application_record.rb file as well. This way the parent serves as just a concept where you can add in common behaviour, STI will not kick in. There will need to be separate tables for children.
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
If you plan on having separate tables for the classes, I'd recommend trying composition instead of inheritance using mixins. Basically you write common functionality in a "module" and include it to the classes that need the separate functionality. Concerns are a nice way to append class methods, associations etc without having to rely on arcane ruby syntax. I'd recommend having a look at the documentation
module Fooable
extend ActiveSupport::Concern
included do |base|
scope :enabled, -> { where(enabled: true) }
has_many :boos, dependent: :destroy
end
class_methods do
def having_name
where('name ILIKE ?', "#{name}%")
end
end
def hi
return 'hi'
end
end
class UserPost < ApplicationRecord
include Fooable
end
UserPost.first.boos # relationship
UserPost.enabled # calling a scope
UserPost.having_name('name') # calling a class method
UserPost.new.hi #calling an instance method

Ruby multiple inheritance needed for rails models

First off, let me say that I know that multiple inheritance is not possible in Ruby, but when I think about it, that's the only way I can see a resolution.
I have 3 separate user classes that all share single-table inheritance. Here they are
class User < ActiveRecord::Base
has_many :notifications
def notify
#code to notify user
end
end
class Student < User
has_many :charges
def charge_user
#code to charge user
end
end
class Teacher < Student
has_many :students
has_many :courses
def create_course
#code to create course
end
end
I want to be able to use each has_many method only once, and the Teacher must inherit all the Student methods
The problem if this is if I run
Teacher.find(1)
I get this error
ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'Teacher'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite User.inheritance_column to use another column for that information.
If I change the teacher class to
class Teacher < User
end
It works, however, now the teacher doesn't have all the has_many methods and normal methods that the student has.

Class inheritance in rails active record

I have a Product table, which has multiple fields like product price, product manufacturer and so on which is common in every item. So I have made a belongs_to relationship with productItem. Every product item has its own specifications. Now I feel the necessity to make few common methods. From the concept of OOP, I have tried to make Parent class Sub class model, where subclass will inherit all the methods of parent. So I have tried doing following:
class Product < ActiveRecord::Base
def check
...
end
end
class ProductItem < Product
belongs_to :product
end
which raises following error:
undefined method `some_field_id' for #<ProductItem:0x007f8cac666850>
So how can I do parent subclass model in rails?
Class inheritance it's not for code sharing, you should rely on mixins for such a thing. Create a module like this, you can put it in app/shared/yourmodule.rb:
module Yourmodule
def dosomething
end
end
class Product
include Yourmodule
end
class ProductItem
include Yourmodule
end
Product.new.dosomething
ProductItem.new.dosomething
You can share attributes through STI though, but STI is recommended only if you share all parent attributes plus a few additional fields, be careful with it.
STI is simple: add (if you don't have it already) a type column to the table you want to inherit from, make it a string and don't set any default and leave it nullable. Now you can just do:
class Product < ActiveRecord::Base
end
class ProductItem < Product
end
You'll be able to access anything from Product

Rails has many and belongs to between two times with same models

I am wondering how to do something so If someone knows I will be glad to hear. I have the following models
User
Usertype
Course
I have two types of users - student and teacher.
What I want to have is two tables
CourseTeacher - course_id, teacher_id
CourseStudent - course_id, student_id
My User model has usertype_id column. So I am wondering how to use has_many_and_belongs_to in that case because everything depends on usertype_id column in User model.
I think class inheritance is a cleaner way to model your domain logic:
class User < ActiveRecord::Base
end
class Student < User
end
class Teacher < User
end
Then the table would have an id and type column, greatly simplifying what you're trying to accomplish. Read the API docs to learn more: Single Table Inheritance
If you don't have ability to refactor, you can try using this approach:
Instead of 2 tables create one:
class CoursesUsers
belongs_to :course
belongs_to :user
end
And the decide yourself logic inside the user model (It seems like polymorphic to me)

How do I insert into different tables from one controller?

I'm developing an application to create a fishbone diagram.
I created several models to handle different levels of causes and effects. The thing is, the application will have one form to introduce data to all the different levels, so how can I do it?
Can I have only one controller to insert info into all the different tables?
Some simple inheritance will do the trick if you are going to be treating them with different logic.
Have a base model
class Bone < ActiveRecord::Base
end
Then three that inherit from it.
class BackBone < Person
end
class RibBone < Person
end
class OutSideBone < Person
end
Then you can handle all three of the classes in the person controller using person as the base. Each will also have their own logic if needed.
If need be you can even do a ownership on to itself, which might be helpful in this case.
class Bone < ActiveRecord::Base
has_many :bones
belongs_to :master_bone, :class_name => "Bone", :foreign_key => "bone_id"
end

Resources