ruby:ハッシュ操作の応用1

以下のようなハッシュを画面に返すとする。

  # 画面に引き渡すインスタンス変数(Hash)
  # @conpany_inf カンパニー情報(ヘッダ情報)
  #   {
  #     company_name [string] カンパニー名
  #     company_started_at [datetime] 創設日
  #     staff_count [integer] スタッフ人数
  #   }
  # @staff_inf スタッフ一覧情報
  #    [{
  #       staff_no: [string] スタッフNO
  #       staff_name: [string] スタッフ名
  #       staff_class: [string] 一般職/管理職
  #       license_info: 資格情報
  #         [{
  #           license_name [string] 資格名
  #           license_get_date [datetime] 取得日
  #         }]
  #   }]

各モデルは以下のようなイメージ。

# app/model/company.rb
class Company < ApplicationRecord
  has_many :staffs
end

# app/model/staff.rb
class Staff < ApplicationRecord
  belong_to :company
  has_many :licenses

  scope :alive, -> { where(is_retire: false) }
  scope :manage_alive, -> { alive.where(is_manage: true) }
end

# app/model/license.rb
class License < ApplicationRecord
end

コントローラは以下のようなロジックで実装。

# controller/staff_controller.rb

class StaffController  < ApplicationController

  # 画面に引き渡すインスタンス変数(Hash)
  # @conpany_inf カンパニー情報(ヘッダ情報)
  #   {
  #     company_name [string] カンパニー名
  #     company_started_at [datetime] 創設日
  #     staff_count [integer] スタッフ人数
  #   }
  # @staff_inf スタッフ一覧情報
  #    [{
  #       staff_no: [string] スタッフNO
  #       staff_name: [string] スタッフ名
  #       staff_class: [string] 一般職/管理職
  #       license_info: 資格情報
  #         [{
  #           license_name [string] 資格名
  #           license_get_date [datetime] 取得日
  #         }]
  #   }]


  def index
    @conpany_inf = conpany_inf_rec(company)

    @staff_inf = []
    staffs = company.staffs.order(:staff_no).alive
    staffs.each do |s|
      @staff_inf << staff_inf_rec(s)
    end
  end

  private

  def company
    @company ||= Company.find(params[:id])
  end

  def conpany_inf_rec(company)
    {
      company_name: company&.name
      company_started_at: company.&.started_at
      staff_count: company.staffs.count
     }
  end

  def staff_inf_rec(staff)
    {
      staff_no: staff&.staff_no
      staff_name: staff&.name
      staff_class: staff&.is_manage_lank & 'manage' : 'normal'
      license_info: license_info_rec(staff)
    }
  end

  def license_info_rec(staff)
    staff.licenses.order(:get_date).map do |li|
      {
        license_name: li.name
        license_get_date: li.get_date
      }
    end
  end
end

rails:判定ロジックサンプル備忘1

以下のようなケースの判定ロジックを考える。
モデルで以下のように定数定義。
app/models/worker.rb

class Worker < ApplicationRecord
  WORKER_TYPES = { TEACHER: 1, PILOT: 2 }.each_value(&:freeze).freeze
end

デコレータは以下のように継承して定義。
app/decorators/

class WorkerDecorator < ApplicationDecorator
end

class TeacherDecorator < WorkerDecorator
end

class PilotDecorator < WorkerDecorator
end

ロジックでは以下のように判定して利用する。

decorate_worker = 
  if params[:worker_type] == Worker::WORKER_TYPES[:TEACHER].to_s
    TeacherDecorator.decorate(worker)
  else
    PilotDecorator.decorate(worker)
  end
puts decorate_worker.abillity

上記を、メソッド化して、以下のように整理。
メソッドからは、クラスを返却している。

decorate_worker = worker_decorator(params[:worker_type]).decorate(worker)
puts decorate_worker.abillity

def teacher?(worker_type)
  worker_type == Worker::WORKER_TYPES[:TEACHER].to_s
end

def pilot?(worker_type)
  !teacher?(worker_type)
end

def worker_decorator(worker_type)
  # classを返却
  teacher?(worker_type) ? TeacherDecorator : PilotDecorator
end

メソッド化しないのであれば、省略記述できるが、可読性は下がる。
以下、記述例。

# ex1
decorator = params[:worker_type] == Worker::WORKER_TYPES[:TEACHER].to_s ? TeacherDecorator : PilotDecorator
decorate_worker = decorator.decorate(worker)

# ex2
decorator = params[:worker_type] == Worker::WORKER_TYPES[:TEACHER].to_s ? TeacherDecorator : PilotDecorator
decorate_worker = decorator.decorate(worker)

# ex3
decorate_worker = decorator(params[:worker_type]).decorate(worker)

def decorator(worker_type)
  worker_type == Worker::WORKER_TYPES[:TEACHER].to_s ? TeacherDecorator : PilotDecorator
end

ruby:ハッシュ操作の基本

ハッシュの基本操作。

>> seeds = {"unk"=>0, "par"=>3, "rog"=>1}
=> {"unk"=>0, "par"=>3, "rog"=>1}
>> seeds["par"]
=> 3

>> seeds_s = {unk: 0, par: 3, rog: 1}                                                                           
=> {:unk=>0, :par=>3, :rog=>1}
>> seeds_s[:par]
=> 3

>> a = seeds_s.fetch(:par)
=> 3
>> a = seeds_s.fetch(:zwo)                                                                                      
Traceback (most recent call last):
        1: from (irb):83:in `fetch`
KeyError (key not found: :zwo)
# 存在しないキー指定するとエラー

>> seeds_s.store(:zwo, 2)                                                                                       
=> 2
>> seeds_s
=> {:unk=>0, :par=>3, :rog=>1, :zwo=>2}
>> seeds_s.size
=> 4

# keyの存在判定
>> seeds_s.include?(:super)
=> false
>> seeds_s.include?(:zwo)
=> true

keyを変数から設定。

>> seeds_s = {unk: 0, par: 3, rog: 1}
=> {:unk=>0, :par=>3, :rog=>1}
>> a = "zog"
=> "zog"

>> seeds_s.store(a.to_s, 9)
=> 9
>> seeds_s
=> {:unk=>0, :par=>3, :rog=>1, "zog"=>9}

イテレータの操作。

# イテレータ(繰り返しメソッド)
>> seeds_s.each {|s| puts s}
unk
0
par
3
rog
1
zwo
2
=> {:unk=>0, :par=>3, :rog=>1, :zwo=>2}
>> seeds_s.each {|key,value| puts key.to_s + ":"+ value.to_s}                                                   
unk:0
par:3
rog:1
zwo:2
=> {:unk=>0, :par=>3, :rog=>1, :zwo=>2}
# each_key, each_valueでキーのみ、値のみの取得も可能

# 配列に変換
>> seeds_a = seeds_s.map {|k,v| [k,v]}
=> [[:unk, 0], [:par, 3], [:rog, 1], [:zwo, 2]]
>> seeds_a[0]
=> [:unk, 0]

>> seeds_a = seeds_s.map {|k,v| {k.to_sym=>v}}
=> [{:unk=>0}, {:par=>3}, {:rog=>1}, {:zwo=>2}]
>> seeds_a[0]
=> {:unk=>0}
>> seeds_a[0][:unk]
=> 0

その他。

# デフォルト指定(未登録キー指定時の返却)
>> z = Hash.new("default")
=> {}
>> z
=> {}
>> z[:key]
=> "default"

ruby:配列(Array)操作の基本

配列の基本操作。

>> names = ['Luf','Zor','Nam']                                                                                  
=> ["Luf", "Zor", "Nam"]
>> names[0]
=> "Luf"
>> names.size
=> 3
>> names[4] = 'Uso'
=> "Uso"
>> names
=> ["Luf", "Zor", "Nam", nil, "Uso"]
>> names.push('San')
=> ["Luf", "Zor", "Nam", nil, "Uso", "San"]

イテレータを使用した操作。

# イテレータ(繰り返しメソッド)
>> names.each do |n|
?>   puts n
>> end
Luf
Zor
Nam

Uso
=> ["Luf", "Zor", "Nam", nil, "Uso", "San"]


# 別の配列にセット
# conpact:nilを取り除く
>> names_a = names.map {|n| n}.compact
=> ["Luf", "Zor", "Nam", "Uso", "San"]
>> names_a
=> ["Luf", "Zor", "Nam", "Uso", "San"]
>> names
=> ["Luf", "Zor", "Nam", nil, "Uso", "San"]


# eachで埋め返す場合は手間がかかるのでmap推奨
>> names_b = []
=> []
>> names.each {|n| names_b << n}
=> ["Luf", "Zor", "Nam", nil, "Uso", "San"]
>> names_b
=> ["Luf", "Zor", "Nam", nil, "Uso", "San"]


# each_with_index
>> names.each_with_index {|n, i| puts n + ':' + i.to_s if n.present? }
Luf:0
Zor:1
Nam:2
Uso:4
San:5
=> ["Luf", "Zor", "Nam", nil, "Uso", "San"]


# select ブロックで評価した値が真だった要素を全て含む配列を返す
>> names_a.select {|n| n.include?("a")}                                                                         
=> ["Nam", "San"]

文字列からの配列作成。

# 文字列から配列作成
>> sea = %w[east west center]
=> ["east", "west", "center"]

# 文字列から配列作成(symbolとして作成)
>> sea = %i[east west center]
=> [:east, :west, :center]

rails:検索時にリテラルのselect句やjoin句を使う

一般的だと思うけど、覚書。

controllerではモデルのリテラルを指定して検索。

controller/tallent_controller.rb

class TallentController  < ApplicationController
  def index
    @tallents = Tallent.select(Tallent::SELECT_STR)
      .joins(Tallent::JOIN_STR)
      .order(name: 'asc')
  end
end

モデル側に、select句やjoin句のリテラルを定義しておく。 (記述する場所はモデルでなくてもよい)

model/tallent.rb

class Tallent < ApplicationRecord
  SELECT_STR = "
    tallents.id AS tallent_id,
    tallents.name AS tallent_name,
    pirates_corps.name AS pirates_corps_name
  "
  JOIN_STR = "
    LEFT OUTER JOIN
      pirates_corps
    ON
      tallents.pirate_corp_id = pirates_corps.id
  "
end

Markdown:記法メモ


特殊文字をそのまま表示

バックスラッシュでエスケープします。

\```

```

コード(pre記法)

  • 整形済みテキストの記法
  • HTMLの<pre>タグに相当
  • 行頭に4つ以上の半角スペースか1つ以上のタブをつける
  • もしくは、段落の前後に「```」ではじまる行をつける
  • 「```ruby」のように、書式指定可能

```
hello ruby
```

hello ruby

```ruby
def index
array.each do |a|
puts a
end
end
```

def index  
  array.each do |a|  
    puts a  
  end  
end  

インラインコード

ここでは`hello ruby`のように記載する

ここではhello rubyのように記載する

見出し

# 見出し 
## 見出し
### 見出し
#### 見出し
##### 見出し
###### 見出し

見出し

見出し

見出し

見出し

見出し
見出し

引用

> 引用です
>
>> ネスト
>

引用です

ネスト

改行

改行したい場所[半角スペース][半角スペース]or<br> 


|指定無し|左寄せ|中央寄せ|右寄せ|
|--------|:-----|:------:|-----:|
|100     |200   |300     |400   | 
指定無し 左寄せ 中央寄せ 右寄せ
100 200 300 400