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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With