Search code examples
rubyencapsulation

Should I add that method as protected and why?


I would like to override Item`s find_items method in UserItem subclass. Should I add that method as protected or private?

I now that protected methods can be used in subclasses and private only in class to which they belong.

class Item
  def item_ids
    @ids ||= REDIS.zrevrange(key, 0, 100).map(&:to_i)
  end

  def items
    find_items
    item_ids.collect {|id| records.detect {|x| x.id == id}}.compact.map(&:content)
  end

protected
  def items_scope
    Item
  end

  def find_items
    items_scope.find(item_ids)
  end
end

class UserItem < Item
  def initialize(user)
    @user = user
  end
  # should I add it here?
protected
  # or here?
  def items_scope
    Item.where(user_id: @user.id).not_anonymous
  end
end

Method overwriting:

def find_items
  items_scope.where(id: item_ids)
end

Solution

  • Semantics in Ruby differ from what you may have used to. Actually, private means that you cannot specify receiver explicitly for the method, but you can use it from derived classes as well, as long as you don't specify receiver. Thus

    class A
      def bar; 42; end
      private :bar
    end
    
    class B < A
      def foo; bar; end
    end
    

    and B.new.foo works just fine. So, private in Ruby is rather close to protected in other OO languages. I don't even remember what protected was in Ruby; it is very seldom used in Ruby.

    In your example I wouldn't use private for find_items. I would leave it public or turn it into mixin (because it doesn't use instance variables)