ransack, ransack, ransack

29
Ransack, Ransack, Ransack Agilewar e kaigi 1 2014.7.25 @maimai77

Upload: keisuke-ohta

Post on 27-Aug-2014

213 views

Category:

Software


2 download

DESCRIPTION

Introducing ransack gem.

TRANSCRIPT

Page 1: ransack, ransack, ransack

Ransack, Ransack, RansackAgileware kaigi 1

2014.7.25 @maimai77

Page 2: ransack, ransack, ransack

Searching ActiveRecord!

一致検索はそこそこできるIssue.where(name: 'hoge').to_sql#=> "SELECT `issues`.* FROM `issues` WHERE `issues`.`name` = 'hoge'"

Issue.where(name: ['hoge', 'fuga']).to_sql#=> "SELECT `issues`.* FROM `issues` WHERE `issues`.`name` IN ('hoge', 'fuga')"

Page 3: ransack, ransack, ransack

Searching ActiveRecord...

大小比較、部分一致は得意じゃないIssue.where("id < ?", 3).to_sql#=> "SELECT `issues`.* FROM `issues` WHERE (id < 3)"Issue.where("name LIKE ?", '%hoge%').to_sql#=> "SELECT `issues`.* FROM `issues` WHERE (name LIKE '%hoge%')"

辛くなってきた…

Page 4: ransack, ransack, ransack

Searching ActiveRecord ;<

OR検索になるともうダメな子4 Arel → 可読性 #とは4 独自の検索クラス → 誰がメンテすんの?4 生SQL → 心が折れそうだ…

Page 5: ransack, ransack, ransack

Ransack

Page 6: ransack, ransack, ransack

What is Ransack?

ransack [rˈænsæk]

〈場所を〉くまなく探る[探す], あさり回る

Page 7: ransack, ransack, ransack

What is Ransack?

ransack gemhttps://github.com/activerecord-hackery/ransack

4 ActiveRecordを拡張して検索機能をつけるgem

4 設定なしで一通りの検索をカバー4 high googleability → googleトップがgithub

4 ドキュメントが貧弱

Page 8: ransack, ransack, ransack

How to use Ransack

In your Gemfile:

gem 'ransack'

> bundle install

Rails4, 4.1用に最適化されたbranchもある

Page 9: ransack, ransack, ransack

Extend ActiveRecord

>bundle exec rails g model Issue name:string>bundle exec rake db:migrate

class Issue < ActiveRecord::Baseend

でIssue.search(name_cont: 'hoge').result.to_sql#=> "SELECT `issues`.* FROM `issues`# WHERE (`issues`.`name` LIKE '%hoge%')"

Page 10: ransack, ransack, ransack

Search argument keys

Issue.search(name_cont: 'hoge').result

ransackable_attribute + predicate(述語)

ex)

4 name_eq

4 name_cont

Page 11: ransack, ransack, ransack

Ransackable_attributes

Issue.ransackable_attributes#=> ["id", "name", "created_at", "updated_at"]

defaultはIssue.column_namesと同じ

Page 12: ransack, ransack, ransack

Predicates

eq, gt, gteq, lt, lteq, in, cont, start, end and more

https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching

Page 13: ransack, ransack, ransack

Alias method

class Issue < ActiveRecord::Base def self.search 'hoge' endend

Issue.search#=> 'hoge'

Issue.ransack(name_cont: 'hoge').result.to_sql#=> "SELECT `issues`.* FROM `issues`# WHERE (`issues`.`name` LIKE '%hoge%')"

Page 14: ransack, ransack, ransack

このあたりまではパーフェクトRuby on Railsにもちらっと書いてます。

Page 15: ransack, ransack, ransack

More Ransack

Page 16: ransack, ransack, ransack

Complex search

4 2つのカラムのいずれかが指定した値と一致4 関連先のテーブルを検索する

Page 17: ransack, ransack, ransack

Complex search

4 2つのカラムのいずれかが指定した値と一致Issue.ransack(name_or_memo_eq: 'hoge').result.to_sql#=> "SELECT `issues`.* FROM `issues`# WHERE ((`issues`.`name` = 'hoge' OR `issues`.`memo` = 'hoge'))"

and, or で結合した ransackable_attribute も ransackable

Page 18: ransack, ransack, ransack

Complex search

4 関連先のテーブルを検索するclass Issue < ActiveRecord::Base belong_to :projectend

Issue.search(project_name_eq: 'hoge').result.to_sql#=> "SELECT `issues`.* FROM `issues`# LEFT OUTER JOIN `projects` ON `projects`.`id` = `issues`.`project_id`# WHERE `projects`.`name` = 'hoge'"

association + ransackable_attribute も ransackable

Page 19: ransack, ransack, ransack

More and more Ransack

Page 20: ransack, ransack, ransack

More complex search

4 逆順の文字列と一致するものを検索4 2つのカラムの値を結合したものと比較4 半角スペースを無視した検索組み合わせだけじゃなんとも…→ ransacker

Page 21: ransack, ransack, ransack

What is ransacker?

customized ransackable_attribute

ransackerメソッドで追加する

Page 22: ransack, ransack, ransack

Define ransacker

4 逆順の文字列と一致するものを検索class Issue < ActiveRecord::Base ransacker :reversed_name, formatter: proc { |v| v.reverse } do |parent| parent.table[:name] endend

Issue.search(reversed_name_eq: 'hoge').result.to_sql#=> "SELECT `issues`.* FROM `issues` WHERE `issues`.`name` = 'egoh'"

Page 23: ransack, ransack, ransack

Define ransacker

formatter: 検索に渡したvalueを加工するproc { |v| v.reverse }.call('hoge')#=> "egoh"

block: 検索対象のカラムを決定する

Page 24: ransack, ransack, ransack

Define ransacker

4 2つのカラムの値を結合したものと比較class Address < ActiveRecord::Base ransacker :address do |parent| Arel::Nodes::NamedFunction.new( 'CONCAT', [parent.table[:region],parent.table[:city]] ) endend

Address.search(address_cont: '大阪府大阪市')

#=> "SELECT `addresses`.* FROM `addresses`# WHERE (CONCAT(`addresses`.`region`, '', `addresses`.`city`)# LIKE '%大阪府大阪市%')"

Page 25: ransack, ransack, ransack

Define ransacker

4 半角スペースを無視した検索ransacker :name_without_spaces, formatter: proc { |v| v.gsub(' ', '') } do |parent| Arel::Nodes::NamedFunction.new( 'REPLACE', [parent.table[:name], ' ', ''] )end

Issue.search(name_without_spaces_eq: 'h o g e').result.to_sql#=> "SELECT `issues`.* FROM `issues`# WHERE REPLACE(`issues`.`name`, ' ', '') = 'hoge'"

Page 26: ransack, ransack, ransack

Define ransacker

NamedFunctionはDB依存しがちなので注意なんかいい方法あったら教えてください

Page 27: ransack, ransack, ransack

Custom Predicate

config/initializers/ransack.rb で定義Ransack.configure do |config| config.add_predicate 'equals_diddly', arel_predicate: 'eq', formatter: proc { |v| "#{v}-diddly" }, validator: proc { |v| v.present? }, compounds: true, type: :stringend

割愛。

Page 28: ransack, ransack, ransack

Conclusion

Page 29: ransack, ransack, ransack

Conclusion

4 機能として検索画面が必要ならとりあえずransack使う4 複雑な検索が必要になっても生SQLに逃げない4 Arelとはちょっと向き合う4 view helperも色々できる4 でもorの結合くらいwhereでできるようになって欲しい