ためすう

Rails5 で rescue_from を使う

2019-05-12

やったこと

Rails5 の rescue_from メソッドについて調べます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

app/controllers/tasks_controller.rb

class TasksController < ApplicationController
  rescue_from Exception, with: :render_500

  def index
    raise Exception.new
  end

  def render_500
    logger.debug('render_500')
  end
end

※ 任意のコントローラに記述してください

注意点

ApplicationControllerクラスでは一部の例外についてrescueできないものがあります。その理由は、コントローラが初期化されてアクションが実行される前に発生する例外があるからです。

と説明があるので、コントローラが初期化される前に、例外が発生した場合は捕捉できない場合があります。

参考

Ruby でキーワード引数を使う

2019-05-12

やったこと

キーワード引数を使ってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

test.rb

class Sample
  def initialize(params)
    p params

    # a を取りだす
    p params[:a]
  end
end

Sample.new(a: 111, b: 222)

出力結果

$ ruby test.rb
{:a=>111, :b=>222}
111

情報を探しても見つかりませんでしたが、関数の引数に ** を付きなくても キーワード引数のハッシュとして、扱えるようです。

Rails5 で try を使う

2019-05-12

やったこと

try メソッドについて調べます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

レシーバーのクラスがnilの場合

$ rails c
irb(main):001:0> @number.try(:nest)
=> nil
irb(main):002:0> @number.try!(:nest)
=> nil

try, try! のどちらを使っても nil が返されました。

レシーバーのクラスが存在する場合

$ rails c
Running via Spring preloader in process 21611
Loading development environment (Rails 5.2.3)
irb(main):001:0> class Sample
irb(main):002:1>   def nest
irb(main):003:2>     p 3
irb(main):004:2>   end
irb(main):005:1> end
=> :nest
irb(main):006:0> @number = Sample.new
=> #<Sample:0x00007f96c024adc0>
irb(main):007:0> @number.try!(:nest)
3
=> 3
irb(main):008:0> @number.try!(:nest_nothing)
Traceback (most recent call last):
        1: from (irb):8
NoMethodError (undefined method `nest_nothing' for #<Sample:0x00007f96c024adc0>)
irb(main):009:0> @number.try(:nest)
3
=> 3
irb(main):010:0> @number.try(:nest_nothing)
=> nil

try だと存在しないメソッドを呼び出そうとしても nil が返されることが分かります。

try について

nilでない場合にのみオブジェクトのメソッドを呼び出したい場合、最も単純な方法は条件文を追加することですが、どこか冗長になってしまいます。そこでtryメソッドを使うという手があります。tryはObject#sendと似ていますが、nilに送信された場合にはnilを返す点が異なります。

tryメソッドは、NoMethodErrorを握りつぶして代わりにnilを返す点に注意が必要です。メソッド名の誤りを防ぎたい場合はtry!を使います。

try を使うには、 Active Support を読み込んでおく必要があります。

Rails の場合は、すぐに使えるようです。

Ruby on Railsアプリケーションでは、基本的にすべてのActive Supportを読み込みます。

参考

Ruby での参照渡しについて

2019-05-10

やったこと

Ruby での参照渡しについて、調べてみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

関数に渡す引数の変数について、object_id を調べてみます。 また変数の代入もしてみます。

test.rb

def test(a, b)
  p "a: #{a.object_id} in test"
  p "b: #{b.object_id} in test"
end

a = 1
b = 2

c = b

p "a: #{a.object_id}"
p "b: #{b.object_id}"
p "c: #{c.object_id}"

test(a, b)

出力結果

$ ruby test.rb
"a: 3"
"b: 5"
"c: 5"
"a: 3 in test"
"b: 5 in test"

どうやら、引数として渡す前、渡した後のオブジェクトは同じもののようです。

つまり、引数に対して関数内で引数のオブジェクトに直接変更を加えると 関数を抜けた後も影響を受けます。

test.rb

def test2(a, b)
  a.upcase!
end

a = 'abc'
b = 'jkl'

test2(a, b)

p a
p b

出力結果

"ABC"
"jkl"

参考

class Object (Ruby 2.6.0)

Rails5 でエラーページを表示する

2019-05-09

やったこと

Rails5 にて、エラーページを表示する方法を調べました。

静的なページ、動的なページのどちらにするかで方法が変わります。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

静的なページを表示

すでに用意されているものを利用します。

config/environments/development.rb

config.consider_all_requests_local = false

例えば存在していないページにアクセスした時、 public/404.html が使われます。

動的なページを表示

config/environments/development.rb

config.consider_all_requests_local = false

エラーページの view を用意します。

app/views/errors/error_404.html.erb

404 dayo

例外を制御します。今回は 404エラーの時の振る舞いを定義します

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  rescue_from ActionController::RoutingError, with: :render_404

  def render_404
    logger.debug(9999)
    render template: 'errors/error_404', status: 404, layout: 'application',  content_type: 'text/html'
  end
end

最後にルーティングの一番下に下記を追加してください

config/routes.rb

get '*path', controller: 'application', action: 'render_404'

参考

Rails5 で日付のバリデーションを行う

2019-05-09

やったこと

Rails5 で日付、日時をフォーマットする方法を調べます。

確認環境

$ ruby --version
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

やったこと

Rails5 ではデフォルトで日付のバリデーションがないようなので、実装方法を調べました。

task.expire_date という タスクの有効期限について、日付のバリデーションをかけます。

調査

app/models/task.rb

class Task < ApplicationRecord
  validate :expire_date_is_valid?

  private
  def expire_date_is_valid?
    begin
      Date.parse self.expire_date.to_s if self.expire_date.present?
    rescue ArgumentError
      errors.add(
        :expire_date,
        '無効な日付です'
      )
    end
  end
end

Date.parse の挙動も試してみました。

$ rails c

irb(main):001:0> Date.parse(888)
Traceback (most recent call last):
        2: from (irb):1
        1: from (irb):1:in `parse'
TypeError (no implicit conversion of Integer into String)
irb(main):002:0> Date.parse('20190509')
=> Thu, 09 May 2019
irb(main):003:0> Date.parse('2019-05-09')
=> Thu, 09 May 2019
irb(main):004:0> Date.parse('19-05-09')
=> Thu, 09 May 2019
irb(main):005:0> Date.parse('9919-05-09')
=> Fri, 09 May 9919
irb(main):006:0> Date.parse('11')
=> Sat, 11 May 2019

これをみると、厳密なチェックは出来ていないので、使用するときは注意してください。

参考

Rails5 の migration で追加するカラムの順番を制御する

2019-05-09

やったこと

Rails5 の migration を利用してカラムを追加する時、追加する位置を制御する方法について調べました。

確認環境

$ ruby --version
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

$ rails g model Task2 name:string content:text
$ rails db:migrate

ここで、task2 テーブルに status カラムを content カラムの後に追加します。

$ rails g migration AddStatusAtToTask2s status:int

これが生成されたファイルです。

db/migrate/20190508233635_add_status_at_to_task2s.rb

class AddStatusAtToTask2s < ActiveRecord::Migration[5.2]
  def change
    add_column :task2s, :status, :int
  end
end

※ 日時部分は実行時間によって変わります。

下記のように変更します。 デフォルトのままだと、カラムが一番後に追加されます。

class AddStatusAtToTask2s < ActiveRecord::Migration[5.2]
  def change
    add_column :task2s, :status, :int, after: :content
  end
end
$ rails db:migrate

無事に意図した位置にカラムを追加することができました。

参考

&. で nil チェック (Ruby)

2019-05-09

やったこと

&. を利用して nil のチェックをしてみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

$ rails c

irb(main):001:0> foo = 13
=> 13
irb(main):002:0> foo&.to_s
=> "13"
irb(main):003:0> nil&.to_s
=> nil
irb(main):004:0> nil.to_s
=> ""
irb(main):005:0> nil.hoge
Traceback (most recent call last):
        2: from (irb):5
        1: from (irb):5:in `rescue in irb_binding'
NoMethodError (undefined method `hoge' for nil:NilClass)
irb(main):006:0> nil&.hoge
=> nil

&. について

メソッド呼び出しで .' の代わりに&.’ を使うことができます。 この形式でメソッドを呼びだそうとすると、レシーバが nil の場合は 以下のように働きます。 - 引数の評価が行なわれない - メソッド呼び出しが行われない - nil を返す

safe navigation operator(通称「ぼっち演算子」)

参考

Rails5 で日付、日時をフォーマットする

2019-05-08

やったこと

Rails5 で日付、日時をフォーマットする方法を調べます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

方法1. strftime

irb(main):001:0> Date.current.strftime('%Y/%m/%d')
=> "2019/05/08"

この方法は都度フォーマットを指定する必要があります。

方法2. config/locales

I18n の機能を利用します

デフォルトの言語を日本語にします

config/application.rb

config.i18n.default_locale = :ja

次に、yml でフォーマットを定義します

config/locales/ja.yml

ja:
  date:
    formats:
      default: '%Y/%m/%d'
      long: '%Y年%m月%d日'
      short: '%m/%d'

I18n を使って日付をフォーマットします。

$ rails c
Running via Spring preloader in process 87044
Loading development environment (Rails 5.2.3)
irb(main):001:0> I18n.l(Date.today)
=> "2019/05/08"
irb(main):002:0> I18n.l(Date.today, format: :long)
=> "2019年05月08日"
irb(main):003:0> I18n.l(Date.today, format: :short)
=> "05/08"

参考

Ruby で引数にメソッドを渡す

2019-05-07

やったこと

Ruby の関数で引数にメソッドを渡す方法を調べてみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

test.rb

def xxx(&yyy)
  p yyy
  yyy.call
end

def abc1
  p 'abc1'
end

## ブロック付きメソッド呼び出し
## { ... }
p '{ ... }'
xxx {
  abc1
}

## do ... end
p 'do ... end'
xxx do
  abc1
end

出力結果

$ ruby test.rb
"{ ... }"
#<Proc:0x00007faa8a036588@ruby-block.rb:13>
"abc1"
"do ... end"
#<Proc:0x00007faa8a036358@ruby-block.rb:19>
"abc1"

最後の引数の直前に & がついている場合、その引数で指定した手続き オブジェクト(Proc)やメソッドオブジェクト(Method)がブロック としてメソッドに渡されます。

参考