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.
Related
I'm having trouble with a single table inheritence (STI) data model where a model can be one of the types OR both. I can add a third type, which would be something like TradingCompanyClearingMember but then I need to duplicate code from both models into the 3rd. Where this becomes especially difficult is defining polymorphic relationships. Is there an easier / better way / alternatives to consider to model this behavior?
class Company < ActiveRecord::Base
validates :type, inclusion: %w(TradingCompany ClearingMember TradingCompanyAndClearingMember)
end
class TradingCompany < Company
has_many :traders, as: :tradeable
belongs_to :clearing_member
end
class ClearingMember < Company
has_many :trading_companies
has_many :contacts
end
class TradingCompanyAndClearingMember < Company
# copied clearing member relationships
has_many :trading_companies
has_many :contacts
# copied trading company relationships
has_many :traders, as: :tradeable
belongs_to :clearing_member
end
class Trader
belongs_to :tradeable, polymorphic: true
end
The closest thing ruby has to multiple inheritance is mixing in modules. You might be able to put the TradingCompany code into a TradingCompanyModule which you import into both trading company type classes. But I think you're probably better served making Company have one TradingCompany and one ClearingMember instead of using inheritance.
You can create a concerns module and include it the models you require it.
module Trader
extend ActiveSupport::Concern
has_many :trading_companies
end
class TradingCompanyAndClearingMember < Company
include Trader
end
class ClearingMember < Company
include Trader
end
I have a class/model called User which (using Single table inheritance) has a subclass called Student (among others)
Student has a 'has_one' association with 'HomeAddress' which is a subclass of 'Place'
My model set up:
class User < ActiveRecord::Base
end
class Student < User
has_one :home_address, :dependent => :destroy
accepts_nested_attributes_for :home_address
end
class Place < ActiveRecord::Base
end
class HomeAddress < Place
belongs_to :student
end
In my Students controller, I'm trying to create a new Student and associated HomeAddress to pass through to my view:
class StudentsController < ApplicationController
def new
#student = Student.new
#student.build_home_address
end
however, I get an error:
:uninitialized constant Student::HomeAddress
This issue is clearly with the line #student.build_home_address but I don't understand why it's causing this error. I've checked all of naming conventions (i.e. models, controllers, associations) and have other nested attributes relationships working in my app. Perhaps there is an issues with having nested attributes for an STI subclass? (i.e. HomeAddress)
Let me know if you would like to see any other code.
Thanks.
I was trying to find answer on my question, but didn't success with it.
I have models Event, participants, participation_form, invitation, user.
Event has_many participants
User has_many invitations
User has_many participation_form
For Participant I want to have field like "based_on" and it will be references with invitation or participation_form.
I have one idea about it - make two fields and one model method that will be check which field contains value and return "based_on"
My question is - is there any way to reference one model to two models with pair of fields - class (model name) and value (id) so I will add another type if I need it in future.
You could use polymorphic associations for that: (http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
Could you tell more about models relations so I can write some example? Why do you need Participant model?
As mentioned byKuba Ploskonka, you'll probably benefit from a polymorphic association here:
--
Setup
For Participant I want to have field like "based_on" and it will be references with invitation or participation_form.
As per your specifications, you'll want to use the following:
#app/models/participation.rb
Class Participation < ActiveRecord::Base
belongs_to :participle, polymorphic: true
end
#app/models/invitation.rb
Class Invitation < ActiveRecord::Base
has_many :participations, as: :participle
end
#app/models/participation_form.rb
Class ParticipationForm < ActiveRecord::Base
has_many :participations, as: :participle
end
This will give you the ability to save your objects as follows:
#app/controllers/invitations_controller.rb
Class InvitationsController < ApplicationController
def create
#invitation = Invitation.new invitation_params
#invitation.participations.build #-> will save a blank "Participation" object
#inviation.save
end
end
More specifically, let's say I have a model
class User < ActiveRecord::Base
:has_many => (xxxImages)
end
Where xxx can be one of different models in my application. For example:
class ABCImages < ActiveRecord::Base
:belongs_to => User
end
class EFGImages < ActiveRecord::Base
:belongs_to => User
end
What I'm basically asking is: is there any way to pick one of those models at runtime to be inserted into the User models has_many association? Or do I need to take the polymorphic route (which I've only read about slightly so I'm not too familiar with it yet)
Thanks!
I think Single Table Inheritance is the way you should go which will harness the power of having different models but rather store in the same table. The only thing needed for this is to add a database field called :type.
So, in you case, I would create a table names base_images and other two classes would be just a subclass of this class.
So, the migration for this base class would look like this,
class CreateBaseImages < ActiveRecord::Migration
def change
create_table :base_images do |t|
t.string :type
t.string :url
t.references :user
t.timestamps
end
end
end
Now, after you migrate this, it will create a model base_image.rb, as below,
class BaseImage < ActiveRecord::Base
belongs_to :user
end
That's it. Now, that we have the BaseImage we will create two different models namely AbcImage and EfgImage which would inherit from BaseImage class.
class EfgImage < BaseImage
end
class AbcImage < BaseImage
end
And our user class would look like this,
class User < ActiveRecord::Base
has_many :base_images
has_many :abc_images
has_many :efg_images
end
With this code in place, you can create association called abc_images or egf_images to user through association which works like a single table. And if you were to call base_images, it would fetch all the images, irrespective of which subclasses they belong.
You will find this so much resuable that later if you intend to create hij_images association then creating class HijImage and inheriting it from the BaseImage class and it simply works. By, the way there is no magic here, rails stores the name of the class into the type field in database. And so when you query for a certain class, it creates the predicate with type and the name of the class.
Assuming a typical has_many association
class Customer < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :customer
end
How can I add a method to the collection of orders? For the sake of code organization, I'm trying to reactor this method (this is a made-up example) inside of my Customer class:
def update_orders
ThirdPartyAPI.look_up(self.orders) do |order|
# Do stuff to the orders
# May need to access 'self', the Customer...
end
end
I don't like this because it puts a lot of knowledge about the Order class inside my Customer class. I can't use an instance method off of an order, since the ThirdPartyAPI can do a batch lookup on multiple orders. I could make a static method off of Order and pass in the array of orders, and their parent customer, but this feels clunky.
I found this in the rails docs, but I couldn't find any good examples of how to use this in practice. Are there any other ways?
I think this should do it
has_many :entities do
def custom_function here
end
def custom_function here
end
end