modelに存在しないカラムを仮想的に存在させた状態にする
Railsで登録フォームなどを作っている時に「ここの入力フォームを2つに分割して書かせるようにしたい」という場面がありました。
僕みたいな初心者railsエンジニアは、「DBの設計から変更しなきゃ….」と考えてしまうのですが、先輩に聞くと vartial attributes という方法を使えば簡単に実装できるというので、実際に使ってみました。
vartual attributes(仮想属性)とは
vartual attributesとは、読んで字のごとく仮想的な属性のことです。
これを用いることで、上に書いたようにデータベースを変更しないで、登録・編集フォームを変更することができます。
今回の使用状況
郵便番号の登録フォームを上3桁、下4桁の分割したフォームに変更させる。
例)123-4567の様に"-“をフォームに追加する。
手順
1. 郵便番号を上3桁、下3桁の属性に分ける
# /models/address.rb #table: adresses #column #string: address class Address < ApplicationRecord attr_writer :first_address, :last_address validates :address, format: { with: /\A\d{7}\z/ } validates :first_address, presence: true validates :last_address, presence: true #先にset_addressを呼ばないとバリデーションエラーになる before_validation :set_address def first_address @first_address || self.address[0..2] if self.address.present? end def last_address @last_address || self.address[3..6] if self.address.present? end #DBカラムはaddressのため、バリデーション前に結合して設定する def set_address self.address = [@first_address, @last_address].join end end
ここでfirst_addressとlast_addressというVirtual Attributes(仮想属性)を追加しています。
注目箇所は、attr_writerというRubyモジュールです。
attr_writerメソッドは、クラスやモジュールにインスタンス変数を書き込むためのアクセサメソッドを定義します。
attr_writerメソッドを使うことで、書き込み用のaddressカラムを分けることができているということになります。
やってないけど、もしフォームで作成したaddressに"-“表示するためには、attr_accesorメソッドを使えばいいってことかな??
あと
def first_address @first_address || self.address[0..2] if self.address.present? end
この文では、住所に入る数値の制限も書かれているのがわかります。
これで、first_address、last_addressという、属性が追加されました。
2. view画面に郵便番号入力欄を追加する
次に郵便番号入力欄を2つに分けて入力できるようにします。
#views/addresses/_form.html.haml = form_for @address do |f| - if @address.errors.any? #error_explanation %h2= "#{pluralize(@address.errors.count, "error")}" %ul - @address.errors.full_messages.each do |msg| %li= msg .field = f.label :address = f.text_field :first_address = f.text_field :last_address .actions = f.submit 'Save'
二つに分けた"“f.text_field”“を追加で書きます。
3. StrongPararametersにfirst_addressとlast_addressの入力を許可させる
最後にcontrollerのStrongPararametersにfirst_addressとlast_addressの入力を許可させます。
#controllers/addresses_controller.rb private def address_params params.require(:address).permit(:first_address, :last_address) end end
フォーム画面
これで追加できるようになったかと。
とりあえずひと安心。。。