Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I delegate to scope ? rails

I have :

class UserItem < ActiveRecord::Base

  belongs_to :user
  belongs_to :item

  scope :equipped, -> { where(equipped: true) }
end

class Item < ActiveRecord::Base
   has_many :user_items
   has_many :users, through: :user_items

   scope :armor, -> { where(type: 'Armor') }
   delegate :equipped, to: :user_items

end

EDIT:

If i try

User.first.items.equipped => undefined method 'equipped' for #<ActiveRecord::Associations::CollectionProxy []>

User.first.items.armor.equipped => undefined method 'equipped' for #<ActiveRecord::AssociationRelation []>

How can I delegate to scope?

like image 969
Matrix Avatar asked Mar 25 '16 00:03

Matrix


1 Answers

You can't easily delegate to scopes, nor would you want to since it would return objects from the targeted class (UserItem), not the child.

Instead, you can merge scopes very simply:

class UserItem < ActiveRecord::Base
  scope :equipped, -> { where(equipped: true) }
end

class Item < ActiveRecord::Base
  scope :equipped, -> {joins(:user_items).merge(UserItem.equipped)} 
end

=> Item.equipped
=> collection of items for which they have a user_item association that is equipped

Edit: some documentation on this feature.

Using Named Scopes Across Models with ActiveRecord#Merge http://apidock.com/rails/ActiveRecord/SpawnMethods/merge

Edit again:

If you REALLY want to return a collection of UserItems from a method you call on Item, then you can do as follows:

class Item
  class << self
    delegate :equipped, to: :UserItem
  end 
  ...

But this will return UserItems in a collection, not Items. Which begs the question of why delegate this at all? If you want a collection of Items, and you want to limit those items by a collection of equipped UserItems, then use merge.

like image 103
Matt Avatar answered Oct 13 '22 11:10

Matt