はじめに
現在、チーム開発でフリマアプリを作成しています。
出品された商品の購入確認画面にて買い手が登録した住所の県名をデータを格納しているモデルより、取得して表示したかったのですが、なかなか上手くいかず時間がかかったので、解決先の一つを記載したいと思います。
今回、県名データは”アクティブハッシュ”というものを使用して、県名データを格納しています。
アクティブハッシュについて、わかりやすい記事があったので、下記にリンクを貼っておきます。
↓↓
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メソッドを用いると、配列の要素を全てチェックすることになり、配列の要素数が多くなればなるほど実行完了までの時間がかかることになります。
条件にマッチする最初の要素を見つけた時点で、要素の探索を終了するほうがパフォーマンス上望ましいですよね。
#だから、こうした
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メソッドより少ない労力で検索できるようになります。
#最後に
自分みたいな初学者は、
とりあえずコード書いて、動かしてみる!
で、動いた!よし!
みたいなところがあると思うので、なかなか上記したような所謂”よりよいコード”っていうのが、わからないかなーと思います。(これがそもそもいいコードなのかはわかりませんが。)
でも、書いてみて調べてみてって時間をかけないとわからないことばかりなので、結論やるしかないということです笑
そんな感じで以上です。