Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check whether an object is a result of has_one or has_many?

I build a query dynamically, based on either a has_one or has_many relation. So, I can end up with either an object, or CollectionProxy. How can I test, based on this result, whether the query used the has_one or the has_many relation?

I thought of checking the type, but the CollectionProxy's type subclasses the related model's type.

This dynamic query involves calling an attribute on an object, which can be either a has_one or a has_many relation. Something like:

class User < ActiveRecord::Base
  has_one :profile
  has_many :names

user = User.new
attr = 'profile' # or 'names'
user.send(attr) # I want to check whether this is a result of which of the two relations
like image 211
linkyndy Avatar asked Dec 04 '25 14:12

linkyndy


2 Answers

You can use Active Record's reflection:

User.reflect_on_association(:profile)
#=> #<ActiveRecord::Reflection::HasOneReflection:0x007fd2b76705c0 ...>

User.reflect_on_association(:names)
#=> #<ActiveRecord::Reflection::HasManyReflection:0x007fd2b767de78 ...>

Within a case statement:

klass = User
attr = :profile

case klass.reflect_on_association(attr)
when ActiveRecord::Reflection::HasOneReflection
  # ...
when ActiveRecord::Reflection::HasManyReflection
  # ...
end

### OR by macro

case klass.reflect_on_association(attr).macro
when :belongs_to
  # ...
when :has_many
  # ...
when :has_one
  # ...
end

This works based on the association declaration in your model (user.rb), i.e. without accessing the database.

like image 194
Stefan Avatar answered Dec 07 '25 02:12

Stefan


You can actually check the type of the result. You just have to check if it's an ActiveRecord::Base or an ActiveRecord::Associations::CollectionProxy.

Following your example:

class User < ActiveRecord::Base
  has_one :profile
  has_many :names

user = User.new
attr = 'profile'
user.send(attr).is_a? ActiveRecord::Base # true
user.send(attr).is_a? ActiveRecord::Associations::CollectionProxy # false

attr = 'names'
user.send(attr).is_a? ActiveRecord::Base # false
user.send(attr).is_a? ActiveRecord::Associations::CollectionProxy # true

This was tested on a Rails 4.1.4 but the classes are the same since Rails 3, apparently.

like image 41
Brenes Avatar answered Dec 07 '25 03:12

Brenes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!