今回は、Railsで検索機能を簡単に実装できるgem「Ransack」のREADMEを翻訳してみました。Ransackの知識が曖昧な方、Ransackについて深掘りしたい方の参考になればと思います。
Github
原文はこちらを参照してください。
Ransack

Ransackを使用することで、Ruby on Railsアプリケーションの単純な検索フォームと高度な検索フォームの両方を作成できます(デモソースコードはこちら)。モデルまたはコントローラーレイヤーでのクエリ生成を簡素化するものを探している場合は、Ransack(またはMetaSearch)はふさわしくありません。代わりにSqueelを試しましょう。
始め方
Ransackは、Ruby2.3以降のRails6.0、5.0、5.1、および5.2と互換性があります。
最後に公式にリリースされたgemを使用したい場合は、Gemfileに以下の記述を:
gem 'ransack'
最新のアップデートされたもの(推奨)を使用する場合は、masterブランチを使用してください。
gem 'ransack', github: 'activerecord-hackery/ransack'
イシュートラッカー
- イシューを作成する前に、コントリビューティングガイドに目を通してください。
- Ransackによって新たなバグ(まだ報告されていないもの)が発生した場合は、イシューを作成してください。
- コントリビューションは歓迎です。しかし、イシューに”+1″のコメントやプルリクエストを送ることはしないでください😃
- 個人のサポートを要求するためにイシュートラッカーは使用しないでください。Stack Overflowがあなたをサポートしてくれる良い場です。
使い方
Ransackは、シンプルモードとアドバンストモードの2つのモードを使用できます。
シンプルモード
このモードはメタサーチのような動きをし、とても少ない労力でセットアップすることができます。
シンプルモードを使用する場合の注意点としては以下です。
- デフォルトで送られるparamsのキーは「:search」ではなく「:q」です。これは主にクエリの文字列を短くするためですが、高度なクエリ(下記)はほとんどのブラウザでURLの長さの制限に違反し、HTTP POSTリクエストへの切り替えが必要です。このキーは設定可能です。
- form_forはsearch_form_forになり、Ransack::Searchオブジェクトが渡されたことを検証します。
- 一般的なActiveRecord::Relationメソッドは、検索オブジェクトによって処理を任せることはなくなりました。代わりにRansack#resultを呼び出すことで検索結果(ActiveRecordアダプターの場合はActiveRecord::Relation)を取得します。
コントローラー
def index
@q = Person.ransack(params[:q])
@people = @q.result(distinct: true)
end
関連付けられたテーブルのカラム(この例では、各々の記事とページネーションをpreloadします)でソートしたい場合はdistinct: trueを記述しません。
def index
@q = Person.ransack(params[:q])
@people = @q.result.includes(:articles).page(params[:page])
# or use `to_a.uniq` to remove duplicates (can also be done in the view):
@people = @q.result.includes(:articles).page(params[:page]).to_a.uniq
end
ビュー
2つの主要なRansackのビューヘルパーはsearch_form_forとsort_linkで、Ransack::Helpers::FormHelperに定義されています。
検索フォームを作成するには、form_forがRansackのsearch_form_forに置き換わります。
<%= search_form_for @q do |f| %>
# Search if the name field contains...
<%= f.label :name_cont %>
<%= f.search_field :name_cont %>
# Search if an associated articles.title starts with...
<%= f.label :articles_title_start %>
<%= f.search_field :articles_title_start %>
# Attributes may be chained. Search multiple attributes for one value...
<%= f.label :name_or_description_or_email_or_articles_title_cont %>
<%= f.search_field :name_or_description_or_email_or_articles_title_cont %>
<%= f.submit %>
<% end %>
f.search_fieldの引数は、「attribute_name[_or_attribute_name]…_ predicate」の形式にする必要があります。加えて「[_or_another_attribute_name]…」は_or_とname属性の繰り返しを意味しています。
cont(contains)とstart(start with)の2つは、利用可能な検索述語です。
全ての詳細はConstrantsとwikiを参照してください。
search_form_forの出力形式は次のように設定されます。
<%= search_form_for(@q, format: :pdf) do |f| %>
<%= search_form_for(@q, format: :json) do |f| %>
Ransackのsort_linkヘルパーは、分類可能なリンクであるテーブルヘッダーを作成します。
<%= sort_link(@q, :name) %>
異なるタイトルのカラムやデフォルトの並び替え順など、追加のオプションをカラム属性の後に渡すことができます。
<%= sort_link(@q, :name, 'Last Name', default_order: :desc) %>
リンクのマークアップがラベルパラメーターにフィットしにくい場合はブロックを使用することができます。
<%= sort_link(@q, :name) do %>
<strong>Player Name</strong>
<% end %>
ポリモーフィックなアソシエーションでは「uninitialized constant Model::Xxxable error」を回避するため、リンク名を明示的に示す必要があります。
<%= sort_link(@q, :xxxable_of_Ymodel_type_some_attribute, 'Attribute Name') %>
順序付けられた配列を指定することで、複数のフィールドに並べ替えることも可能です。
<%= sort_link(@q, :last_name, [:last_name, 'first_name asc'], 'Last Name') %>
上記の例では、リンクをクリックすると、last_name、first_nameの順に並べ替えられます。配列内のフィールドに並べ替え方向を指定すると、Ransackは常にその特定のフィールドを指定された方向に並べ替えるようになります。
複数のdefault_orderフィールドをハッシュで指定することもできます。
<%= sort_link(@q, :last_name, %i(last_name first_name),
default_order: { last_name: 'asc', first_name: 'desc' }) %>
この例では、両方のフィールドの並べ替え方向を切り替えます。デフォルトでは、最初はlast_nameフィールドを昇順で並べ替え、first_nameフィールドを降順で並べ替えます。
SQL関数の結果など、複雑な値で並べ替える場合は、スコープを使用して並べ替えることができます。次のように、モデルで並べ替える仮想フィールドの名前と名前が一致するスコープを定義します。
class Person < ActiveRecord::Base
scope :sort_by_reverse_name_asc, lambda { order("REVERSE(name) ASC") }
scope :sort_by_reverse_name_desc, lambda { order("REVERSE(name) DESC") }
...
続いて、この仮想フィールドを並べ替えることができます。
<%= sort_link(@q, :reverse_name) %>
ソートリンク順序インジケーターの矢印は、config/initializers/ransack.rbなどの初期化ファイルでcustom_arrowsオプションを設定することでグローバルにカスタマイズできます。
現在ソートに使用されていないすべてのソート可能なフィールドに表示されるdefault_arrowを有効にすることもできます。これはデフォルトで無効になっているため、何も表示されません。
Ransack.configure do |c|
c.custom_arrows = {
up_arrow: '<i class="custom-up-arrow-icon"></i>',
down_arrow: 'U+02193',
default_arrow: '<i class="default-arrow-icon"></i>'
}
end
イニシャライザファイルでhide_sort_order_indicatorsをtrueに設定すると、すべてのソートリンクが順序インジケータの矢印なしで表示される場合があります。カスタマイズされている場合でも、矢印が非表示になることに注意してください。
Ransack.configure do |c|
c.hide_sort_order_indicators = true
end
グローバルに設定せずに並べ替えリンクでhide_indicator: trueを渡すことにより、順序インジケーターの矢印なしで個々の並べ替えリンクを表示できます。
<%= sort_link(@q, :name, hide_indicator: true) %>
Ransackのsort_urlヘルパーはsort_linkに似ていますが、URLのみを返します。
sort_urlにはsort_linkと同じAPIがあります。
<%= sort_url(@q, :name, default_order: :desc) %>
<%= sort_url(@q, :last_name, [:last_name, 'first_name asc']) %>
<%= sort_url(@q, :last_name, %i(last_name first_name),
default_order: { last_name: 'asc', first_name: 'desc' }) %>
アドバンスモード
「高度な」検索は、ネストされたAND/ORグループ化などを使用して複雑なクエリを生成するために、Railsのネストされた属性機能を使用します。これには少し手間がかかりますが、非常に優れた検索インターフェイスを生成できます。これらの検索の注目すべき欠点は、パラメータ文字列のサイズが大きくなると、通常、GETの代わりにHTTP POSTメソッドを使用する必要があるということです。
これは、routesを微調整する必要があることを意味します…
resources :people do
collection do
match 'search' => 'people#search', via: [:get, :post], as: :search
end
end
…そして別のコントローラーアクションを追加します…
def search
index
render :index
end
…そしてビューのsearch_form_for行を更新します…
<%= search_form_for @q, url: search_people_path,
html: { method: :post } do |f| %>
これらを行うことでRansack::Helpers::FormBuilderのヘルパーを使用し、デモアプリ(ここのソースコード)にあるような、はるかに複雑な検索フォームを作成することができます。
Ransack searchメソッド
Ransackは、クラスメソッド#searchをモデルで使用できるようにしようとしますが、#searchがすでに他の場所で定義されている場合は、いつでもデフォルトの#ransackクラスメソッドを使用することができます。したがって、以下は同等です。
Article.ransack(params[:q])
Article.search(params[:q])
ユーザーから#search名が他のgemと競合する問題が報告されているため、#searchメソッドエイリアスはRansack(2.0)の次のメジャーバージョンで非推奨になります。代わりに、デフォルトの#ransackを使用することをお勧めします。
今のところ、Ransackの#searchメソッドが、コード内のsearchという名前の別のメソッドまたは別のgemの名前と競合する場合は、Ransack::Adapters::ActiveRecord::Baseの拡張class_methodにパッチを適用して、行エイリアスを削除することで解決できます。 またはconfig/initializers/ransack.rbにあるRansack初期化ファイルに次の行を配置します。
Ransack::Adapters::ActiveRecord::Base.class_eval('remove_method :search')
アソシエーション
Ransackを使用して、has_manyおよびbelongs_toアソシエーション内のオブジェクトを簡単に検索できます。
これらの関連付けを考えると…
class Employee < ActiveRecord::Base
belongs_to :supervisor
# has attributes first_name:string and last_name:string
end
class Department < ActiveRecord::Base
has_many :supervisors
# has attribute title:string
end
class Supervisor < ActiveRecord::Base
belongs_to :department
has_many :employees
# has attribute last_name:string
end
…そしてコントローラー…
class SupervisorsController < ApplicationController
def index
@q = Supervisor.ransack(params[:q])
@supervisors = @q.result.includes(:department, :employees)
end
end
…このようにフォームを設定するかもしれません…
<%= search_form_for @q do |f| %>
<%= f.label :last_name_cont %>
<%= f.search_field :last_name_cont %>
<%= f.label :department_title_cont %>
<%= f.search_field :department_title_cont %>
<%= f.label :employees_first_name_or_employees_last_name_cont %>
<%= f.search_field :employees_first_name_or_employees_last_name_cont %>
<%= f.submit "search" %>
<% end %>
...
<%= content_tag :table do %>
<%= content_tag :th, sort_link(@q, :last_name) %>
<%= content_tag :th, sort_link(@q, :department_title) %>
<%= content_tag :th, sort_link(@q, :employees_last_name) %>
<% end %>
関連付けの並べ替えに問題がある場合は、記号化された関連付け(:department_title、:employees_last_name)の代わりに、複数形のテーブル( ‘departments.title’、 ‘employees.last_name’)でSQL文字列を使用してみてください。
Ransack エイリアス
ransack_aliasを使用して、Ransack検索の属性名をカスタマイズすることができます。これは関連付けや複数のカラムをクエリする際、長い属性名でなければならないといった場面に特に役立ちます。
class Post < ActiveRecord::Base
belongs_to :author
# Abbreviate :author_first_name_or_author_last_name to :author
ransack_alias :author, :author_first_name_or_author_last_name
end
これで、フォームで:author_first_name_or_author_last_name_contを使用する代わりに、:author_contを使用できます。これは、URLでより表現力豊かなクエリパラメータを生成するのに役立ちます。
<%= search_form_for @q do |f| %>
<%= f.label :author_cont %>
<%= f.search_field :author_cont %>
<% end %>
検索マッチャ
可能なすべての述語のリスト
述語 | 説明 | 注釈 |
*_eq | equal | |
*_not_eq | not equal | |
*_matches | matches with LIKE | e.g. q[email_matches]=%@gmail.com |
*_does_not_match | does not match with LIKE | |
*_matches_any | Matches any | |
*_matches_all | Matches all | |
*_does_not_match_any | Does not match any | |
*_does_not_match_all | Does not match all | |
*_lt | less than | |
*_lteq | less than or equal | |
*_gt | greater than | |
*_gteq | greater than or equal | |
*_present | not null and not empty | Only compatible with string columns. Example: q[name_present]=1 (SQL: col is not null AND col != '' ) |
*_blank | is null or empty. | (SQL: col is null OR col = '' ) |
*_null | is null | |
*_not_null | is not null | |
*_in | match any values in array | e.g. q[name_in][]=Alice&q[name_in][]=Bob |
*_not_in | match none of values in array | |
*_lt_any | Less than any | SQL: col < value1 OR col < value2 |
*_lteq_any | Less than or equal to any | |
*_gt_any | Greater than any | |
*_gteq_any | Greater than or equal to any | |
*_lt_all | Less than all | SQL: col < value1 AND col < value2 |
*_lteq_all | Less than or equal to all | |
*_gt_all | Greater than all | |
*_gteq_all | Greater than or equal to all | |
*_not_eq_all | none of values in a set | |
*_start | Starts with | SQL: col LIKE 'value%' |
*_not_start | Does not start with | |
*_start_any | Starts with any of | |
*_start_all | Starts with all of | |
*_not_start_any | Does not start with any of | |
*_not_start_all | Does not start with all of | |
*_end | Ends with | SQL: col LIKE '%value' |
*_not_end | Does not end with | |
*_end_any | Ends with any of | |
*_end_all | Ends with all of | |
*_not_end_any | ||
*_not_end_all | ||
*_cont | Contains value | uses LIKE |
*_cont_any | Contains any of | |
*_cont_all | Contains all of | |
*_not_cont | Does not contain | |
*_not_cont_any | Does not contain any of | |
*_not_cont_all | Does not contain all of | |
*_i_cont | Contains value with case insensitive | uses LIKE |
*_i_cont_any | Contains any of values with case insensitive | |
*_i_cont_all | Contains all of values with case insensitive | |
*_not_i_cont | Does not contain with case insensitive | |
*_not_i_cont_any | Does not contain any of values with case insensitive | |
*_not_i_cont_all | Does not contain all of values with case insensitive | |
*_true | is true | |
*_false | is false |
(全リストを見る: https://github.com/activerecord-hackery/ransack/blob/master/lib/ransack/locale/en.yml#L15 and wiki)
Ransackersを使用してArel経由でカスタム検索機能を追加する
Ransackの背後にある主な前提は、Arel述語メソッドへのアクセスを提供することです。 Ransackは、Arelを介して追加の検索関数を作成するために、ransackersと呼ばれる特別なメソッドを提供します。 ransackerメソッドの詳細については、wikiを参照してください。実用的なランサッカーのコード例をwikiに投稿してください!
DISTINCT選択の問題
distinct :trueが渡された場合、結合の条件によって何らかの結果が生じる場合でも、結果は重複行を返さないようにSELECT DISTINCTを生成します。リレーションでuniqを呼び出すのと同じSQLを生成します。
多くのデータベースでは、関連付けられたテーブルのカラムを並べ替えると、異なるSQLがtrueになる可能性があることに注意してください。そのような場合、これらのクエリを機能させるには、必要に応じて結果を変更する必要があります。
たとえば、joins and includeを呼び出して結果に含めると、次のように、これらのテーブルのカラムをselectステートメントに追加して問題を解決できます。
def index
@q = Person.ransack(params[:q])
@people = @q.result(distinct: true)
.includes(:articles)
.joins(:articles)
.page(params[:page])
end
上記が役に立たない場合は、ActiveRecordのselectクエリを使用して、必要なカラムを明示的に追加することもできます。これにより、要改善のSQLエンジン、かつ必要なカラムが強制的に追加されるため、すべてのカラムを指定する必要があります。
例えば:
def index
@q = Person.ransack(params[:q])
@people = @q.result(distinct: true)
.select('people.*, articles.name, articles.description')
.page(params[:page])
end
Postgresqlを使用する際にアプローチする別の方法は、ActiveRecordsの.includesをdistinct :trueではなく.groupと組み合わせて使用することです。
例えば:
def index
@q = Person.ransack(params[:q])
@people = @q.result
.group('persons.id')
.includes(:articles)
.page(params[:page])
end
最後の方法は、コードの最後にコレクションでto_a.uniqを呼び出すことです。ただし、重複排除はSQLではなくRubyで行われるため、速度が低下し、メモリの使用量が増える可能性があり、表示される可能性があります。結果の数がページサイズよりも大きい場合、ページ付けが厄介になります。
例えば:
def index
@q = Person.ransack(params[:q])
@people = @q.result.includes(:articles).page(params[:page]).to_a.uniq
end
PG::UndefinedFunction: ERROR: could not identify an equality operator for type json
distinct :true使用中に上記のエラーが発生した場合は、Ransackが選択しているカラムの1つがjsonカラムであることを意味します。 PostgreSQLは、JSONタイプのための比較演算子を提供していません。これを回避することは可能ですが、実際にはPostgreSQLのドキュメントで推奨されているように、それらをjsonbに変換する方がはるかに優れています。
承認(ホワイトリスト/ブラックリスト)
デフォルトでは、検索と並べ替えはモデルのどのカラムでも許可されており、クラスのメソッド/スコープはホワイトリストに登録されていません。
RansackはActiveRecord::Baseに4つのメソッドを追加します。これらのメソッドは、モデルのクラスメソッドとして再定義して、選択的な承認を適用できます。ransackable_attributes、ransackable_associations、ransackable_scopes、ransortable_attributesです。
これらの4つのメソッドがRansackでどのように実装されているかを次に示します。
# `ransackable_attributes` by default returns all column names
# and any defined ransackers as an array of strings.
# For overriding with a whitelist array of strings.
#
def ransackable_attributes(auth_object = nil)
column_names + _ransackers.keys
end
# `ransackable_associations` by default returns the names
# of all associations as an array of strings.
# For overriding with a whitelist array of strings.
#
def ransackable_associations(auth_object = nil)
reflect_on_all_associations.map { |a| a.name.to_s }
end
# `ransortable_attributes` by default returns the names
# of all attributes available for sorting as an array of strings.
# For overriding with a whitelist array of strings.
#
def ransortable_attributes(auth_object = nil)
ransackable_attributes(auth_object)
end
# `ransackable_scopes` by default returns an empty array
# i.e. no class methods/scopes are authorized.
# For overriding with a whitelist array of *symbols*.
#
def ransackable_scopes(auth_object = nil)
[]
end
これらのメソッドから返されない値は、Ransackによって無視されます。つまり、許可されません。
4つのメソッドはすべて、単一のオプションパラメータauth_objectを受け取ることができます。モデルでsearchまたはransackメソッドを呼び出すときに、独自のオーバーライドされたメソッドで使用できるオプションハッシュのauth_objectキーの値を指定できます。
これは、Ernie Millerによるこのブログ投稿を基に、これらすべてをまとめた例です。 Articleモデルで、次のransackable_attributesクラスメソッド(できればprivate)を追加します。
class Article < ActiveRecord::Base
def self.ransackable_attributes(auth_object = nil)
if auth_object == :admin
# whitelist all attributes for admin
super
else
# whitelist only the title and body attributes for other users
super & %w(title body)
end
end
private_class_method :ransackable_attributes
end
これがarticles_controllerのサンプルコードです。
class ArticlesController < ApplicationController
def index
@q = Article.ransack(params[:q], auth_object: set_ransack_auth_object)
@articles = @q.result
end
private
def set_ransack_auth_object
current_user.admin? ? :admin : nil
end
end
Railsコンソールで試してみる:
> Article
=> Article(id: integer, person_id: integer, title: string, body: text)
> Article.ransackable_attributes
=> ["title", "body"]
> Article.ransackable_attributes(:admin)
=> ["id", "person_id", "title", "body"]
> Article.ransack(id_eq: 1).result.to_sql
=> SELECT "articles".* FROM "articles" # Note that search param was ignored!
> Article.ransack({ id_eq: 1 }, { auth_object: nil }).result.to_sql
=> SELECT "articles".* FROM "articles" # Search param still ignored!
> Article.ransack({ id_eq: 1 }, { auth_object: :admin }).result.to_sql
=> SELECT "articles".* FROM "articles" WHERE "articles"."id" = 1
これで完了です!これで、Ransackのさまざまな要素をホワイトリスト/ブラックリストに登録する方法がわかりました。
スコープ/クラスメソッドの使用
前のセクションから続けて、スコープで検索するにはモデルクラスでransackable_scopesのホワイトリストを定義する必要があります。ホワイトリストはシンボルの配列である必要があります。デフォルトでは、すべてのクラスメソッド(スコープなど)は無視されます。スコープは真の値を照合するため、またはスコープが値を受け入れる場合は指定された値に適用されます。
class Employee < ActiveRecord::Base
scope :activated, ->(boolean = true) { where(active: boolean) }
scope :salary_gt, ->(amount) { where('salary > ?', amount) }
# Scopes are just syntactical sugar for class methods, which may also be used:
def self.hired_since(date)
where('start_date >= ?', date)
end
def self.ransackable_scopes(auth_object = nil)
if auth_object.try(:admin?)
# allow admin users access to all three methods
%i(activated hired_since salary_gt)
else
# allow other users to search on `activated` and `hired_since` only
%i(activated hired_since)
end
end
end
Employee.ransack({ activated: true, hired_since: '2013-01-01' })
Employee.ransack({ salary_gt: 100_000 }, { auth_object: current_user })
Rails3および4では、真の値がurl paramsまたは文字列に変換するその他のメカニズムを介して渡される場合、真の値は配列でラップしない限り(つまり、アクティブ化されない限り)、Ransackableスコープに渡されない場合があります。 [‘true’])。 Ransackは、「true」をboolean値に変更します。これは現在、Rails5で解決されています😃
ただし、おそらくuser_id: 1があり、Ransackが1をboolean値に変換したくない場合があります。 (ブール値にサニタイズされた値はconstants.rbにあります)。これをグローバルにオフにし、型変換を自分で処理するには、config/initializers/ransack.rbなどの初期化ファイルでsanitize_custom_scope_booleansをfalseに設定します。
Ransack.configure do |c|
c.sanitize_custom_scope_booleans = false
end
スコープごとにこれをオフにするために、RansackはActiveRecord :: Baseに次のメソッドを追加します。このメソッドを再定義して、サニタイズを選択的にオーバーライドできます。
ransackable_scopes_skip_sanitize_args
この動作をバイパスするスコープをransackable_scopes_skip_sanitize_argsに追加します。
def self.ransackable_scopes_skip_sanitize_args
[:scope_to_skip_sanitize_args]
end
スコープはRansackに最近追加されたものであり、現在いくつかの注意点があります。まず、子の関連付けを含むスコープは子モデルではなく、親テーブルモデルで定義する必要があります。第2に配列を引数として持つスコープは、機能するために配列でラップする必要があるため(この問題を参照)まだ簡単には使用できません。これは、Ransackフォームヘルパーと互換性がありません。このユースケースでは、可能であれば代わりにランサッカーを使用する方がよい場合があります。ソリューションとテストを含むプルリクエストは大歓迎です!
ANDではなくORでクエリをグループ化する
デフォルトのANDグループ化は、クエリハッシュにm: ‘or’を追加することでORに変更できます。
次のように、インデックスアクションのparams [:q]をparams [:q].try(:merge、m: ‘or’)に変更することで、コントローラーコードで簡単に試すことができます。
def index
@q = Artist.ransack(params[:q].try(:merge, m: 'or'))
@artists = @q.result
end
通常、ユーザーがANDクエリとORクエリのグループ化を切り替えられるようにする場合は、mがURL paramsハッシュに含まれるように検索フォームを設定しますが、ここでは、すばやく試すためにmを手動で割り当てました。
または、Railsコンソールで試してみてください。
artists = Artist.ransack(name_cont: 'foo', style_cont: 'bar', m: 'or')
=> Ransack::Search<class: Artist, base: Grouping <conditions: [
Condition <attributes: ["name"], predicate: cont, values: ["foo"]>,
Condition <attributes: ["style"], predicate: cont, values: ["bar"]>
], combinator: or>>
artists.result.to_sql
=> "SELECT \"artists\".* FROM \"artists\"
WHERE ((\"artists\".\"name\" ILIKE '%foo%'
OR \"artists\".\"style\" ILIKE '%bar%'))"
コンビネータはデフォルトのandの代わりにorになり、SQLクエリはWHERE … ANDの代わりにWHERE … ORになります。
これはアソシエーションでも機能します。多くのメンバーシップを持ち、メンバーシップを通じて多くのミュージシャンがいるアーティストモデルを想像してみてください。
artists = Artist.ransack(name_cont: 'foo', musicians_email_cont: 'bar', m: 'or')
=> Ransack::Search<class: Artist, base: Grouping <conditions: [
Condition <attributes: ["name"], predicate: cont, values: ["foo"]>,
Condition <attributes: ["musicians_email"], predicate: cont, values: ["bar"]>
], combinator: or>>
artists.result.to_sql
=> "SELECT \"artists\".* FROM \"artists\"
LEFT OUTER JOIN \"memberships\"
ON \"memberships\".\"artist_id\" = \"artists\".\"id\"
LEFT OUTER JOIN \"musicians\"
ON \"musicians\".\"id\" = \"memberships\".\"musician_id\"
WHERE ((\"artists\".\"name\" ILIKE '%foo%'
OR \"musicians\".\"email\" ILIKE '%bar%'))"
SimpleFormの使用
RansackフォームビルダーとSimpleFormフォームビルダーを組み合わせたい場合は、Railsが起動する前にRANSACK_FORM_BUILDER環境変数を設定します。以下に示すように、config/application.rbの前に「rails/all」が必要です(そして、Gemfileにgem「simple_form」を追加します)。
require File.expand_path('../boot', __FILE__)
ENV['RANSACK_FORM_BUILDER'] = '::SimpleForm::FormBuilder'
require 'rails/all'
I18n
Ransack翻訳ファイルはRansack::Localeで入手できます。また、http://www.localeapp.com/projects/2999で入手できるRansackの多くの翻訳の1つに興味があるかもしれません。
フォームの述語と属性の翻訳は、次のように指定できます(その他の例については、Ransack :: Localeの翻訳ファイルを参照してください)。
en:
ransack:
asc: ascending
desc: descending
predicates:
cont: contains
not_cont: not contains
start: starts with
end: ends with
gt: greater than
lt: less than
models:
person: Passanger
attributes:
person:
name: Full Name
article:
title: Article Title
body: Main Content
属性名は、グローバルに、またはactiverecordの下で変更することもできます。
en:
attributes:
model_name:
model_field1: field name1
model_field2: field name2
activerecord:
attributes:
namespace/article:
title: AR Namespaced Title
namespace_article:
title: Old Ransack Namespaced Title
Mongoid
Mongoidのサポートは、ransack-mongoidの独自のgemに移動されました。 RansackはActiveRecordと同じようにMongoidで動作しますが、Mongoidでは関連付けが現在サポートされていない点が異なります。デモのソースコードはここにあります。ランサック検索で呼び出された結果メソッドは、Mongoid::Criteriaオブジェクトを返します。
@q = Person.ransack(params[:q])
@people = @q.result # => Mongoid::Criteria
# or you can add more Mongoid queries
@people = @q.result.active.order_by(updated_at: -1).limit(10)
注: Ransackは現在、Active RecordまたはMongoidのいずれかで動作しますが、同じアプリケーションで両方を動作させることはできません。両方が存在する場合、Ransackはデフォルトでアクティブレコードのみになります。ロジックは、オーバーライドする必要がある場合に備えて、Ransack::Adapters#instantiate_object_mapperに含まれています。
Semantic Versioning
Ransackは、x.y.zの形式でセマンティックバージョニングを実行しようとします。ここで、
xはメジャーバージョン(下位互換性のない新機能)を表します。
yはマイナーバージョン(下位互換性のある新機能)を表します。
zはパッチ(バグ修正)を表します。
言い換えると、Major.Minor.Patchです。
コントリビューションズ
プロジェクトをサポートするには:
- OpenCollectiveを介したサポートを検討してください
- アプリでRansackを使用し、壊れているものや不足しているものがあればお知らせください。問題を実証するための失敗した仕様は素晴らしいです。テストに合格したプルリクエストはさらに優れています!
- 問題またはプルリクエストを提出する前に、必ず寄稿ガイドを読んでそれに従ってください。
- バグレポート、プルリクエスト、またはドキュメントの改善に直接関係のない質問やディスカッションについては、StackOverflowまたは他のサイトを使用してください。
- Ransackがあなたに役立ったなら、Twitter、Facebook、その他の場所でその言葉を広めてください。プロジェクトを使用している人が多ければ多いほど、バグをすばやく見つけて修正できます。
今回は、Railsで検索機能を簡単に実装できるgem「Ransack」のREADMEを翻訳したので紹介しました。中々難しい箇所もありますが、何となくの理解で読み進めていただけたらと思います。