CFitz
CFitz

Reputation: 178

How to add attribute/property to each record/object in an array? Rails

I'm not sure if this is just a lacking of the Rails language, or if I am searching all the wrong things here on Stack Overflow, but I cannot find out how to add an attribute to each record in an array.

Here is an example of what I'm trying to do:

@news_stories.each do |individual_news_story|
  @user_for_record = User.where(:id => individual_news_story[:user_id]).pluck('name', 'profile_image_url');
  individual_news_story.attributes(:author_name) = @user_for_record[0][0]
  individual_news_story.attributes(:author_avatar) = @user_for_record[0][1]
end

Any ideas?

Upvotes: 2

Views: 3875

Answers (2)

Alex Sharp
Alex Sharp

Reputation: 533

It looks like you're trying to cache the name and avatar of the user on the NewsStory model, in which case, what you want is this:

@news_stories.each do |individual_news_story|
  user_for_record = User.find(individual_news_story.user_id)

  individual_news_story.author_name = user_for_record.name
  individual_news_story.author_avatar = user_for_record.profile_image_url
end

A couple of notes.

  1. I've used find instead of where. find returns a single record identified by it's primary key (id); where returns an array of records. There are definitely more efficient ways to do this -- eager-loading, for one -- but since you're just starting out, I think it's more important to learn the basics before you dig into the advanced stuff to make things more performant.

  2. I've gotten rid of the pluck call, because here again, you're just learning and pluck is a performance optimization useful when you're working with large amounts of data, and if that's what you're doing then activerecord has a batch api you should look into.

  3. I've changed @user_for_record to user_for_record. The @ denote instance variables in ruby. Instance variables are shared and accessible from any instance method in an instance of a class. In this case, all you need is a local variable.

Upvotes: 0

Mate Solymosi
Mate Solymosi

Reputation: 5967

If the NewsStory model (or whatever its name is) has a belongs_to relationship to User, then you don't have to do any of this. You can access the attributes of the associated User directly:

@news_stories.each do |news_story|
  news_story.user.name  # gives you the name of the associated user
  news_story.user.profile_image_url  # same for the avatar
end

To avoid an N+1 query, you can preload the associated user record for every news story at once by using includes in the NewsStory query:

NewsStory.includes(:user)... # rest of the query

If you do this, you won't need the @user_for_record query — Rails will do the heavy lifting for you, and you could even see a performance improvement, thanks to not issuing a separate pluck query for every single news story in the collection.

If you need to have those extra attributes there regardless:

You can select them as extra attributes in your NewsStory query:

NewsStory.
  includes(:user).
  joins(:user).
  select([
    NewsStory.arel_table[Arel.star],
    User.arel_table[:name].as("author_name"),
    User.arel_table[:profile_image_url].as("author_avatar"),
  ]).
  where(...) # rest of the query

Upvotes: 3

Related Questions