Rails6のバージョンアップについて
最近WEB+DB PRESS vol.111を読んで今さらながらRais6に気づいたので、Rails6の新機能をブログにまとめようと思います
ていうかバージョン上げよう...
・ActionMailbox
名前の通りメールができる機能、
メールの受信はもちろん転送や返信、
プロバイダの指定、
取得した情報をデータベースに保存などが出来る
・ActionText
テキストの編集機能を追加出来る新機能、
wordとかexcelとかhatenablogみたいな書式編集が出来る、
ドラッグアンドドロップで画像の追加が出来る、
form.rich_text_areaで簡単に作成、本当にリッチ
・複数データベース
database.ymlで指定することで指定された複数のデータベースに保存されるようになる
・Zeitwerk
Zeitwerkという効率的で早いオートロードシステム
実行順序に依存するオートロード定数のエッジケースも解消
名前空間にあるものは遅延される
・ActiveRecord: :Relation#pick
whereやlimitを使っていた検索をpickで行える
例えばUserテーブルからageが20より多いのもののidを取得する時rails6では
User.where("age>20").limit(1).plunk(:id).first が
User.where("age>20").limit(1).pick(:id) となる
・create_or_find_byメソッド
レコードがなければ作成を行い、レコードがあれば作成しないメソッドに従来は find_or_create_by メソッドを使っていたが、 find_or_create_by ではSQLのSELECTからINSERTを行う際に時間差があるため、その間にSELECTで取得したレコードが古くなってしまう問題があった
create_or_find_byメソッドではINSERTを行い、ユニーク制約のエラーが発生した場合は、SELECTでレコードを取得する
create_or_find_byの注意点としてメソッドを使用する際には、あらかじめユニーク制約を設定する必要があること、レコードの作成よりも参照が多い場合は処理自体が遅くなる可能性があること、また、レコードが作成できない場合の例外がある
・insert_allメソッド
複数件のレコードを一括でINSERTできるメソッド
今まではBULK INSERTという方法を使っていた
他にもまだまだアップデートした点はある様
変更点の多さから今回は特に大きなアップデートだったとわかる
Railsはどんどん便利になっていくと感じた
AltJSについて
AltjsとはJavascriptの弱点(文法の複雑さ、動的型付け)を補うために、Javascriptにコンパイルして代替される言語のこと
Altjsのメリット...Javascriptよりコードが読みやすい、変更しやすく再利用しやすい(保守性が高い)
デメリット...Javascriptにコンパイルする手間がある、エラーが発生した時のjavascriptがAltjsのどこに相当するのか調べないといけない
<主なAltjsの例>
・Typescript
中〜大規模開発の際jsに代替されるaltjs。オブジェクト指向。AngularJSで採用。javascriptとの互換性を持つ。javascriptとの大きな違いはjsが動的型付けなのに対しtypescriptは静的型付けであること。静的型付けであることにより大規模開発の際、変数の型によるバグを防ぐことでより堅牢なアプリケーション作成を可能にする。
・CoffeScript
文法がRubyやPythonっぽくてコード量が少なくて済み、コンパイル後のjsも綺麗。Railsで標準的にサポートされている(rails newで自動的に生成される、$rails new --skip-coffeeで作成されない)、Asset Pipelineという機能によって、自動でコンパイルされる。関数スコープに従って適切な位置で変数の自動生成される。
・PureScript
javascriptのオブジェクト指向と異なり関数型言語でHaskellっぽい。mapやfilter、reduceなどのメソッドをもつ。
・Elm
わりかし新しい言語。2019年わざわざ学ばなくていいプログラミング言語1位。jsの他html,cssにコンパイルされる。Haskellベースで協力な静的型付け言語で純粋関数型言語。Reactなどと同じでフレームワークとなるがJSフレームワークに比べて描画が速い、SPA(SinglePageApplication)に向いてる。型検査されるためコンパイル後に壊れない
Barba.js触ってみた
pjaxの流れでBarba.js触ってみた
ざっくり言うとBarba.jsとはpjaxの簡単バージョン
はっきり言ってそこまで差わかってない
メリット...ページ遷移が早くて楽しい、アニメーション楽しい
デメリット...読み込み時のscriptが動かない、実態は最初に閲覧したページのため、相対パスがずれる、meta情報が変わらない、学習コスト高め
けどBarbaの方がpjaxより学習コスト低い
$(function(){
$.pjax({
areas: ['#container','side'],
link : 'a:not([target])',
update: {head: 'base, meta'},
wait : 500
});
});
areas...更新する範囲の指定。複数ある場合はコンマ区切り
link...pjaxを適用させるリンクを設定
update...更新させたいものを指定できます。baseタグ、metaタグ、linkタグ、scriptタグを指定する事ができます。
wait...リンクをクリックしてからの遅延時間
pjax初心者
pjaxをちょっと触ったのでまとめて見ました
フロントやってた人に聞いた話じゃアメリカではajaxよりpjaxらしい
Pjax = pushState + Ajax のjQeuryのプラグインのこと
pushStateとはHTML5から追加されたHistory APIのメソッドで、ざっくり言うと「履歴の変更」ができる。ブラウザの履歴情報をページ遷移せずに変更するメソッドのこと
history.pushState(state,title,url); のように使い
第1引数stateで履歴に関するオブジェクト
第2引数titleで履歴のタイトルを指定
第3引数urlで履歴のurlを指定、絶対パス相対パスどちらでもOK
AjaxとはAsynchronous JavaScript + XMLのこと
ページ遷移をさせず(非同期処理で)コンテンツを書き換えられる、他の処理と同時並行で、サーバとやりとりができる、サクサク動くページの動きを再現できる
以上のことよりpjaxとは「非同期ページ遷移」の「履歴あり」のこと
<a class="pjaxLink" href="ルーティング"> ←遷移させるボタンとか
ここからhead要素に書く
<script src="/static/javascript/main.js"></script>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery.pjax/1.9.6/jquery.pjax.js"></script>
<script src="pjax.min.js"></script>
<script src="/static/javascript/base.js"></script>
遷移元<section id="pjaxContent" class="pjax-test">に書くid class
(これだと変化させたい部分をsectionで挟む)
jsファイルで指定したid classを変化させる
url: 遷移先パス,
container : 遷移部分,
fragment : 遷移部分,
timeout : 時間
をjsに書く
<おまけ>ラクスルの価格表ページがpjaxらしい
某フリマサイトの検索まとめ(後編)
某フリマサイトのコピーをRailsにて作成した際にransackによる検索をする方法をまとめました
URL:https://github.com/yusuke-ishizaki/freemarket_sample_50b
Ransackによる条件検索
——————————————————
・必要なもの
Gem”ransack” gem”active hash”
—————————————————
・詳細検索作成手順
1. ransack 導入
2. コントローラー記述
3. フォーム制作
4. ActiveHash導入(gem,モデル) ←ここから
5. ActiveHash導入(アソシエーション)
6. フォーム作成2
↓詳細
————————————————
4.ActiveHash 導入
検索する際にセレクトボックスやチェックボックスの記述があるが、ここでデータベース内の値を引っ張ってきたい
このときにActiveHashを用いる
Activehashを用いる状況として
・基本的に’select option’使いたくない
・セレクト数が多くviewに記述したくないとき(ex.都道府県セレクト)
・テーブルを作るほどでもないセレクトメニュー(ex.メルカリのサイズ、状態など)
導入手順
・gem 'active_hash' →bundle install →rails s
・モデルの作成(ここにデータを記述)
→“$rails g model”コマンドを使わずに/app/model/~.rbを作成
→class モデル名(任意) < ActiveHash::Base
self.data = [
{id: 1, name: ’’}, {id: 2, name: ''}
]
end
→データはハッシュでベタ打ち
今回は/app/models/size.rb status.rb
5.ActiveHash導入(アソシエーション)
Activehashに必要なアソシエーションを組んでいく
入力検索フォームで値を引っ張りたいモデル(Product) と activehashでデータを格納してるモデル(Size) でアソシエーションを組みデータを引っ張れるようにする
新しく作ったactivehashモデルにはアソシエーションは書かず、値を引っ張る側にアソシエーション を記述する
/app/models/product.rb
class Product < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to_active_hash :hash先モデル
end
6.フォーム作成2
フォームのセレクト欄とチェックボックスを作成していく
セレクトフォーム…= f.collection_select
チェックボックス…= f.collection_check_boxes
・セレクトフォーム
= f.collection_select(オブジェクト名, オブジェクトの配列, value属性の項目, テキストの項目 [, オプション])
オブジェクト名→属性名:フォームの対象モデルの中の該当する属性名
オブジェクトの配列→配列名:セレクトメニューの選択するのに使用するデータの配列。連想配列かオブジェクト
value属性の項目→valueになるカラム名:セレクトメニューで値として扱うカラムの名前※optionのvalueの値になる
テキストの項目→表示されるカラム名:セレクトメニュー表示名として扱うカラム名
今回は”= f.collection_select :size_eq, Size.all, :id, :name, { include_blank: 'すべて'}, { class: "search-box__detail-search__form-group__input" }”
[search.html.haml L27]
※productのviewの中なのにSize.allが使用できるのはクラスメソッドはどこからでも呼び出せるため
= f.collection_check_boxes オブジェクト名, オブジェクトの配列, value属性の項目, テキストの項目 [, オプション] do |b|
= b.check_box
= b.text
今回は”= f.collection_check_boxes :status, Status.all, :name, :name, prompt: '--' do |b|”
[search.html.haml L39]
某フリマサイトの検索まとめ(前編)
某フリマサイトのコピーをRailsにて作成した際にransackによる検索をする方法をまとめました
URL:https://github.com/yusuke-ishizaki/freemarket_sample_50b
Ransackによる条件検索
——————————————————
・必要なもの
Gem”ransack” gem”active hash”
—————————————————
・詳細検索作成手順
1. ransack 導入
2. コントローラー記述
3. フォーム制作
4. ActiveHash導入(gem,モデル)
5. ActiveHash導入(アソシエーション)
6. フォーム作成2
↓詳細
————————————————
1. Ransack 導入
gemfileに gem’ransack’記述
→bundle install
→rails s
2.コントローラーに記述
検索対象コントローラーにsearchアクションを作成
今回は ’products controller’
→検索オブジェクト作成
@search = Product.ransack(params[:q])
・@search…検索オブジェクト、検索するということの定義、名前なんでも良き
・.ransack…Productのデータを検索するよーという命令メソッド
・params[:q]…検索結果パラメータ、公式より:qにするみたい
→検索オブジェクト結果作成
@products = @search.result
・@products…検索結果オブジェクト、結果の定義、こっちをviewに反映する、名前なんでも良き
・.result…resultメソッド、検索オブジェクトの検索結果を出力する
→まとめ
class ProductController < ApplicationController
def search
@search = Product.ransack(params[:q])
@products = @search.result
end
●[product_controller.rb L64]
<おまけ>distinct: trueや.to_a.uniqを使うことで重複を避けることができる
@search.result(distinct: true) @search.result.to_a.uniq
3.フォーム雛形作成
通常の入力・検索フォームではform_with, form_for, form_tag使う”search_form_for”を用いる
“= search_form_for 検索オブジェクト, url: 検索結果表示ページのpath do |f| “
検索オブジェクトにはcontrollerで定義したもの(今回は@search)を用いる
パスは url: で結果表示先を示す
|f| はform_with系と同様に f.label のように使う
今回は “= search_form_for @search, url: search_product_index_path do |f|”
●[search.html.haml L5]
<おまけ> “= search_form_for(@q, format: :pdf) do |f|” “= search_form_for(@q, format: :json) do |f|” とすることで形式をpdfやjsonに指定できる
キーワード検索フォーム ransack版
“= search_form_for 検索オブジェクト, url: 検索結果表示ページのpath do |f| “のネスト中に
“= f.search_field :カラム_cont, class:クラス名”
search_field…検索入力バーを作成する
カラム_cont…指定カラムに対してLIKE句検索(あいまい検索)を行う
今回は “= f.search_field :name_cont, class: "search-box__detail-search__form-group__input"
●[search.html.haml L15]
★今回name_contとした理由…controllerで@search=Product.ransack とProductモデルに検索をかけるよう指定しているので “nameカラム”に”_cont”しても正確にProduct.nameを検索する(Brand.nameなど他のモデルには手を出さない)
<おまけ>複数カラムあいまい検索…= f.search_field :カラム1_or_カラム2_or_カラム3_cont(orのとこandでもおっけい) 1にname、2にstatus、3にtextなど
検索結果表示
” - @products.each do |product|”
検索結果の表示には、controllerにて定義した検索結果オブジェクト@products
検索結果をソートさせたい
“= sort_link(検索オブジェクト, :カラム, ‘ソートのラベル’, default_order: :desc)”
今回は”= sort_link(@search, :name, '名前順', default_order: :asc)”
●[search.html.haml L6]
価格帯検索したい
”= f.number_field :カラム_gteq, placeholder: 説明, class:クラス名”
”= f.number_field :カラム_lteq, placeholder: 説明, class:クラス名”
_gteq で~以上の検索
_lteq で~以下の検索
●今回は
”= f.number_field :price_gteq, placeholder: "¥ Min", class: "search-box__detail-search__form-group__price-min search-box__detail-search__form-group__input””
” = f.number_field :price_lteq, placeholder: "¥ Max", class: "search-box__detail-search__form-group__price-max search-box__detail-search__form-group__input””
[search.html.haml L32]
—————————————————————
追記
●今回使わなかったけどransackでできること
Predicate検索(カラム名と述語(Predicate)で検索する方法)
*_eq equal(=)を使った検索
*_matches LIKE検索
*_does_not_match LIKE検索で除外されるもの
*_cont LIKE検索(部分一致)
*_start LIKE検索(前方一致)
*_end LIKE検索(後方一致)
*_gt より大きい(>)検索
*_gteq 以上(>=)検索
*_lt より小さい(<)検索
*_lteq 以下(<=)検索
*_true trueのものを検索
*_false falseのものを検索
*_null null(存在しない)ものを検索
*_present present?メソッドに近い NULLでも空文字でもなければマッチ
*_blank blank?メソッドに近い NULLか空文字だったらマッチ
*_not_??? 述語の前にnotをつけることで、否定が可能
*_???_all 末尾にallをつけることで、複数の値に対してANDで連結して検索
*_???_any 末尾にanyをつけることで、複数の値に対してORで連結して検索
= f.attribute_fields do |a|
= a.attribute_select associations: [:アソシエーションしてるモデルのカラム]
でアソシエーションしてるモデルのカラムをセレクトに選ぶことができる
動的に追加されるフォームを作成する方法
・/app/helpers/application_helper.rbにlink_to_add_fieldsメソッドを作成
module ApplicationHelper
def link_to_add_fields(name, f, type)
・フォームのあるhtmlに
= link_to_add_fields “クラス”, f, :カラム
・javascriptで動かす