ためすう

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)がブロック としてメソッドに渡されます。

参考

Ruby の Symbol (シンボル) について

2019-05-07

やったこと

Ruby の Symbol (シンボル) が腑に落ちていないので、調べてみます。

確認環境

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

調査

シンボルを3つの方法で定義してみます。

$ rails c
irb(main):010:0> :symbol
=> :symbol
irb(main):011:0> :'symbol'
=> :symbol
irb(main):012:0> %s!symbol!
=> :symbol

シンボルを定義しただけなので、このコードに意味はあまりありません。

シンボル自体の説明を以降でします。

Symbol (シンボル)

概要

シンボルは任意の文字列と一対一に対応するオブジェクトです。

同じ内容のシンボルはかならず同一のオブジェクトです

メリット

  • 処理の効率が良いこと
  • immutable (不変) である

参考