I'm working with two different models Person and Organization. Among many other attributes, both a Person and Organization can be a Contractor. If I was working with just the Person model and wanted to store contractor information I would say that Contractor belongs_to :person and be done with it. However this seems like Contractor belongs to two other models.
I searched around on google and found a lot of info about how to assign ownership to two different models at once. (For example a Sale must belong to both a Buyer and a Seller.) But in my situation a Contractor is EITHER a Person or an Organization. Is there any way to elegantly store Contractor information for both models in the same table?
If not, I figure I can always make two different contractor tables, but I figured this might be an opportunity to learn something. Many thanks in advance.
Maybe you can try this. Rails provide polymorphic-associtions. You can try to build one model named ContractorInfo belongs to Contractable(use polymorphic: true), then Person has_one ContractorInfo as contractable, Organization has_one ContractorInfo as Contractable.
I agree with ShallmentMo, but as additional, You could define something like this:
Models
class Contractor < ActiveRecord::Base
belongs_to :contractable, polymorphic: true
...
end
class Person < ActiveRecord::Base
...
has_many :contractors, as: :contractable
...
end
class Organization < ActiveRecord::Base
...
has_many :contractors, as: :contractable
...
end
Migrations
create_table :contractors , force: true do |t|
t.references :contractable, polymorphic: true, index: true
...
t.timestamps null: false
end
Usage
def create
#contractor = Contractor.new(params[:contractor])
contractable = params[:contractor][:contractable].split(":")
#contractor.contractable_type = contractable[0] # String: 'Person' or 'Organization'
#contractor.contractable_id = contractable[1].to_i # Integer: id of 'Person' or 'Organization'
...
Related
Objective: To design a best database table for a Trip
Table 01 : Trip (Columns: id, transport_mode_id....etc)
Table 02: Trains (id, name, number....etc.)
Table 03: Buses(id, name, number....etc)
I want to design a Trip table (transport_mode_id) with either train_id or bus_id. Trip should have either bus_id or train_id.
Should I create a two columns train_id, bus_id ? in the Trip table. Please suggest to design a trip table
What you are looking for is a polymorphic-associations Sometimes trip links to a bus, other times to a train, and planes, and boats.
A slightly more advanced twist on associations is the polymorphic association. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a trip model that belongs to either a train model or a bus model. Here's how this could be declared:
class Trip < ApplicationRecord
belongs_to : transportable, polymorphic: true
end
class Bus < ApplicationRecord
has_many :trips, as: :transportable
end
class Train < ApplicationRecord
has_many :trips, as: :transportable
end
on the Database
class CreateTrips < ActiveRecord::Migration[5.0]
def change
create_table :trips do |t|
...
t.references :transportable, polymorphic: true, index: true
....
end
end
end
if the table all ready exists
class CreateTrips < ActiveRecord::Migration[5.0]
def change
add_reference :trips, :transportable, polymorphic: true, index: true
end
emd
I hope that this helps
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I want to create a base model Person with some person related attributes like name, address, phone and so on. One Person can be one ore more of the following:
LoginUser with fields for login, password, last_login, ...
CardHolder with fields for card_id, last_entrance, ...
Supplier with just a flag whether or not the person is a supplier
Recipient with just a flag whether or not the person is a recipient
Is there a common sense or best practise design pattern in Ruby on Rails to represent that inheritance? How it should be represented in the model(s) and table structure so that it is possible to check whether a Person is a LoginUser and to access the corresponding fields.
In another project I worked already with STI but in this case this isn't the right pattern.
What you're looking for is a reverse polymorphic association. Polymorphic associations allow you to link one model to many different ones. A reverse polymorphic association allows you to link many models to one single one. They're a little tricky to set up, but once you get the hang of it it's no problem.
In order to accomplish this, you need another model that acts as a go-between for the Person model and each of the different roles. This go-between model is the one that actually has the polymorphic association. Your Person model will has_many that model, and your various role models will has_one of it. You then use :through to make the rest of the necessary associations so your code doesn't know any different. Shazam!
Here's an example of how to do it with the Person and CardHolder models. I'm calling the extra model Role because that seems like an obvious choice:
class Person < ApplicationRecord
has_many :roles
# Reach through the Roles association to get the CardHolders, via polymorphic :rollable.
# Unfortunately, you can't has_one, so you'll have to enforce uniqueness in Role
# with a validation.
has_many :card_holders, through: :roles, source: :rollable, source_type: 'CardHolder'
end
class Role < ApplicationRecord
belongs_to :person
# Here is where our actual polymorphic connection is:
belongs_to :rollable, polymorphic: true
end
class CardHolder < ApplicationRecord
# The other side of the polymorphic connection, with has_one:
has_one :role, as: :rollable
# Get the person via the role, just like the inverse:
has_one :person, through: :role
end
The database setup is like this:
class CreatePeople < ActiveRecord::Migration[5.1]
def change
create_table :people do |t|
t.string :name
# put in whatever other Person columns you need
t.timestamps
end
end
end
class CreateRoles < ActiveRecord::Migration[5.1]
def change
create_table :roles do |t|
t.references :person, index: true
t.references :rollable, polymorphic: true, index: true
t.timestamps
end
end
end
class CreateCardHolders < ActiveRecord::Migration[5.1]
def change
create_table :card_holders do |t|
t.integer :card_id
t.datetime :last_entrance
# put in whatever other columns you need
t.timestamps
end
end
end
Using it is quite simple:
> p = Person.create(name: "Sven Reuter")
# directly add a card holder
> p.card_holders << CardHolder.create(card_id: 1, last_entrance: Time.current)
# build a role instead
> p.roles.build(rollable: CardHolder.new(card_id: 2, last_entrance: Time.current)
# get all of the roles
> p.roles
I would go with Person table and the PersonAttributes table that is a union of all the attributes the person might have. PersonAttributes might use STI if applicable, e.g. with LoginUser storing logins and CardHolder referencing Cards.
Clean and simple.
I have a model that could be owned by many other models (It has many foreign keys).
I'm going to try to make a polymorphic function on this model, that will behave depending on who it's owner is. Unfortunately I'm not sure what the active record code would be to find that out, and when I go in binding.pry the self object doesn't have any information I can tell.
So a good example would be Company and Person both have a Tax ID
When the Tax ID model is going to do something, it wants to know who it's owner is. Makes sense?
My actual relationship is a has_many, but I doubt that is the sticking point.
Assuming the following structure,
class Tax
belongs_to :taxable, polymorphic: true
end
class Company
has_many :taxes, as: :taxable
end
class Person
has_many :taxes, as: :taxable
end
create_table :taxes do |t|
t.integer :taxable_id
t.string :taxable_type
t.timestamps
end
each tax record can access its owner using tax.taxable. To get the type, use either
tax.taxable.class.name
or
tax.taxable_type
(With help from #SteveTurczyn and #MrYoshiji.)
class Tax
belongs_to :taxable, :polymorphic => true # tax table needs taxable_type taxable_id
end
class Company
has_one :tax, :as => :taxable
end
class Person
has_one :tax, :as => :taxable
end
Tax.first.taxable
Im not sure i understand rails polymorphic.
In Java you can create Objects from the same Objecttype:
http://www.fh-kl.de/~guenter.biehl/lehrgebiete/java2/j2-08-Dateien/abb.8.10.jpg
Person trainer = new Trainer()
Person sportler = new Trainer()
In Rails http://guides.rubyonrails.org/association_basics.html#polymorphic-associations:
In this example: picture can be from an employee or from a product, sounds strange because this is not realy the same type.
Do i understand the real purpose: to save objects in the same container an array of person or image?
In my rails project: I have several person: sportsmen, trainer and guest. They are sons of person (inheritance).
I think i meet the inheritance reason.
There is another class named exercise.
Sportsmen and trainer can create exercises.
So i want to use polymorphic. Exercises can be from trainer or sportsmen. Like in the example of the rails page, images can be from employee or a product.
Do i meet the best practise?
How do i implement a has_many :through with polymorphy?
It is not possible to use a habtm assoziation with polymorphic.
You have to define a additional class, but how exactly?
I think you want single table inheritance (STI) models, not a polymorphic relationship.
See this article http://www.alexreisner.com/code/single-table-inheritance-in-rails and these stackoverflow answers Rails - Single Table Inheritance or not for Applicant/Employee relationship Alternative to Rails Single Table Inheritance (STI)?
Just to make it clear, you should use polymorphic associations when you have a model that may belong to many different models on a single association.
Suppose, you want to be able to write comments for users and stories. You want both models to be commendable. Here's how this could be declared:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Employee < ApplicationRecord
has_many :comment, as: :commentable
end
class Product < ApplicationRecord
has_many :comment, as: :commentable
end
To declare the polymorphic interface (commendable) you need to declare both a foreign key column and a type column in the model.
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :body
t.integer :commentable_id
t.string :commentable_type
t.timestamps
end
add_index :comments, :commentable_id
end
end
You can check more details about associations here.
I'm modelling a scenario with Users and Tools, where a Tool is owned by one User but can be used by many Users including to one owning it.
I was thinking about adding an owner_id column to Tools and say it has_many Users or by adding a new relationsship table.
I'm really new to Rails and I have problems setting up the right associations in the models though, maybe you can point me in the right direction?
Thank you very much.
Your should add owner_id to the Tools table.
Associations will be like that.
class User < ActiveRecord::Base
has_and_belongs_to_many :tools
end
class Tool < ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :owner, :class_name => 'User'
end
You'll need a tools_users table in order to use habtm-association. Generate a migration and create a table with option id: false and two columns user_id and tool_id:
class CreateToolsUsersTable < ActiveRecordMigration
def change
create_table :tools_users, id: false do |t|
t.integer :tool_id
t.integer :user_id
end
end
end
After that you can call something like #user.tools or #user.owner
Read more there
User has many tools
Tool belongs to user in owner
Tool has many users
is what I would do.
I'm not sure about the wording because I don't use Active Record but this is how it works in other orms