3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Rails] アクティブハッシュから値を取得する

Posted at

はじめに

現在、チーム開発でフリマアプリを作成しています。

出品された商品の購入確認画面にて買い手が登録した住所の県名をデータを格納しているモデルより、取得して表示したかったのですが、なかなか上手くいかず時間がかかったので、解決先の一つを記載したいと思います。

今回、県名データは”アクティブハッシュ”というものを使用して、県名データを格納しています。
アクティブハッシュについて、わかりやすい記事があったので、下記にリンクを貼っておきます。
↓↓
active_hashまとめ

開発の仕様とコード

ruby :2.5.1p57
Rails :5.2.4.2

#routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: {
    registrations: 'users/registrations',
  }
  devise_scope :user do
    get 'sending_destinations', to: 'users/registrations#new_sending_destination'
    post 'sending_destinations', to: 'users/registrations#create_sending_destination'
  end

  root "items#index"

  resources :items do
    collection do
      get 'item_show'
      get 'get_category_children', defaults: { format: 'json' }
      get 'get_category_grandchildren', defaults: { format: 'json' }
    end
    resources :purchases, only: :show do
      collection do
        post 'pay'
        get 'complete'
      end
    end
  end
end
# prefecture.rb(アクティブハッシュ使用)

class Prefecture < ActiveHash::Base
  include ActiveHash::Associations
  has_many :items

  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]
end

#結論から言うと

以下のコントローラーとビューから表示が可能です。

#controller.rb

class PurchasesController < ApplicationController
  def show
    @item = Item.find(params[:id])
    @item_img = @item.item_imgs.find(params[:id])
    @sending_destination = current_user.sending_destination
    prefecture = Prefecture.data.detect{|o| o[:id] == @sending_destination.prefecture_id}
    @prefectureName = prefecture[:name]
  end  
end

# show.html.haml(商品購入確認画面)

.details-content__info
  .details-content__inner
   配送先
    %address.details-content__user
      ="〒 #{@sending_destination.post_code}"
      %br
      %br
        = @prefectureName + @sending_destination.city
      %br
        = @sending_destination.house_number + @sending_destination.building_name
    = link_to "#", class: 'details-content__fix' do
      %span 変更する
      = icon 'fas', 'chevron-right'

#つまずいたところ

1番最初は下記のような感じ行けないかなーってコントローラーに
@sending_destinationを記載していました。

#controller.rb

class PurchasesController < ApplicationController
  def show
    @item = Item.find(params[:id])
    @item_img = @item.item_imgs.find(params[:id])
    @sending_destination = current_user.sending_destination.prefecture_id
  end  
end

っていうのもsending_destinationsテーブルを以下にしていたからです。

class CreateSendingDestinations < ActiveRecord::Migration[5.2]
  def change
    create_table :sending_destinations do |t|
      t.string :destination_first_name, null: false
      t.string :destination_family_name, null: false
      t.string :destination_first_name_kana, null: false
      t.string :destination_family_name_kana, null: false
      t.integer :post_code, null: false
      t.integer :prefecture_id, null: false
      t.string :city, null: false
      t.string :house_number, null: false
      t.string :building_name
      t.integer :phone_number, unique: true
      t.references :user, null: false, foreign_key: true
      t.timestamps
    end
  end
end

でも、フツーに考えて、prefecture_idとして数字が格納されているだけなので、仮に表示させたとしてもおかしいですよね笑

でも、上記のprefedture_idと上述したprefecture.rbのハッシュのidキーが一致したらOKじゃね?と考えたので、それを実現するにはどうしよかとまず考えました。

で、県名は配列(self.data)の中のハッシュの中に入っているので、配列をもってきてハッシュから取り出したら、いけるくね?って考えました。

で、どのメソッドを使って実現しようかなって思って、白羽の矢が立ったのが、selectメソッドでした。

【初心者必見】Rubyのselectメソッドの基礎から応用まで解説

で、書いたコードが下記の通り。

class PurchasesController < ApplicationController
  def show
    @item = Item.find(params[:id])
    @item_img = @item.item_imgs.find(params[:id])
    @sending_destination = current_user.sending_destination
    prefecture = Prefecture.data.select{|o| o[:id] == @sending_destination.prefecture_id}.first
    @prefectureName = prefecture[:name]
  end
end

これでやれば、以下の通り表示ができました。

#でも

いろいろ調べてたら、selectメソッドってデメリットもあるらしいです。

selectメソッドを用いると、配列の要素を全てチェックすることになり、配列の要素数が多くなればなるほど実行完了までの時間がかかることになります。
条件にマッチする最初の要素を見つけた時点で、要素の探索を終了するほうがパフォーマンス上望ましいですよね。

意外と知らない便利なRuby/Railsメソッド5選

#だから、こうした


class PurchasesController < ApplicationController
  def show
    @item = Item.find(params[:id])
    @item_img = @item.item_imgs.find(params[:id])
    @sending_destination = current_user.sending_destination
    prefecture = Prefecture.data.detect{|o| o[:id] == @sending_destination.prefecture_id}
    @prefectureName = prefecture[:name]
  end  
end

これで、selectメソッドより少ない労力で検索できるようになります。

#最後に
自分みたいな初学者は、

とりあえずコード書いて、動かしてみる!
で、動いた!よし!

みたいなところがあると思うので、なかなか上記したような所謂”よりよいコード”っていうのが、わからないかなーと思います。(これがそもそもいいコードなのかはわかりませんが。)
でも、書いてみて調べてみてって時間をかけないとわからないことばかりなので、結論やるしかないということです笑
そんな感じで以上です。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?