railsについて、先輩にもらったアドバイスまとめ(その1)
最近はRuby on Railsで社内システムを作っています。 その中で先輩からもらったアドバイスやレビューで受けた指摘をまとめます。
new()はいらない
hoge = Hoge.new()
は
hoge = Hoge.new
でよい。
(Rubyは短く楽に書けるときは楽をするのじゃ!)
is_available?のisはいらない
有効かを判定しtrue/falseを返却するようなメソッドの名前は
def is_available? # 何らかの処理 end
ではなく
def available? # 何らかの処理 end
でよい。
(present?やblank?というメソッドがありますよねー)
※私はこの「?」を疑問形の「?」だと思っていました…(Is this a pen?的な)
破壊的でないメソッドに「!」はいらない
def hoge! # 破壊的な処理 end
であり、破壊的でないメソッドに「!」はいらない。
(破壊的な処理を行う場合はprivateメソッドであっても「!」をつけるようにしています)
ある機能追加のために複数のテーブルにカラム追加を行う場合、migrateファイルは分ける
分けたのですが理由が思い出せず…。
※これはもしかしたら1つの機能追加で複数のテーブルに手が入ったことをわかりやすくするために、migrateファイルはわけないほうがよかったのかも?と思いました。
できるだけ短く、意味のある処理ごとにメソッドにする
def calc_hoge hoge = 0 hoge = hoge + (a * b) hoge = hoge + (c * d) end
は
def calc_hoge hoge = 0 hoge += calc_a_b hoge += calc_c_d end def calc_a_b a * b end def calc_c_d c * d end
のようにしたほうがコードが説明的になってわかりやすい。
2016/4/19(火)追記
ステータスコード404でリソースの存在を隠すこともできる
現在作成しているシステムはユーザーにロールを設定しており、ロールによっては閲覧できないリソースがある。
そのリソースを表示するようなページに権限のないユーザーがアクセスした場合、
403が返るとリソースが存在していることが権限のないユーザーにも分かってしまう。
存在自体を隠したいときは404を返す。
詳しくは下記の記事を参照
HTTPステータスコードを適切に選ぶためのフローチャート : 難しく考えるのをやめよう | インフラ・ミドルウェア | POSTD
railsで404のときに表示されるページは public/404.html
である。
任意のデザインにしたい場合は404.htmlを編集すればよい。
rspecのテストでカバレッジが計測できるgem、SimpleCovを導入する
テストを書くならカバレッジ計測と行単位で通った・通ってないの確認ができたらいいな、と思っていたら
@tmtms さんより「SimpleCov」を教えていただきました。
導入手順
Gemfileに「simplecov」を追加
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' gem 'rspec-rails' # Test format nyan cat gem 'nyan-cat-formatter' # テストを自動実行 gem 'spring-commands-rspec' gem 'guard-rspec', require: false # カバレッジ取得 gem "simplecov" # モデルにテーブルのカラムをコメントで出力 gem 'annotate' end
gemをインストール
$ bundle install --path vendor/bundle --jobs=4 $ # .bundle/configに設定されている場合はbundleでOK
spec/spec_helper.rbにsimplecovのstartを記述
require 'simplecov' SimpleCov.start 'rails' RSpec.configure do |config| # rspec-expectations config goes here. You can use an alternate #・・・略・・・
これで準備は完了
使い方
rspecでテストを実行する。
$ bundle exec rspec spec/
するとプロジェクトフォルダ直下に「coverage」というフォルダが作成される。
coverageフォルダ配下の「index.html」をブラウザで開く。
するとファイルごとのカバレッジ一覧が表示される。
ファイル名をクリックすれば、行単位で通った・通っていないが確認できる。
導入にあたり参考にしたサイト
rspecでのテストがちょっと楽しくなるgem、nyan-cat-formatterを導入する
テストの待ち時間&結果確認がちょっと楽しくなるgemです。
GitHub - mattsears/nyan-cat-formatter: Nyan Cat inspired RSpec formatter!
導入手順
Gemfileに「nyan-cat-formatter」を追加
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' gem 'rspec-rails' # Test format nyan cat gem 'nyan-cat-formatter' end
gemをインストール
$ bundle install --path vendor/bundle --jobs=4 $ # .bundle/configに設定されている場合はbundleでOK
使い方
オプションをつけてrspecを実行!!
$ bundle exec rspec --format NyanCatFormatter spec/
すると…
※テスト実行中はNyan Catが走ります
テストが落ちると…
とりあえずユーザー管理と認証を実装したいのでdeviseを使う
自力で実装する心の余裕が消えたのでdeviseを使うことにしました。
もうすでにあるものはガンガン使おう!そうしよう。
インストールや設定手順は下記リンクを参照しました。
- Rails 4.2 で ユーザー管理・認証 (devise) - Qiita
- Railsのログイン認証gemのDeviseのインストール方法 - Rails Webook
- [*Rails*] deviseの使い方 - Qiita
手順
Gemfileにdeviseを追加する。
gem 'devise'
bundle installを行う。
(ここではbundlerの設定をそのまま使用したいのでbundleコマンドを実行している)
$ bundle Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using rake 10.5.0 ・・・略・・・ Using rack-test 0.6.3 Installing orm_adapter 0.5.0 Installing warden 1.2.6 Installing bcrypt 3.1.11 with native extensions Using mail 2.6.3 ・・・略・・・ Using web-console 2.3.0 Installing responders 2.1.1 Installing devise 3.5.6 Bundle complete! 16 Gemfile dependencies, 72 gems now installed. Bundled gems are installed into ./vendor/bundle.
devise関連ファイルのをrailsコマンドで生成する。
$ bundle exec rails generate devise:install create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. If you are deploying on Heroku with Rails 3.2 only, you may want to set: config.assets.initialize_on_precompile = false On config/application.rb forcing your application to not access the DB or load models when precompiling your assets. 5. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================
環境を設定する。
config/environments/development.rb
に下記を追記する。
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
devise用のUserモデルを作成する。
$ bundle exec rails g devise User invoke active_record create db/migrate/20160321071935_devise_create_users.rb create app/models/user.rb invoke rspec create spec/models/user_spec.rb insert app/models/user.rb route devise_for :users
Userテーブルを追加するのでmigrateする。
$ bundle exec rake db:migrate:reset == 20160321071935 DeviseCreateUsers: migrating ================================ -- create_table(:users) -> 0.0166s -- add_index(:users, :email, {:unique=>true}) -> 0.0333s -- add_index(:users, :reset_password_token, {:unique=>true}) -> 0.0259s == 20160321071935 DeviseCreateUsers: migrated (0.0760s) =======================
deviseが出力するメッセージの表示場所を設定する。
(ここでは app/views/layouts/application.html.erb
に設定)
ついでにナビゲーションバーにログインしていない場合はログイン、ログイン済みの場合はログアウトというリンクを表示する。
<body> <header> <div class=""> <% if user_signed_in? %> <div> Logged in as <strong><%= current_user.email %></strong>. <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> </div> <% else %> <div> <%= link_to "ログイン", new_user_session_path %> </div> <% end %> </div> </header> <div> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <%= yield %> </div> </body>
undefined method `devise_for'というエラーが出た。
→一度rails serverを再起動しないといけないらしい。
undefined method `devise_for' in rails - Stack Overflow
正しく動けば以下のようなログイン画面が表示されるはず。
その他
ログインしていないユーザーはログイン画面にリダイレクトするよう設定したかったので下記を参考に実装。
devise + omniauth-facebookでリクエストURLにリダイレクトする - yasuoza diary
初期ユーザーの追加をする。
Devise に初期ユーザを追加 - Ruby and Rails
Ruby on Rails 4 アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/11
- メディア: 大型本
- この商品を含むブログ (5件) を見る
N+1問題を検出してくれるgem、bulletを導入する
Railsで作ったプロジェクトを開発環境で動かしていくと、ある一覧ページを表示する度にすごい量のSELECTが発行されているように見え、先輩に相談!
「N+1問題」というものを教えていただきました。
N+1問題 / Eager Loading とは - Rails Webook
解決策
以下のページを参考にしました。
ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い - Qiita
そもそもN+1問題はログを眺めていないと気づけないのでは…?と思ったところ、素敵なgemがあること先輩に教えていただきました!
それが「bullet」です。
GitHub - flyerhzm/bullet: help to kill N+1 queries and unused eager loading
導入手順
導入は下記ページを参考にしました。
» Railsライブラリ紹介: N+1問題を検出する「bullet」 TECHSCORE BLOG
Gemfileにbulletを追加
(開発環境でのみ使用する)
group :development do # Access an IRB console on exception pages or by using <%= console %> in views gem 'web-console', '~> 2.0' gem 'thin' gem 'rails_best_practices' gem 'bullet' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' end
bundleコマンドを実行し、gemをインストールする
$ bundle Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using rake 10.5.0 Using i18n 0.7.0 ・・・略・・・ Using sass-rails 5.0.4 Using web-console 2.3.0 Installing uniform_notifier 1.9.0 Installing bullet 5.0.0 Bundle complete! 15 Gemfile dependencies, 67 gems now installed. Bundled gems are installed into ./vendor/bundle.
開発環境のconfigにbullet用の設定を追加する
(config/environments/development.rbというファイルに下記の記述を追加する)
config.after_initialize do Bullet.enable = true Bullet.alert = true Bullet.bullet_logger = true Bullet.console = true Bullet.rails_logger = true end
railsサーバーを再起動する
(再起動しないとbulletが使えない)
再起動してN+1問題のクエリが発行されるページへアクセスすると、下記のようなポップアップが表示されるようになる
どこの処理で発生したかに加え対処方法をきちんと教えてくれるので、対処が簡単になりました(∩´∀`)∩ワーイ
素敵なgem、rails_best_practicesを導入する
先輩のアドバイスを受け、Railsのベストプラクティスに従っているかを確認できるgemを導入しました。
手順
Gemfileにrails_best_practicesを追加(今回は開発環境だけで使用する)
group :development do # Access an IRB console on exception pages or by using <%= console %> in views gem 'web-console', '~> 2.0' gem 'thin' gem 'rails_best_practices' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' end
bundleコマンドを実行し、gemをインストールする
$ cat .bundle/config --- BUNDLE_PATH: vendor/bundle BUNDLE_JOBS: 4 BUNDLE_DISABLE_SHARED_GEMS: '1' $ $ $ bundle Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using json 1.8.3 Using minitest 5.8.4 ・・・略・・・ Installing code_analyzer 0.4.5 Installing rails_best_practices 1.16.0 Bundle complete! 13 Gemfile dependencies, 64 gems now installed. Bundled gems are installed into ./vendor/bundle. Post-install message from rails_best_practices: ******************************************************************************** rails_best_practices is a code metric tool to check the quality of rails codes. I highly recommend you browse the Rails Best Practices website first. http://rails-bestpractices.com Please also try our online service http://railsbp.com Enjoy! Richard Huang (flyerhzm@gmail.com) ******************************************************************************** $
これでrails_best_practicesが使える状態になる。
早速実行してみる!
プロジェクトのディレクトリに入り、 rails_best_practices .
を実行する。
$ bundle exec rails_best_practices . Source Code: |==============================================================================================================================| /Users/maetoo11/workspace/rails-app-name/db/schema.rb:34 - always add db index (model_name => [column_name]) /Users/maetoo11/workspace/rails-app-name/app/views/hoge/index.html.erb:53 - law of demeter /Users/maetoo11/workspace/rails-app-name/app/helpers/humus_helper.rb:1 - remove empty helpers /Users/maetoo11/workspace/rails-app-name/app/views/humus/_form.html.erb:1 - replace instance variable with local variable /Users/maetoo11/workspace/rails-app-name/app/views/hoge/_form.html.erb:7 - replace instance variable with local variable Please go to http://rails-bestpractices.com to see more useful Rails Best Practices. Found 28 warnings.
各警告メッセージの意味(日本語)は下記の記事を参考にしました。
Rails Best Practices の警告をちゃんと考える - Qiita
Rails Best Practicesの本家ページ(?)です。
Rails Best Practices - Rails Best Practices
※どうやってプラクティスを検索していいかが不明…。
これでベストプラクティスをできるだけ守ったコードがかけるはず!!
rails newの先輩オススメ手順
railsプロジェクトを新しく作成する際に実行する「rails new」のオススメ手順を、会社の先輩に教えていただいたのでメモ。
前提
手順
railsアプリケーション用のディレクトリを作成する。
→作成したディレクトリに移動
$ mkdir rails-app-name $ $ cd rails-app-name $ $ pwd /Users/maetoo11/workspace/rails-app-name $ $ ls -l $
railsアプリケーション用ディレクトリでbundle initを実行し、Gemfileを作成する。
$ ruby -v ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15] $ $ bundle init Writing new Gemfile to /Users/maetoo11/workspace/rails-app-name/Gemfile $ $ $ $ ls -l total 8 -rw-r--r-- 1 maetoo11 staff 64 3 3 17:37 Gemfile
Gemfileを編集してrailsのgem を追加する。
$ vi Gemfile 1 source 'https://rubygems.org' 2 3 gem 'rails'
bundle installでGemfileで指定されたgemのインストールを行う。
ここで大事なこと!
--path vendor/bundle
を指定し、railsアプリケーション用のディレクトリ配下のvendor/bundleディレクトリにgemをインストール
これにより、gemをrailsプロジェクト毎に管理できる!!--jobs=4
を指定するとbundle installを並列処理で実行できる
参考:Bundlerで並列処理??bundle installを爆速で処理する方法。 - Qiita
$ bundle install --path vendor/bundle --jobs=4 Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using json 1.8.3 Installing i18n 0.7.0 Installing minitest 5.8.4 Installing rake 10.5.0 Installing builder 3.2.2 ・・・略・・・ Installing rails 4.2.5.2 Bundle complete! 1 Gemfile dependency, 34 gems now installed. Bundled gems are installed into ./vendor/bundle. $ $ ls -l total 16 -rw-r--r-- 1 maetoo11 staff 63 3 3 17:37 Gemfile -rw-r--r-- 1 maetoo11 staff 2607 3 3 17:40 Gemfile.lock drwxr-xr-x 3 maetoo11 staff 102 3 3 17:40 vendor $ $ # vendor/bundle配下にgemがインストールされていることを確認 $ ls -la vendor/bundle/ruby/2.3.0/gems total 0 drwxr-xr-x 34 maetoo11 staff 1156 3 3 17:40 . drwxr-xr-x 9 maetoo11 staff 306 3 3 17:40 .. drwxr-xr-x 6 maetoo11 staff 204 3 3 17:40 actionmailer-4.2.5.2 drwxr-xr-x 6 maetoo11 staff 204 3 3 17:40 actionpack-4.2.5.2 ・・・略・・・
rails newを実行する際に、付与するオプションを決める。
→まずはヘルプを表示して、オプションを確認
$ bundle exec rails new -h Usage: rails new APP_PATH [options] Options: -r, [--ruby=PATH] # Path to the Ruby binary of your choice # Default: /Users/maetoo11/.rbenv/versions/2.3.0/bin/ruby -m, [--template=TEMPLATE] # Path to some application template (can be a filesystem path or URL) [--skip-gemfile], [--no-skip-gemfile] # Don't create a Gemfile -B, [--skip-bundle], [--no-skip-bundle] # Don't run bundle install -G, [--skip-git], [--no-skip-git] # Skip .gitignore file [--skip-keeps], [--no-skip-keeps] # Skip source control .keep files -O, [--skip-active-record], [--no-skip-active-record] # Skip Active Record files -S, [--skip-sprockets], [--no-skip-sprockets] # Skip Sprockets files [--skip-spring], [--no-skip-spring] # Don't install Spring application preloader -d, [--database=DATABASE] # Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite3/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc) # Default: sqlite3 -j, [--javascript=JAVASCRIPT] # Preconfigure for selected JavaScript library # Default: jquery -J, [--skip-javascript], [--no-skip-javascript] # Skip JavaScript files [--dev], [--no-dev] # Setup the application with Gemfile pointing to your Rails checkout [--edge], [--no-edge] # Setup the application with Gemfile pointing to Rails repository [--skip-turbolinks], [--no-skip-turbolinks] # Skip turbolinks gem -T, [--skip-test-unit], [--no-skip-test-unit] # Skip Test::Unit files [--rc=RC] # Path to file containing extra configuration options for rails command [--no-rc], [--no-no-rc] # Skip loading of extra configuration options from .railsrc file Runtime options: -f, [--force] # Overwrite files that already exist -p, [--pretend], [--no-pretend] # Run but do not make any changes -q, [--quiet], [--no-quiet] # Suppress status output -s, [--skip], [--no-skip] # Skip files that already exist Rails options: -h, [--help], [--no-help] # Show this help message and quit -v, [--version], [--no-version] # Show Rails version number and quit Description: The 'rails new' command creates a new Rails application with a default directory structure and configuration at the path you specify. You can specify extra command-line arguments to be used every time 'rails new' runs in the .railsrc configuration file in your home directory. Note that the arguments specified in the .railsrc file don't affect the defaults values shown above in this help message. Example: rails new ~/Code/Ruby/weblog This generates a skeletal Rails installation in ~/Code/Ruby/weblog. See the README in the newly created application to get going.
今回は
- bundle installを飛ばす
- DBにMySQLを指定
- turbolinksを使用しない
- test-unitを使用しない
を指定してrails newを実行する。
2016/12/16 追記
Rails5からは
bundle exec rails new -B -d mysql --skip-turbolinks --skip-test.
らしいです。(未確認です)
$ bundle exec rails new -B -d mysql --skip-turbolinks --skip-test-unit . exist create README.rdoc create Rakefile create config.ru create .gitignore conflict Gemfile Overwrite /Users/maetoo11/workspace/rails-app-name/Gemfile? (enter "h" for help) [Ynaqdh] force Gemfile create app ・・・略・・・ $ $ ls -l total 40 -rw-r--r-- 1 maetoo11 staff 1392 3 3 17:48 Gemfile -rw-r--r-- 1 maetoo11 staff 2607 3 3 17:40 Gemfile.lock -rw-r--r-- 1 maetoo11 staff 478 3 3 17:48 README.rdoc -rw-r--r-- 1 maetoo11 staff 249 3 3 17:48 Rakefile drwxr-xr-x 8 maetoo11 staff 272 3 3 17:48 app drwxr-xr-x 6 maetoo11 staff 204 3 3 17:48 bin drwxr-xr-x 11 maetoo11 staff 374 3 3 17:48 config -rw-r--r-- 1 maetoo11 staff 153 3 3 17:48 config.ru drwxr-xr-x 3 maetoo11 staff 102 3 3 17:48 db drwxr-xr-x 4 maetoo11 staff 136 3 3 17:48 lib drwxr-xr-x 3 maetoo11 staff 102 3 3 17:48 log drwxr-xr-x 7 maetoo11 staff 238 3 3 17:48 public drwxr-xr-x 3 maetoo11 staff 102 3 3 17:48 tmp drwxr-xr-x 4 maetoo11 staff 136 3 3 17:48 vendor
Gemfileを編集し、不要なgemの削除と必要なgemの追加を行う。
→今回は開発・テスト環境でwebrickではなくthinを使うようにした。(39行目)
$ vi Gemfile 1 source 'https://rubygems.org' 2 3 4 # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 gem 'rails', '4.2.5.2' 6 # Use mysql as the database for Active Record 7 gem 'mysql2', '>= 0.3.13', '< 0.5' ・・・略・・・ 35 36 group :development do 37 # Access an IRB console on exception pages or by using <%= console %> in views 38 gem 'web-console', '~> 2.0' 39 gem 'thin' 40 41 # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 42 gem 'spring' 43 end
vendor/bundle配下をgitで管理しないファイルにするために、.gitignoreを編集する。(9行目)
$ vi .gitignore 1 # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 # 3 # If you find yourself ignoring temporary files generated by your text editor 4 # or operating system, you probably want to add a global ignore instead: 5 # git config --global core.excludesfile '~/.gitignore_global' 6 7 # Ignore bundler config. 8 /.bundle 9 /vendor/bundle 10 11 # Ignore all logfiles and tempfiles. 12 /log/* 13 !/log/.keep 14 /tmp
bundlerの設定を確認する。
→最初のbundle install時に指定したオプションが設定されている。
→以降、このプロジェクトディレクトリで実行するbundlerはこの設定を使用する。
$ cat .bundle/config --- BUNDLE_PATH: vendor/bundle BUNDLE_JOBS: 4 BUNDLE_DISABLE_SHARED_GEMS: '1'
bundle installを実行する。
$ bundle Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using rake 10.5.0 Using i18n 0.7.0 Using json 1.8.3 Using minitest 5.8.4 ・・・略・・・ Bundle complete! 11 Gemfile dependencies, 53 gems now installed. Bundled gems are installed into ./vendor/bundle. Post-install message from rdoc: Depending on your version of ruby, you may need to install ruby rdoc/ri data: <= 1.8.6 : unsupported = 1.8.7 : gem install rdoc-data; rdoc-data --install = 1.9.1 : gem install rdoc-data; rdoc-data --install >= 1.9.2 : nothing to do! Yay!
これでrails newのオススメ手順は終わりです。