大ちゃんの駆け出し技術ブログ

RUNTEQ受講生のかわいいといわれるアウトプットブログ

【Rails】技術面接対策の記事の質問を多少深ぼる記事⑦

はじめに

こんにちは!大ちゃんの駆け出し技術ブログです。

この記事は前回の記事の続きものです。

(前回の記事)

sakitadaiki.hatenablog.com

本記事ではQ37 ~ Q42を深掘りします。

Q37: Railsのどういうところがキライですか?

回答:

私の場合は、機械学習系のライブラリ開発が乏しかったり存在しなかったりする点。

これについては正直回答ができないのでスキップします。。。RailsRubyだけでなく他の言語も比較しないと嫌いところは答えられないと思うので。2年後あたりにはわかるのかもしれないです。

同様のトピックである下記記事はざっと読みましたが「へーそうなんだー」ぐらいの感想でしたね、、。

qiita.com

Q38: ご贔屓のRuby gemを教えて下さい

回答:

Rails開発者なら誰もがご存知のDeviseが好きです。認証のような複雑なものを2分でセットアップできるからです。

まず漢字が読めませんでした、、、、。ご贔屓(ごひいき)だそうです。要はお気に入りのgemはなんですかと言う質問ですね。

回答例はDeviseですが、自分はあまりDeviseは好きではないですね、、、。ブラックボックス過ぎて何が実際に行われているのがわからず、ログイン機能のカスタム性も優れていません。ポートフォリオではガッツリDeviseを使っていますが、Slackログインを実装するために仕方なく使っています。

個人的に1番好きなgemはbulletですかね。

GitHub - flyerhzm/bullet: help to kill N+1 queries and unused eager loading

こちらのgemはN + 1問題を検知してくれるgemです。以下のようにLogにN + 1問題が発生していた記録を残し、さらにはその解決方法まで提案してくれます。

[INFO] N+1 Query in /posts
  Post => [:comments]
  Add to your finder: :include => [:comments] # 解決方法
[INFO] N+1 Query method call stack
  /home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:14:in `_render_template__600522146_80203160_0'
  /home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:11:in `each'
  /home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:11:in `_render_template__600522146_80203160_0'
  /home/flyerhzm/Downloads/test_bullet/app/controllers/posts_controller.rb:7:in `index'

自分はポートフォリオでテーブル数が20個で未経験にしてはかなり複雑なDB設計をしていました。

https://i.gyazo.com/1c70c96831791315474e886f8d34132f.png

そのためActive Recordをたくさん使用していたのですが、N + 1問題がどこで起きてもおかしくないと思っていました。しかし、bulletを使用することでどこでN + 1問題が起きているかわかるので、N + 1問題の解決を容易に行うことができました!このgemがなかったらN + 1問題の修正地獄に追われていたことでしょう、、、、。

Q39: springについて説明してください

回答:

springはアプリケーションプリローダーであり、アプリケーションをバックグラウンドで実行し続けることでマイグレーションやrakeタスクを実行するときにアプリケーションの起動が不要になります。

springはRailsにデフォルトで入っているgemです。rails newしたらGemfileに既に記述されます。

group :development, :test do
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'spring-commands-rspec'
end

一応公式のgemを見てみます。

github.com

Spring is a Rails application preloader. It speeds up development by keeping your application running in the background so you don't need to boot it every time you run a test, rake task or migration.

[訳] Springは、Railsアプリケーションプリローダーです。アプリケーションをバックグラウンドで動作させておくことで、テストやrakeタスク、マイグレーションを実行するたびにアプリケーションを起動する必要がなく、開発をスピードアップしてくれます。

ほとんど回答例と同じような説明をしていますね。

前もってロードしておく(preload)とあるように実行するたびに再起動するのではなく常に起動しておくことで、処理が呼び出された際に実行するスピードを早めてくれるということです。

例えば、あるテストファイルを実行するとします。

起動時にはspringは走っていません。

$ bin/spring status
Spring is not running.

テストファイルを実行します。

$ time bin/rake test test/controllers/posts_controller_test.rb
Running via Spring preloader in process 2734
Run options:

# Running tests:

.......

Finished tests in 0.127245s, 55.0121 tests/s, 78.5887 assertions/s.

7 tests, 10 assertions, 0 failures, 0 errors, 0 skips

real    0m2.165s
user    0m0.281s
sys     0m0.066s

springが起動します。

$ bin/spring status
Spring is running:

再度実行すると既にバックグラウンド側で起動している状態ですのでテストが早くなります。

$ time bin/rake test test/controllers/posts_controller_test.rb
Running via Spring preloader in process 8352
Run options:

# Running tests:

.......

Finished tests in 0.176896s, 39.5714 tests/s, 56.5305 assertions/s. # 早くなっている

7 tests, 10 assertions, 0 failures, 0 errors, 0 skips

real    0m0.610s
user    0m0.276s
sys     0m0.059s

Q40: アセットパイプラインについて説明してください

回答:

ブラウザで使われるJavaScriptCSSを用意するフレームワークです。

ちょっと回答例が説明不足な気がしますね、、。

Railsディレクトリ構造では画像、javascriptcss、htmlの各ファイルは以下のように分割して配置されています。

画像 -> app/assets/images
javascript -> app/assets/javascripts
css(scss) -> app/assets/stylesheets
html -> app/views

しかし、Railsではこれらのファイルを集約し一つのファイルにまとめる仕組みがあり、それがアセットパイプラインです。

もう少し詳しく説明します。よくある共通レイアウトのapplication.html.erbを見てみます。

<!DOCTYPE html>
<html>

<head>
  <title>Hoge</title>
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>

  <%= stylesheet_link_tag 'application' %>
  <%= javascript_include_tag 'application' %>
</head>

<body>
  <%= yield %>
</body>

</html>

javascriptcssのファイルをレイアウトに適用する記述は以下の2つです。

<%= stylesheet_link_tag 'application' %>
<%= javascript_include_tag 'application' %>

stylesheet_link_tagはapp/assets/stylesheets/application.scssをレイアウトに適用するように指定しています。javascript_include_tagも同様にapp/assets/javascripts/application.jsをレイアウトに適用するように指定しています。各ファイルのデフォルトの記述は以下のようになります。

// application.scss
 *
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_self
 *= require_tree
//= require rails-ujs
//= require turbolinks
//= require_tree .

ここで重要な記述は各ファイル共通して存在するrequire_treeです。これにより同一ディレクトリにあるファイルを集約してファイル内に読み込みます。例えば、application.scssの同一ディレクトリにmain.scssやhogehoge.scssがあればそれらをapplication.scss内に読み込みます。結果require_treeで個々のファイルを集約させたものが全体のレイアウトであるapplication.html.erbに適用されます。これが基本的なアセットパイプラインの仕組みです。

上述したscssとjsとは似ていませんが、画像ファイルの読み込みもアセットパイプラインの仕組みの中の一つです。以下のようにimage_tagを記述します。

<%= image_tag "hoge.png" %>

上記のように記述するとapp/assets/imagesディレクトリのhoge.pngにアクセスできます。

Q41: Railsで認証を管理するときには何を使っていましたか

回答:

Deviseです。

回答例と同じようにDeviseですね、、、。理由としてはポートフォリオではどうしてもDeviseとOmniauthの組み合わせを使用しないと安全なSlack ログインを実装することができなかったので、、。

# Gemfile
gem 'devise', github: 'heartcombo/devise', branch: 'ca-omniauth-2'
gem 'ginjo-omniauth-slack', require:'omniauth-slack'

他の認証gemにsorceryがありますが、sorceryにもslackログインの機能があるようです。

github.com

しかし、こちらのファイルは2016年の12月より更新がされていないためか何度試してもエラーになりました。おそらくSlackの方で認証の方法が大きく変わっているためだと思われます。sorceryの方がカスタマイズ性が優れていて好きなので可能であればsorceryを使いたかったですね、、。

Q42: splat演算子について説明してください

回答:

splat演算子は、メソッドに渡される引数の数を事前に決めておきたくない場合に使われます。Rubyにはsplat演算子とdouble splat演算子**の2種類があります。 splat演算子は想像どおり以下のように動作します。

def do_sth(*input)
  input.each {|x| puts x }
end
do_sth(3,4,5)
# => 3
# => 4
# => 5

double splat演算子*は通常のsplat演算子と似ていますが、キーバリューを引数に取る点が異なります。

def do_sth(**input)
  input.each {|k,v| puts v }
end
do_sth('a':3, 'b':4, 'c':5)
# => 3
# => 4
# => 5

これはよく(*args)とかでお目にかかるものでしょう。メソッドの引数の数を指定しない時に使われます。

def hoge(*args)  
  args.each { |arg| p arg }
end

hoge("A", "B")
=> "A", "B"

eachで展開できるため予想できますが、渡された引数は配列となっています。

def hoge(*args)  
  p args
end

hoge("A", "B")
=> ["A", "B"]

double splat演算子は見たことがありませんが使うタイミングが気になりますね。キーバリューを引数に取るので少し扱いが難しそうです。

def hoge(**args)
  args.each {|key, value| p value }
end

hoge fuga: "A", foo: "B"
=> "A", "B"

double splatでは引数の塊がハッシュとなります。

def hoge(**args)
  p args
end

hoge fuga: "A", foo: "B"
=> { fuga: "A", foo: "B" }

終わりに

今回はここまで!!!!

次回はQ43からです!

残りあと2回のブログで終わりそうです!