個人的な就職活動を本格化させたので、課題に対するやる気が急速に減退。
というか課題も必要最低限の機能は動いているし、これ以上はやるだけ無駄。勉強したい分野だけ実装して、どうでもいい箇所は放置しないと時間が勿体ない。
rails
htmlエスケープ
古いver.のrailsを除き、通常エスケープされる。≒ 変換される。
これはuserの入力文字列を扱う場合に、そのまま扱うとhtmlタグや属性として認識されるような文字列が含まれていた場合に、それを認識させないようにするための措置である。
ただし、link_toやform_for等のヘルパーメソッドではhtml_safeとして扱われているようで、エスケープ処理が行われない。
controller
@a = "<h1>hogehoge</h1>"
view
= @a
=> &lt;h1&gt;hogehoge&lt;/h1&gt;
.each_slice()
n個の要素をまとめて取り出してブロック内の処理を行う。
items.each_slice(2){ |hoge| hoge.join(",")}
viewだとこんな感じ
- items.each_slice(3) do |elements|
- elements.each do |e|
= e.name
オープンクラス
hash 既存のクラス
.select
配列に対して用いる。
ブロックがtrueになる配列のみを抽出する。
array.select{ |n| 条件}
reject
.selectと逆。
ブロック内がfalseになる配列のみを抽出する。
.class
型を判定できる。
arr=[]
arr.class
=> array
.instance_of?()
引数のクラスのインスタンスかどうか判定できる。
@users = User.all
@users.class
=> array
@users[0].class
=> User(id: integer, name: string, created_at: datetime, updated_at: datetime)
@users[0].instance_of?(User)
=> true
where
配列を渡すこともできる。
where(id: [1,2])
link_to派生
link_to_if
link_to_unless
link_to_unless_current?
例)下記の場合、indexページの場合は単なる文字列で”index”が出力され、
indexページ以外の場合はaタグでindexが出力される。その場合のhrefは/items/index
= link_to_unless_current 'index', '/items/index'
current_page?
current_page?(root_path)
current_page?(action: 'index')
current_page?(controller: 'user', action: 'show')
current_page?('/users/sign_up')
reject
ブロック内の戻り値がtrueの時、key,valueを削除する。
戻り値がハッシュを返すが、変更がなかった場合はnilを返す。
hash.reject {|key, value| block }
delete_if
ブロック内の戻り値がtrueの時、key,valueを削除する。
rejectとほぼ同様だが、変更がない場合もハッシュを返す。
hash.reject {|key, value| block }
空白演算子
posixの空白演算子[:blank:]は正規表現中で通用する。
searchの空白区切で配列に分解する時に便利そう。
"あああ いいい ううう".split(/[[:blank:]]+/)
#=> ['あああ', 'いいい', 'ううう']
@keyword = params[:keyword].to_s.split(/[[:blank:]]+/)
配列の掛け算
a = ["ggg", "ggf"]
a*2
=> ["ggg", "ggf", "ggg", "ggf"]
クエリ
find_each > all.each
find_eachはDBから分割してデータを取得し、メモリ上に展開するのでメモリ効率が良い。
all.eachすると最初に全てのデータを展開するためメモリ効率が悪い。
Hoge.find_each do |fuga|
# 処理
end
キャッシュについて
.cache.fetch
引数で指定したキーに対応するキャッシュがあれば返す、なければ作成して返す。
# ./app/controllers/articles_controller.rb
# 追加したメソッドからarticlesを取得するように変更
def index
# @articles = Article.all
@articles = cache_articles
end
private
def cache_articles
Rails.cache.fetch("cache_articles", expired_in: 60.minutes) do
# Article.all
Article.all.to_a
end
end
ActiveRecord
ActiveRecord::FinderMethods
クエリを即発行する。
ActiveRecord::FinderMethods
find, find_by, take, first, last, exists?
ActiveRecord::Relation
ActiveRecord::Relationのオブジェクトを返す。
遅延評価(Lazy Evaluation)のため、実際にデータが必要になるまではクエリを投げない。
whereやlimitがこれに該当する。
内部実装的にはarelというライブラリで、SQL文を合成する。
@user = User.where('id > ?', 5).limit(3)
@user = @user.where(name: "tanaka")
これはチェーン可能で、分けて書いても
@user = User.where('id > ?', 5).where(name: "tanaka").limit(3)
と解釈されて、SQL文が書かれる。
逆に
@user = User.where('id > ?', 5).take(3)
@user = @user.where(name: "tanaka")
とした場合、takeはActiveRecord::FinderMethodsなのでSQL文をすでに発行しており、内部的にto_aされているため、where句は続けられず、エラーとなる。
@user = User.where('id > ?', 5).to_a
も同様にto_aの時点でクエリが発行されるので、後ろにActiveRecord:Relationメソッドは書けない。
ActiveRecord::Calculations
countやaverageが属す。
詳しく調べていないが、おそらくこれもクエリ即時発行型と思う。
記載順序で挙動が変わるので少なくともRelationとは別の動きをする。
ancestory gem
include他、eager_loadできないため、ツリー一覧を表示する際にN+1問題を生じやすい。
include自体はアソシエーションに対してしか効かないため、ancestoryの.childrenや.parentには効かせられない。
Model.allで取得したインスタンスの配列に対して、selectメソッドで処理するのがクエリ発生数を抑えられるため好ましい。
逆にこれ以外の方法は、別のモデルからアソシエーションでancestoryを使っているモデルを取得するときにincludeするしかない。この場合、カテゴリー一覧のような全件取得はおそらく無理。
%ul.left-box__category
- @category.select{|n| n.ancestry == nil}.each do |big_category|
= link_to big_category.name, search_items_path
%ul.left-box
- @category.select{|n| n.ancestry == big_category.id.to_s}.each do |middle_category|
= link_to middle_category.name, search_items_path
%ul.left-box
- @category.select{|n| n.ancestry == big_category.id.to_s + "/"+middle_category.id.to_s}.each do |small_category|
= link_to small_category.name, search_items_path(category_id: small_category.id)
コメント