2

I am working on a rails app where I have 2 different types of Users (MasterClientUser and AccountManager). I am using single table inheritance to differentiate the users. I have a update_last_seen_at private method that will need to be called on both the AccountManager and the MasterClientUser. I am attempting to put it in the User model but I get the following error:

private method `update_last_seen_at' called for #<MasterClientUser:0x007fc650d2cad0>

The update_last_seen_at method is called from the HomeController:

class HomeController < ApplicationController

  before_action :authenticate_user!, :save_users_access_time, only: [:index]

  def index
    @user = current_user
  end

  def save_users_access_time
    current_user.update_last_seen_at
  end

end

Models

class User < ActiveRecord::Base
end

class MasterClientUser < User

  private

  def update_last_seen_at
    self.update_attributes(last_seen_at: Time.now)
  end

end

class AccountManager < User
end

I have also tried putting the method in a module and including the module in each of the different User types, but I get the same error.

Is there any way that I can share the method for both User types and keep it private without having to put them in each model explicitly?/ is there a better strategy go about solving this issue.

Steve_D
  • 545
  • 2
  • 11
  • 20
  • 3
    Where's the code calling update_last_seen_at? Private methods can't have an explicit receiver. Are you able to write the call without an explicit receiver? – Coenwulf Feb 20 '15 at 16:49
  • Just put it in `User` it will be accessible in all subclasses. If you are getting this error it means that you are calling this method breaking object privacy, so we'll need to see the line of code calling the method. – BroiSatse Feb 20 '15 at 17:06
  • updated to show where the update_last_seen_at method is called – Steve_D Feb 20 '15 at 17:07
  • After the edit - if you want to call a method on a model in the controller, it is not a private method. Why do you want to make it private then? – BroiSatse Feb 20 '15 at 17:07

2 Answers2

1
def save_users_access_time
  current_user.update_last_seen_at
end

You can't call a private method outside the user class it self, that's why you have an issue, you could change that method to a normal public method

Regardless of that, I actually think the whole method is unnecessary, if all that it's going to do is update the last_seen_at field, you could consider using touch instead.

def save_users_access_time
  current_user.touch(:last_seen_at)
end
Mohammad AbuShady
  • 40,884
  • 11
  • 78
  • 89
-1

Define method as protected in the User class, that is going to let to derived classes use it. I think a good (general) explanation of types of methods is this: What is the difference between Public, Private, Protected, and Nothing?, hope it helps you.

though ruby support only this:

Ruby gives you three levels of accessibility:

  1. Public methods can be called by everyone - no access control is enforced. A class's instance methods (these do not belong only to one object; instead, every instance of the class can call them) are public by default; anyone can call them. The initialize method is always private.
  2. Protected methods can be invoked only by objects of the defining class and its subclasses. Access is kept within the family. However, usage of protected is limited.
  3. Private methods cannot be called with an explicit receiver - the receiver is always self. This means that private methods can be called only in the context of the current object; you cannot invoke another object's private methods.
Community
  • 1
  • 1
joseramonc
  • 1,811
  • 2
  • 21
  • 40
  • 1
    That link is to how those scopes are defined for c#, not for ruby. For a better reference see: http://devblog.orgsync.com/2013/05/20/private-and-protected-they-might-not-mean-what-you-think-they-mean/ – Coenwulf Feb 20 '15 at 16:51