23

Coming from a long history of C-style syntax and now trying to learn Ruby (on Rails), I've been having my share of issues with its idioms and such, but today I hit one I didn't expect to have a problem with and I can't see whatever it is that must be right in front of my face.

I have a Binary class that includes a private method to derive a URI value from a path value (uri and path are attributes of the class). I'm calling self.get_uri_from_path() from within Binary.upload(), but I get:

Attempt to call private method

A snippet of the model looks like this:

class Binary < ActiveRecord::Base
  has_one :image

  def upload( uploaded_file, save = false )
    save_as = File.join( self.get_bin_root(), '_tmp', uploaded_file.original_path )

    # write the file to a temporary directory
    # set a few object properties

    self.path   = save_as.sub( Rails.root.to_s + '/', '' )
    self.uri    = self.get_uri_from_path()
  end

  private

  def get_uri_from_path
    return self.path.sub( 'public', '' )
  end
end

Am I making the call incorrectly? Am I missing something else that's even more fundamental? The only place that Binary.get_uri_from_path() is being called from - at the moment - is Binary.upload(). I'd expect to be able to call a private method from within the same class unless Ruby does something markedly different from other languages I've used.

Thanks.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Rob Wilkerson
  • 40,476
  • 42
  • 137
  • 192

3 Answers3

46

Don't do

self.get_uri_from_path()

do

get_uri_from_path()

Because...

  class AccessPrivate
    def a
    end
    private :a # a is private method

    def accessing_private
      a              # sure! 
      self.a         # nope! private methods cannot be called with an explicit receiver at all, even if that receiver is "self"
      other_object.a # nope, a is private, you can't get it (but if it was protected, you could!)
    end
  end

via

marcgg
  • 65,020
  • 52
  • 178
  • 231
  • 1
    Thanks. A little more digging helped me understand the differences in private methods of Ruby vs. other languages. I just didn't expect differences at that level. – Rob Wilkerson Aug 19 '09 at 17:23
  • you're welcome. It's true it's a bit more tricky, but it actually makes sense after a while :) – marcgg Aug 19 '09 at 17:25
  • I'm finding that a lot of Ruby is terrific - laconic, yet expressive - but I'm definitely having to fight through the idiom deltas. :-) – Rob Wilkerson Aug 19 '09 at 22:37
1

I believe that the proper idiom in this case is not self.get_uri_from_path() but rather simply get_uri_from_path(). The self is redundant. Further notes: * self.path calls the path method on self, which is presumably defined in the parent class. If you had wanted to access the instance variable directly, you could have said @path. (@ is the sigil for instance variables.) * Parentheses for method arguments are optional except where their absence would cause ambiguity. You could, if you chose, replace get_uri_from_path() with get_uri_from_path. This stands in contrast to Javascript, where a function with no parens represents that function as a value rather than an application of that function.

Thom Smith
  • 13,916
  • 6
  • 45
  • 91
  • Yeah, I'm aware of the optional parens, but I keep seeing stuff without them and I don't like the ambiguity. Is it a variable or is it a method? I'd rather not have to ask myself that question every time I see it. Maybe that gets easier over time. – Rob Wilkerson Aug 19 '09 at 22:39
1

there is a heck though where you can call private method in any situation, that being:

object.send(:private_method)

I believe 1.9 has a different implementation of this trick

penger
  • 3,861
  • 1
  • 16
  • 11