ransack, ransack, ransack

Post on 27-Aug-2014

213 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Introducing ransack gem.

TRANSCRIPT

Ransack, Ransack, RansackAgileware kaigi 1

2014.7.25 @maimai77

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')"

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%')"

辛くなってきた…

Searching ActiveRecord ;<

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

Ransack

What is Ransack?

ransack [rˈænsæk]

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

What is Ransack?

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

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

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

4 ドキュメントが貧弱

How to use Ransack

In your Gemfile:

gem 'ransack'

> bundle install

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

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%')"

Search argument keys

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

ransackable_attribute + predicate(述語)

ex)

4 name_eq

4 name_cont

Ransackable_attributes

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

defaultはIssue.column_namesと同じ

Predicates

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

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

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%')"

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

More Ransack

Complex search

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

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

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

More and more Ransack

More complex search

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

What is ransacker?

customized ransackable_attribute

ransackerメソッドで追加する

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'"

Define ransacker

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

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

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 '%大阪府大阪市%')"

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'"

Define ransacker

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

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

割愛。

Conclusion

Conclusion

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

top related