Search code examples
ruby-on-railsassociationsruby-on-rails-5activemodel

Selecting one of a has_many relation in Rails


What is the preferred way of selecting a specific record out of a has_many relation for a specific model in Rails? (I'm using Rails 5.)

I have a model User and a model Picture which are related via the following code:

class User < ApplicationRecord
  has_many :pictures, as: :imageable
  # ...
end

class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
  # ...
end

What I want to do is to allow a User to set a profile picture from the images associated with it, so I can call @user.profile_picture on a User object and retrieve the profile picture.


Solution

  • You can add an additional one-to-one relationship.

    # create by running:
    # rails g migration AddPrimaryPictureToUser
    class AddPrimaryPictureToUser < ActiveRecord::Migration[5.0]
      def change
        add_column :users, :primary_picture_id, :integer
        add_index :users, :primary_picture_id
        add_foreign_key :users, :pictures, column: :primary_picture_id
      end
    end
    

    class User < ApplicationRecord
      has_many :pictures, as: :imageable
      # This should be belongs_to and not has_one as the foreign key column is 
      # on the users table
      belongs_to :primary_picture, 
                 class_name: 'Picture',
                 optional: true
    end
    
    
    class Picture < ApplicationRecord
      belongs_to :imageable, polymorphic: true
      has_one :primary_user, 
              foreign_key: 'primary_picture_id',
              class_name: 'User'
      # ...
    end
    

    The main reason to do it this way vs for example a boolean flag on the pictures table is that having a separate relationship makes it easy to join which is important for avoiding N+1 queries which is an issue if you are listing a bunch of users together with their primary image.

    @users = User.includes(:primary_picture).all