DEV Community

Jeeho Lee
Jeeho Lee

Posted on

Working with has_many and belongs_to association methods

When using has_many() and belongs_to() to simplify the creation of association methods between models, I wasn't sure if they'd be accurately reflective if the association methods had some additional steps out of the norm. For example, when looking at the many-to-many relationship of users to photos that's linked by a join table of comments, we could possibly write this as a method in the User model:

  def commented_photos
    my_comments = self.comments

    array_of_photo_ids = Array.new

    my_comments.each do |a_comment|
      array_of_photo_ids.push(a_comment.photo_id)
    end

    matching_photos = Photo.where({ :id => array_of_photo_ids })

    unique_matching_photos = matching_photos.distinct

    return unique_matching_photos
  end
Enter fullscreen mode Exit fullscreen mode

However, if we reduce that to:

  has_many(:commented_photos,
    through: :comments,
    source: :photo
  )
Enter fullscreen mode Exit fullscreen mode

It wouldn't be entirely accurate since we're omitting the step of ensuring we return only unique records (i.e. the line where we specify unique_matching_photos = matching_photos.distinct).

We could use the has_many method to create the method commented_photos, and then call the distinct method as a subsequent step, but if we wanted to include distinction within the method like it was initially written, it seems like the version of Rails we're on will determine how that'd be implemented.

For versions prior to Rails 4, you could add the :uniq option within the has_many associations:

  has_many(:commented_photos,
    :through => :comments,
    :source => :photo,
    :uniq => true
  )
Enter fullscreen mode Exit fullscreen mode

However, for more current versions of Rails (up to version 7 at time of this post), we'd now write querying method inside the scope block as such:

  has_many(:commented_photos, -> {distinct},
    through: :comments,
    source: :photo
  )
Enter fullscreen mode Exit fullscreen mode

This was a good reminder on double checking that using associations may save time, but we'll have to be careful to not omit any steps that are "out of the standard", and how scoping would help address these situations.

Top comments (0)