Rails before version 6

note Rails 6 is not released yet !!

class User < ActiveRecord::Base
  has_one :profile
  delegate :first_name, to: :profile

  def age
    Date.today.year - date_of_birth.year
  end

  private
  private *delegate(:date_of_birth, :religion, to: :profile)

  def other_security_info
    # ...
  end
end

User.new.age        # => 2
User.new.first_name # => Tomas
User.new.date_of_birth # NoMethodError: private method `date_of_birth' called for #<User:0x00000008221340>
User.new.religion # NoMethodError: private method `religion' called for #<User:0x00000008221340>
User.new.other_security_info # NoMethodError: private method `other_security_info' called for #<User:0x00000008221340>

source:

After Rails 6

note Rails 6 is not released yet !!

After this PR in Rails 6.0 you can do:


class User < ActiveRecord::Base
  has_one :profile
  delegate :first_name, to: :profile
  delegate :date_of_birth, :religion, to: :profile, private: true

  def age
    Date.today.year - date_of_birth.year
  end

  private

  def other_security_info
    # ...
  end
end

User.new.age        # => 2
User.new.first_name # => Tomas
User.new.date_of_birth # NoMethodError: private method `date_of_birth' called for #<User:0x00000008221340>
User.new.religion # NoMethodError: private method `religion' called for #<User:0x00000008221340>
User.new.other_security_info # NoMethodError: private method `other_security_info' called for #<User:0x00000008221340>

How NOT to do it

There is misconception amongs developers that you can place delegate on new line after private:

class Bar
   def car
      12
   end
end

class Foo
   # plain delegate after private
   private
   delegate :car, to: :bar

   def bar
     Bar.new
   end
end

Foo.new.car
#=> 12

Foo.new.public_methods - Object.new.public_methods 
#=> [:car]

As you can see this does not work !!!

To learn more read https://github.com/rails/rails/pull/31944