How to Get Activerecord Associations via Reflection

How to get activerecord associations via reflection

Model.reflections gives information about a model's associations. It is a Hash keyed on the association name. e.g.

Post.reflections.keys # => ["comments"]

Here is an example of some of the information it can be used to access:

Post.reflections["comments"].table_name # => "comments"
Post.reflections["comments"].macro # => :has_many
Post.reflections["comments"].foreign_key # => "message_id"

Note: this answer has been updated to cover Rails 4.2 based on MCB's answer and the comments below. In earlier versions of Rails the reflection's foreign_key was accessed using primary_key_name instead, and the keys for the reflections may be symbols instead of strings depending on how the association was defined e.g. :comments instead of "comments".

ActiveRecord::Reflections methods - modelname_ids

Use String#singularize:

tale_instance_object.send(x.name.to_s.singularize + "_ids") # => [1, 2, 3, ...]

Also, you can use built-in #ids_reader method:

my_model_instance.association(:x).ids_reader # => [1, 2, 3, ...]

Programatically get the class of the belongs_to association in Rails 4

B.reflect_on_all_associations(:belongs_to).map(&:name)

or

b.class.reflect_on_all_associations(:belongs_to).map(&:name)

How to iterate an ActiveRecord object's associated objects

Model name can be converted to object using public_send in case you fetched the association models, check below:

parent_object.reflect_on_all_associations(:has_one).map(&:class_name).each do |model_name|
# assuming that parent_object is the object that has all associations.
obj = parent_object.public_send(model_name)
do_stuff_to_assoc_object(obj)
end

def do_stuff_to_assoc_object(obj)
# I do things to the associated object here
end

As per @Clemens Kofler comment, to avoid double iteration, we can remove the .map as following:

parent_object.reflect_on_all_associations(:has_one).each do |association|
# assuming that parent_object is the object that has all associations.
obj = parent_object.public_send(association.class_name)
do_stuff_to_assoc_object(obj)
end

def do_stuff_to_assoc_object(obj)
# I do things to the associated object here
end

Reference:
https://apidock.com/ruby/Object/public_send

Processing ActiveRecord::Reflections -- some model reflections coming up empty (Rails 4.2)

I couldn't find any resources to guide me through Rails' inner-workings, so instead I went to look at a popular gem that likewise needs to parse through ActiveRecord::Reflections, ActiveModel::Serializer, since it too would likely have to deal with Rails not loading things as it wished. There, I found:

included do
...

extend ActiveSupport::Autoload
autoload :Association
autoload :Reflection
autoload :SingularReflection
autoload :CollectionReflection
autoload :BelongsToReflection
autoload :HasOneReflection
autoload :HasManyReflection
end

Adding this to my concern solved my issues. From the ActiveSupport::Autoload docs: "This module allows you to define autoloads based on Rails conventions (i.e. no need to define the path it is automatically guessed based on the filename) and also define a set of constants that needs to be eager loaded".

Is there a way to list all belongs_to associations?

You could make use of the class's reflections hash to do this. There may be more straightforward ways, but this works:

# say you have a class Thing
class Thing < ActiveRecord::Base
belongs_to :foo
belongs_to :bar
end

# this would return a hash of all `belongs_to` reflections, in this case:
# { :foo => (the Foo Reflection), :bar => (the Bar Reflection) }
reflections = Thing.reflections.select do |association_name, reflection|
reflection.macro == :belongs_to
end

# And you could iterate over it, using the data in the reflection object,
# or just the key.
#
# These should be equivalent:
thing = Thing.first
reflections.keys.map {|association_name| thing.send(association_name) }
reflections.values.map {|reflection| thing.send(reflection.name) }

Ambiguous source reflection for through association error? (Rails)

This error is telling you the relationship between Stuff and Thing is ambiguous because you haven't defined the relationship between Stuff and Foo. This typically looks like this:

class Student
has_many :scheduled_classes
has_many :teachers, through: :scheduled_classes
end

class ScheduledClass
belongs_to :student
belongs_to :teacher
end

class Teacher
has_many :scheduled_classes
has_many :students, through: :scheduled_classes
end

Note that the through value is named after a relationship on the same class.

Get rails associations from console

User.reflect_on_all_associations

This will return an array of associations similar to this:

#<ActiveRecord::Reflection::AssociationReflection:0x00000105575548 @macro=:has_many, @name=:posts, @options={}, @active_record=User(id: integer, login: string), @collection=false>

Sample code:

reflections = User.reflect_on_all_associations
reflections.each do |reflection|
puts ":#{reflection.macro} => :#{reflection.name}"
end


Related Topics



Leave a reply



Submit