【Tips】Rails の private メソッドになぜ underscore が付くのか

# 【本文】
最近、Rails のソースコードを暇つぶしに読んでいたら、ふと private メソッドの枠組みで underscore の有無があることが気になりました。

参考 URL を読むと、Ruby では private と protected メソッドに使われることが多いそうです。

他のプログラミング言語でも( JavaScript, PHP, Phython etc...)同様のコーディング規約が存在します。これは、boolean を返すメソッドは末尾に`?`を付けたり、破壊的なメソッドは`!`を付けたり、getter メソッドに`=`を付けることと同じ意味ですね。

- 参考URL
    - [Ruby \- Rubyの1文字目がアンダーバー\(\_\)のメソッド定義｜teratail](https://teratail.com/questions/110830)
    - [JavaScript \- \[Javascript\]アンダースコアから始まる変数、関数の意味｜teratail](https://teratail.com/questions/18728)
    - [coding style \- What's the deal with a leading underscore in PHP class methods? \- Stack Overflow](https://stackoverflow.com/Questions/663350/whats-the-deal-with-a-leading-underscore-in-php-class-methods)
    - [code quality \- Should I always use prefix private methods with an underscore in Python? \- Software Engineering Stack Exchange](https://softwareengineering.stackexchange.com/questions/324720/should-i-always-use-prefix-private-methods-with-an-underscore-in-python)


# 【あとがき】
## private メソッドでも underscore が付かないものもある？

underscore はコーディング規約の一種と考えても、Rails のソースコードでは、 underscore が付くものと付かないものが存在します。

Rails と言う巨大なフレームワークなら一定のコーディング規約があると思うのですが、なぜ付かないものがあるのでしょうか？
結論は違いがわかりませんでしたでしたが...

全ての unserscore 付きメソッドに言えることではありませんが、`_assign_attributes`にしろ、`_find_all`にしろ、呼び出し元のメソッドと強く依存しているケースが散見されます。



```ruby:rails/activemodel/lib/active_model/attribute_assignment.rb
...
def assign_attributes(new_attributes)
	unless new_attributes.respond_to?(:each_pair)
		raise ArgumentError, "When assigning attributes, you must pass a hash as an argument, #{new_attributes.class} passed."
	end
	return if new_attributes.empty?

	_assign_attributes(sanitize_for_mass_assignment(new_attributes))
end

alias attributes= assign_attributes

private
	def _assign_attributes(attributes)
		attributes.each do |k, v|
			_assign_attribute(k, v)
		end
	end

	def _assign_attribute(k, v)
		setter = :"#{k}="
		if respond_to?(setter)
			public_send(setter, v)
		else
			raise UnknownAttributeError.new(self, k.to_s)
		end
	end
	...
```

```ruby:rails/actionpack/lib/action_dispatch/routing/url_for.rb
...
def route_for(name, *args)
	public_send(:"#{name}_url", *args)
end

protected
	def optimize_routes_generation?
		_routes.optimize_routes_generation? && default_url_options.empty?
	end

private
	def _with_routes(routes) # :doc:
		old_routes, @_routes = @_routes, routes
		yield
	ensure
		@_routes = old_routes
	end

	def _routes_context # :doc:
		self
	end
...
```

```ruby:rails/actionview/lib/action_view/path_set.rb
...
%w(<< concat push insert unshift).each do |method|
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
    def #{method}(*args)
      paths.#{method}(*typecast(args))
      end
  METHOD
end

...

def find_all(path, prefixes = [], *args)
  _find_all path, prefixes, args
end

...

private
  def _find_all(path, prefixes, args)
    prefixes = [prefixes] if String === prefixes
    prefixes.each do |prefix|
      paths.each do |resolver|
        templates = resolver.find_all(path, prefix, *args)
        return templates unless templates.empty?
      end
    end
    []
  end

  def typecast(paths)
    paths.map do |path|
      case path
      when Pathname, String
        OptimizedFileSystemResolver.new path.to_s
      else
        path
      end
    end
  end
```
## sanitize とは一体？
全くの余談ですが、`#assign_attributes`を見ると、入力値と仮定する new_attributes を`sanitize_for_mass_assignment`を通していることがわかります。つまるところ、new_attributes は、比喩表現として`消毒`される必要があることですよね。

メソッドを見てみると、Storong Parameter 等で許可されていない params が合ったら例外を出すようです。

```ruby:rails/activemodel/lib/active_model/forbidden_attributes_protection.rb
def sanitize_for_mass_assignment(attributes)
	if attributes.respond_to?(:permitted?)
		raise ActiveModel::ForbiddenAttributesError if !attributes.permitted?
		attributes.to_h
	else
		attributes
	end
end
```

他にも activemodel の中を探検すると、`dirty`(汚れた)と呼ばれる module が目につきます。この module は、DB 保存前の入力値を扱う機能であり、例え assign_attributes でインスタンス変数に入力値を割り当てても、元の DB 保存値を取り出せるメソッドが定義されています。

つまるところ、データベースにとって、ユーザの入力値は、粗く汚く悪意ある情報と見ており、それを考慮した上で対応する必要性があることが読み取れます。まぁ読めばわかることではあるのですが、オブジェクトやドメインに対する共通認識を理解することで、コードの理解度を深められるなと思ったところです。

- 参考 URL
	- [データのサニタイズ — CakePHP Cookbook v2\.x documentation](http://caky.de/ja/core-utility-libraries/sanitize.html)
	- [サニタイジング（サニタイズ）とは \- IT用語辞典 e\-Words](http://e-words.jp/w/%E3%82%B5%E3%83%8B%E3%82%BF%E3%82%A4%E3%82%B8%E3%83%B3%E3%82%B0.html)


## `@_`のようにインスタンス変数にも underscore が使われてる？

メモ化等で使用範囲を内部で留めるインスタンス変数に対して、使用されているようです。
今回の private に似た目的ですね。

- 参考 URL
	- [Active Support Core Extensions — Ruby on Rails Guides](https://guides.rubyonrails.org/active_support_core_extensions.html#internal-attributes)
	- [I could quibble with your first sentence\. The local variable \_ can represent more than one block variable e\.g\., \|\_,\_,x\|, whereas other variables used that way \(e\.g\., \|a,a,x\|\) will raise Syntax Error: duplicated argument name\.](https://stackoverflow.com/questions/36551735/instance-variables-that-start-with/36551986#36551986)