備忘録 2020/04/22

## 内容一覧
* [Arrayのオブジェクトのpluckと、ActiveRecordオブジェクトのpluck](#Arrayのオブジェクトのpluckと、ActiveRecordオブジェクトのpluck)
* [vimのswapファイルとsshの接続](#vimのswapファイルとsshの接続)
* [メソッドの定義場所の探索](#メソッドの定義場所の探索)


## Arrayのオブジェクトのpluckと、ActiveRecordオブジェクトのpluck

今までpluckはActiveRecordオブジェクトに対してしか使っていなかったが、Arrayに対しても使えることがわかった。

```
pry(main)> [{id: 1}, {id: 2}].pluck(:id)
=> [1, 2]
```
当たり前だがActiveRecordと違ってsqlが発行されない。
`Brakeman`で指摘された以下のようなコードにて、[Rails SQL Injection](https://rails-sqli.org/)のPluck Methodに記載の例の通りに試してみたが、うまくいかなかった。

```
# コード例
Mask.all.uniq.pluck(params[:target])

pry(main)> params = {}
pry(main)> params[:target] = "name FROM users--"
pry(main)> Mask.all.uniq.pluck(params[:target])
 Mask Load (0.3ms)  SELECT `masks`.* FROM `masks`
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
```

`uniq`があることによってArrayオブジェクトになっているからだとわかった。

```
pry(main)> Mask.all.uniq.class
  Mask Load (0.5ms)  SELECT `masks`.* FROM `masks`
=> Array

pry(main)> Mask.all.class
=> Mask::ActiveRecord_Relation

pry(main)> Mask.all.pluck(params[:target])
  (0.4ms)  SELECT name FROM users-- FROM `masks`
=> ["太郎", "一郎", "二郎". "三郎", "四郎", "五郎", .....]
```

ちなみに`Non-attribute arguments will be disallowed in Rails 6.0`らしい。

```
pry(main)> Mask.all.pluck(params[:target])
DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "name FROM users--". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql(). (called from <main> at (pry):9)
```



## vimのswapファイルとsshの接続

vimでファイルを編集のまま、保存せずにしばらく放置していたらssh接続が切れてしまったが、swapファイルから作業内容を復元。
今までswapファイルってなんか邪魔だなと思っていましたが、初めて役に立ちました。
> https://nanasi.jp/articles/howto/file/crash-recovery.html

というかそもそも一定時間で切れないように設定するべきではと思い、[こちらの記事](https://scribble.washo3.com/mac/osx-ssh-keep-alive.html)を参考に、`.ssh/config`に以下を追記。

```
ServerAliveInterval 300
TCPKeepAlive yes
```


## rails dbconsoleでパスワードを入力するのが面倒

以下で解決

```
$ rails dbconsole -p   # rails db -p でもいける
```
> Automatically provide the password from database.yml
> https://github.com/rails/rails/blob/157920aead96865e3135f496c09ace607d5620dc/railties/lib/rails/commands/dbconsole/dbconsole_command.rb#L150-L151

下記の記事で見つけました。
> https://teratail.com/questions/51709
> https://qiita.com/taka0125/items/5d0d7cf58a9249ad0a96



## メソッドの定義場所の探索

ちなみに、メソッドの定義場所を調べるのに`source_location`を使っていたけど、gemの`pry`を入れると`?`とか`$`とかが使えるらしい。
> https://qiita.com/jnchito/items/fc8a61b421d026a23ffe#comments

```
pry(main)> ? Rails::Generators::Base.class_option

From: /Users/knog/work/ruby_projects/rails_projects/sample/vendor/bundle/ruby/2.5.0/gems/railties-5.2.2/lib/rails/generators/base.rb @ line 202:
Owner: #<Class:Rails::Generators::Base>
Visibility: public
Signature: class_option(name, options=?)
Number of lines: 1

Make class option aware of Rails::Generators.options and Rails::Generators.aliases.



pry(main)> $ Rails::Generators::Base.class_option

From: /Users/knog/work/ruby_projects/rails_projects/sample/vendor/bundle/ruby/2.5.0/gems/railties-5.2.2/lib/rails/generators/base.rb @ line 203:
Owner: #<Class:Rails::Generators::Base>
Visibility: public
Number of lines: 6

def self.class_option(name, options = {}) #:nodoc:
  options[:desc]    = "Indicates when to generate #{name.to_s.humanize.downcase}" unless options.key?(:desc)
  options[:aliases] = default_aliases_for_option(name, options)
  options[:default] = default_value_for_option(name, options)
  super(name, options)
end
```

<br>

最後の`super`はどのクラスにあるのか疑問だったけど、試しに引数渡して実行してみたら、`Thor`にあるっぽい。

```
pry(main)> Rails::Generators::Base.class_option(:hoge)
=> #<Thor::Option:0x00007f91585bd998
 @aliases=[],
 @banner="HOGE",
 @check_default_type=nil,
 @default=nil,
 @description="Indicates when to generate hoge",
 @enum=nil,
 @hide=nil,
 @human_name="hoge",
 @lazy_default=nil,
 @name="hoge",
 @repeatable=false,
 @required=false,
 @type=:string>
```

### Thor::Base::ClassMethods#class_option

```
def class_option(name, options = {})
  build_option(name, options, class_options)
end
```

> https://www.rubydoc.info/github/wycats/thor/Thor%2FBase%2FClassMethods:class_option
> https://github.com/erikhuda/thor/blob/master/lib/thor/base.rb#L312-L314


`build_option`は、

```
def build_option(name, options, scope) #:nodoc:
  scope[name] = Thor::Option.new(name, {:check_default_type => check_default_type}.merge!(options))
end
```
> https://github.com/erikhuda/thor/blob/master/lib/thor/base.rb#L590-L592