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
Related
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
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.
I have an application where there are multiple ways to handle creating and updating an object based on the user that is logged in. I keep getting a circular reference exception on the child classes. Is this correct or would it be better to create concerns module with shared code and have them both be independent?
class WorkOrder < ActiveRecord::Base
#parent class
end
module Dispatch
class WorkOrder < ::WorkOrder
#child class
end
end
module Service
class WorkOrder < ::WorkOrder
#child class
end
end
How are you planning on differentiating records in the database between being from the parent class or one of the child classes?
You may want to look at Single Table Inheritance (STI) and Polymorphic Associations:
http://railscasts.com/episodes/394-sti-and-polymorphic-associations
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?
I'd like to have a common superclass for two models in ruby, to share several methods. Let's say I want a Truck and Car inheriting from Vehicle. Here are some options:
Make class Vehicle < ActiveRecord::Base, and have class Truck < Vehicle etc. But then I get errors saying I don't have a table for Vehicle (and I don't want one, either).
Use module Vehicle and include Vehicle in class Truck < ActiveRecord::Base. But then attr_reader and friends don't get applied to Truck.
Thus, I want class Vehicle. How do I do this without requiring a table? I'm sure there's a standard, nice way of doing this...
Add a class method called abstract_class? that returns true:
class Vehicle < ActiveRecord::Base
def self.abstract_class?
true
end
end