Where to Place Private Methods in Ruby

Where to place private methods in Ruby?

The best practice in my point of view is to go sequentially and declare your methods without keeping private in point of view.

At the end, you can make make any method private by just adding: private :xmethod

Example:

class Example
def xmethod
end

def ymethod
end

def zmethod
end

private :xmethod, :zmethod

end

Does this justify your question?

How to define a private method in Ruby?

It's fairly standard to put private/protected methods at the bottom of the file. Everything after private will become a private method.

class MyClass

def a_public_method

end

private

def a_private_method
end

def another_private_method
end

protected
def a_protected_method
end

public
def another_public_method
end
end

As you can see in this example, if you really need to you can go back to declaring public methods by using the public keyword.

It can also be easier to see where the scope changes by indenting your private/public methods another level, to see visually that they are grouped under the private section etc.

You also have the option to only declare one-off private methods like this:

class MyClass

def a_public_method

end

def a_private_method
end

def another_private_method
end
private :a_private_method, :another_private_method
end

Using the private module method to declare only single methods as private, but frankly unless you're always doing it right after each method declaration it can be a bit confusing that way to find the private methods. I just prefer to stick them at the bottom :)

Private methods in Ruby

Private methods cannot be called with an explicit receiver. But they can be called by any subclasses and instances of the class.

Here's a nice explanation of public, protected and private methods in Ruby.

Understanding private methods in Ruby

Here's the short and the long of it. What private means in Ruby is a method cannot be called with an explicit receivers, e.g. some_instance.private_method(value). So even though the implicit receiver is self, in your example you explicitly use self so the private methods are not accessible.

Think of it this way, would you expect to be able to call a private method using a variable that you have assigned to an instance of a class? No. Self is a variable so it has to follow the same rules. However when you just call the method inside the instance then it works as expected because you aren't explicitly declaring the receiver.

Ruby being what it is you actually can call private methods using instance_eval:

class Foo
private
def bar(value)
puts "value = #{value}"
end
end

f = Foo.new
begin
f.bar("This won't work")
rescue Exception=>e
puts "That didn't work: #{e}"
end
f.instance_eval{ bar("But this does") }

Hope that's a little more clear.

-- edit --

I'm assuming you knew this will work:

class Foo
def public_m
private_m # Removed self.
end
private
def private_m
puts 'Hello'
end
end

Foo.new.public_m

Calling a private instance method from a class method in Ruby

Using private or protected really don't do that much in Ruby. You can call send on any object and use any method it has.

class Foo
def Foo.bar(my_instance, n)
my_instance.send(:plus, n)
end
end

How to access private methods

Yes, this is possible with Kernel#send:

receiver.send :method_name, parameters

Though there are workarounds like BasicObject#instance_eval, or Kernel#binding manipulations, the common way to call private method is to call send on the receiver.

Working with private methods in ruby on rails

You can make them class methods to call them in your controllers.

 private 

def self.create_notification_on_accept(event)
# I don't know where are you getting participant id, so pass it if you need
# additionally, if they are available on event object then you could do
# event.participant.id, event.user_id since the background of the code is not given
# hence I'm making some assumptions
event.notifications.create(action_type: "Accept", actor_id: participant.id,
user_id: user_id)
end

def self.create_notification_on_reject(event)
event.notifications.create(action_type: "Reject", actor_id: participant.id,
user_id: user_id)
end

And in your controller you can do this

def accept_invitation
#find event so you can pass it as a param
Event.create_notification_on_accept(event)
@participants.where(user_id: current_user.id).update_all(is_attending: true)
render "update"
end

However, a better thing to do this would be to have callbacks instead of class methods. That way you can reduce the overhead of calling the method everywhere, instead you can leave it onto the model to know when to call.

Is Ruby private method accessible in sub class?

Here's a brief explanation from this source:

  1. Public methods can be called by anyone---there is no access control. Methods are public by default (except for initialize, which 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.
  3. Private methods cannot be called with an explicit receiver. Because you cannot specify an object when using them, private methods can be called only in the defining class and by direct descendants within that same object.

This answer from a similar question expands on the topic in more detail: https://stackoverflow.com/a/1565640/814591

How to create a private class method?

private doesn't seem to work if you are defining a method on an explicit object (in your case self). You can use private_class_method to define class methods as private (or like you described).

class Person
def self.get_name
persons_name
end

def self.persons_name
"Sam"
end

private_class_method :persons_name
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name

Alternatively (in ruby 2.1+), since a method definition returns a symbol of the method name, you can also use this as follows:

class Person
def self.get_name
persons_name
end

private_class_method def self.persons_name
"Sam"
end
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name


Related Topics



Leave a reply



Submit