I have a Rails app with two models that are associated:
class Person < ApplicationRecord
has_many :pets
has_many :toys
end
class Pet < ApplicationRecord
belongs_to :person
endI want to fetch an instance variable in Pet from an instance of Person, however I am using metaprogramming to do this. I am using the following code:
<% if form.object.send(association).present? %>
<%= image_tag form.object.send(association).send(preview_url_attribute), class: options[:image_classes] %>
<% end %>In the above example, form.object is an instance of Person. association is the name of the association between A and B (e.g. :pets), and preview_url_attribute is the name of the attribute in Pet that I want to fetch (e.g. :breed).
Is there a better way to do this without using send?
Yes, there is a more concise and readable way to fetch the desired attribute in the associated model without using send. Instead, you can leverage the association methods provided by ActiveRecord associations.
Assuming you have the following code:
class Person < ApplicationRecord
has_many :pets
# ...
end
class Pet < ApplicationRecord
belongs_to :person
# ...
endAnd you want to fetch the preview_url_attribute from the associated pets in the Person model.
You can simplify the code in the view as follows:
<% if form.object.association(association).loaded? && form.object.association(association).any? %>
<%= image_tag form.object.association(association).first.public_send(preview_url_attribute), class: options[:image_classes] %>
<% end %>Here's what changed:
-
Instead of using
send(association)to fetch the associated records, you can useassociation(association)provided by ActiveRecord associations. This method returns an instance ofActiveRecord::Associations::CollectionProxy, which provides access to the associated records. -
The
loaded?method checks if the association has been loaded. This ensures that the associated records are fetched only if they are already loaded, avoiding additional queries. -
The
any?method checks if there are any associated records present. This ensures that the code block is executed only when there are associated records available. -
Finally,
firstis used to fetch the first associated record, andpublic_send(preview_url_attribute)is used to retrieve the value of the desired attribute.
By using the association and the methods provided by ActiveRecord associations, you can achieve the desired result in a more readable and idiomatic way without relying on send.