How to cast an ActiveRecord object to another class when using STI?
Asked Answered
A

4

26

I'm currently using ActiveRecord single table inheritance.

How can I cast one of my models from type A to B? They have the same parent.

Actaeon answered 6/8, 2010 at 21:30 Comment(1)
There should be no need to cast.Ideologist
P
52

#becomes is what you are looking for:

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-becomes

Peplum answered 6/8, 2010 at 22:59 Comment(5)
It looks like becomes is now deprecated. Do you know if there is a method that can take its place - apidock.com/rails/ActiveRecord/Base/becomesChrist
api.rubyonrails.org/classes/ActiveRecord/… not deprecated, just moved.Peplum
This is not casting.Akins
If you want to be pedantic, casting is the wrong word for use here, it achieves what this person wants.Peplum
@schmijos, independently of how data is persisted, how is "converting one data type into another" not casting? omar, why is the word wrong?Broadside
D
5

You shouldn't need to cast since Ruby does not perform any type-checking at compile time. What are you trying to accomplish?

Say you have a class Dad, and child classes Son and Daughter.

You could just have a variable @dad and store in it either a Son or Daughter object, and just treat it as if it were a Dad. As long as they respond to the same methods, it makes no difference. This is a concept called "duck typing".

Dispatcher answered 6/8, 2010 at 22:23 Comment(3)
I don't exactly remember why I did this question, but if I remember well it is needed when you have a STI relationship with a polymorphic association, or else it is saved with the wrong type field.Actaeon
Ruby does not, however, Rails does github.com/rails/rails/blob/…Wellesley
Sometimes (usually) the child classes have more methods than the parent class, so if you need to access one of those methods, you have to cast it to the appropriate class.Zone
C
3

If we have something like following

class A < ApplicationRecord
end

Class B < A
end

we can use becomes

a = A.first
b = a.becomes(B)

or vice versa

Crossing answered 19/6, 2020 at 8:9 Comment(0)
N
-2

Create a new instance of B to setting the values for attributes it shares with A.

Something like:

class C < ActiveRecord::Base
end

class A < C
end

class B < C
end

@a = A.new(...)
@b = B.new(@a.attr1, @a.attr2, ..., @a.attrN)
None answered 6/8, 2010 at 21:52 Comment(5)
This is not casting... is it?Ideologist
@Webbisshh No, it's not. This is an approximation for the particular problem posed in the question.None
becomes is implemented like this except that it copies more than just the attributes. See api.rubyonrails.org/classes/ActiveRecord/… and view the source code.Harry
but it doesnt copy relations.. like user.post_idsSech
It's inheritance, it's not casting - the casting would allow to turn the object of class B to class A.Glycerol

© 2022 - 2024 — McMap. All rights reserved.