Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a has_many association getter

A user can have several cars -

  • User: has_many :cars
  • Car: belongs_to :user

Every time I call @user.cars it returns the list of cars in default search order.

If I wanted the association sorted on some arbitrary field, I could do

class User < ActiveRecord::Base
  has_many :cars, -> { order :num_wheels }
end

But let's say my ordering logic is complex and I want to just override the association getter to implement my own logic

I try something something like -

class User < ActiveRecord::Base
  has_many :cars

  def cars
    # Pretend this is complex logic
    cars.order(:num_wheels)
  end
end

However that obviously fails because you can't reference the original cars from inside the overridden cars method without it looping infinitely.

Is there a way to reference the "original" getter from inside my overridden getter?

Thanks!

like image 584
user2490003 Avatar asked Apr 22 '16 00:04

user2490003


2 Answers

Use super:

class User < ActiveRecord::Base
  has_many :cars

  def cars
    # Pretend this is complex logic
    super.order(:num_wheels)
  end
end

when you use a macro like has_many, Rails dynamically creates a module(which could be accessed by User.generated_association_methods).In your case, define the accessors and readers(such as "cars" in your case, which could be accessed by User.generated_association_methods.instance_methods). This module becomes the ancestor of your User class, so you can access the reader method(cars) by "super" in your own cars method.

like image 106
lei liu Avatar answered Nov 16 '22 05:11

lei liu


With my understanding I believe what has_many is essentially doing is:

Class User < ActiveRecord::Base
  has_many :cars

  # is essentially
  def cars
    Car.where(user_id: self.id)
  end
end

So when a user wants to list all the cars it would still be User.cars. When using ActiveRecord the has_many is assuming both the method name of cars and the foreign keys associated.

like image 4
Joe Marion Avatar answered Nov 16 '22 04:11

Joe Marion