まさ@ブログ書き込み中

自由に生きるための英語、プログラミング、考えごとについて色々書いています。

脳筋コード脱出のための備忘録

 

こんばんは、まさです。

 

ブログ書くの20日ぶりっていう異常さ。

ぼちぼち学校もバイトも頑張っていて、幸せ継続中です。

 

軽やかに実装したい

色々あって自分でコードを書いてリファクタリングされたことがあったのですが、まあ圧倒的リファクタリングで、これはもう今までの「動けばいいんだろオラオラ」的なコードではなく「無理しなくても動きますよホラホラ」的なコードを書きたいと思いました。例えが伝わっていなかったらすいません。

 

 

大切なのはHTML・CSS・JS・Rubyの得意なことを十分にさせてあげること

僕はプログラミングを初めてついに8ヶ月になりましたが、少し慣れてくると基本的な処理は大体力技でこなせてしまいます。

 

HTML・CSS・JSをもちろんいじったりするのですが、それはそれらを活用することが必要不可欠と思われる時のみ。

 

そのため、僕の頑張りどころの焦点はほぼRubyに向いています。ISUCONで身につけた感覚、すなわち「無駄なクエリは排除する」とか「コードの行数は減らすように頑張ってみる」とか「無駄にインスタンス変数生成しない」とかは意識しているつもりですがWebサービスRubyだけで出来ているわけではありません。Rubyだけでどうにかすると考えている時点で適材適所に失敗しているのだなと今回学びました。

 

 

Rubyでバリデーションする前にHTMLで弾いて、JSで確認しよう

フォームから送られて来たデータを取り入れたインスタンスを保存するまえにvalid?メソッドを呼び出し、問題が起こればerrorメソッドとfull_messagesメソッドをチェーンで呼び出すのは一般的ですが、Modelのvalidationとは別のことをチェックしたければどうすればいいでしょうか。

 

僕の場合はRubyの条件分岐や正規表現を使って裏側でチェックしていたのですが、そもそもHTMLで弾かせる作戦があります。

 

5桁の数字を入力して欲しければ

<input type="number" min="1" max="99999" required>

にすればいいだけのこと。ただ、ブラウザ側からHTMLに変更を加えられてデータが送られた時のために次の手も用意しなければなりません。

 

そこでチェックをJSにやらせてしまうという手があります。

 

これによって、ある程度のバリデーションを終えたデータのみがバックエンド側に送られてきます。それを用いて裏側で保存すればOK。ここでStrong Parametersをしっかり使っておきたいところです。

 

 

Railsをうまくつかう

Railsをうまく使うことに関して今回の件で学んだのは大きくこの二つでした。

  • inputタグのnameの使い方
  • nested_attribute_for

 

inputタグのnameの使い方

HTMLは通常、配列とかハッシュなどのデータ構造に変換して送る機能はありません。よくparamsで取って来たときにハッシュになってたり配列になってたりするのはRailsがよしなにやってくれているわけです。

原則として、HTMLフォームはいかなる構造化データについても関知しません。フォームが生成するのはすべて名前と値のペアであり、これらは単なる文字列です。これらのデータをアプリケーション側で参照した時に配列やハッシュになっているのは、Railsで使用されている命名ルールのパラメータのおかげです。

Action View フォームヘルパー | Rails ガイド

 

ですが、その命名ルールを知らないと理想のデータ構造で値を送ることができません。僕はそれが出来ていませんでした。

 

ハッシュの場合は、name属性の値をネストさせればいいみたいです。params["nation"]["prefecture"]で値を取ってくるにはこうすればいい。

<input type="text" name="params[nation][prefecture]">

 

配列の場合は、空の角かっこを用意すればいいとか。国は一つだけど県が複数ある場合はこんな風に書けばいいんですね。

<input type="text" name="params[japan][ ]">

 

あるキーにハッシュが複数ある、ハッシュの配列はこうすればいいということになります。国は一つで県も一つだけどそれに関して入力すべき情報が複数ある場合。

<input type="text" name="params[japan][okinawa][ ][address]">

<input type="text" name="params[japan][okinawa][ ][name]">

<input type="text" name="params[japan][okinawa][ ][sex]">

<input type="text" name="params[japan][okinawa][ ][email]">

 

nested_attribute_forを使う

あるモデルParentが別のモデルChildrenを多数持つ(has_many)時、accepts_nested_attribute_for :childrenとするだけでParentモデルから一気にChildrenモデルのupdateやcreateが出来るようになるそうな。

 

何がすごいって、allow_destroy_trueとすると削除フラグを使うだけで削除できるようになるそうな。

class Parent < ActiveRecord::Base
 has_many :children, dependent: :destroy
 accepts_nested_attributes_for :children, allow_destroy: true
end

[Rails]accepts_nested_attributes_forの使い方 - Qiita

 

実はさぼさんからアドバイスとしてこれを使ったほうがいいとは言われてたのですが、使い方を複雑に感じてしまったのと、早いうちに実装しないといけなかったので自分なりのやりかたでやってしまったのが間違いでした・・・。

 

parentの名前をアップデートする際にchildrenを削除するにはこうすればいいみたいです。

private
 def parent_params
 params.require(:parent).permit( :name, children_attributes:[ :id, :name, :parent_id, :_destroy ] )
end

 

authorがbookをたくさん持っている場合でも、こんな風のハッシュをデータとして送ってupdateしてしまえばいいみたいです。

{
  :book => {
    :title             => "吾輩は猫である",
    :author_attributes => { :name => "夏目漱石" }
  }
}

Railsでネストしたモデルをまとめて受け取って保存する [俺の備忘録]

 

 

先人から学ぶ

自分一人で道や方法を切り開くことはとても大切ですが、プログラミングを始めてから先人から学ぶことも大切だなと日々実感しています。

 

トライアンドエラーの繰り返しから学んでいくことが上級者への近道だと思っているので、また何かあればこのブログに立ち戻って記録を糧により効率的なコードを書いていきたいと思います。

 

ではまた。