README.md in ii_finder-1.1.2 vs README.md in ii_finder-1.2.0
- old
+ new
@@ -22,18 +22,18 @@
## Usage
Prepare model:
```ruby
-class User < ActiveRecord::Base
+class Item < ActiveRecord::Base
end
```
Prepare finder:
```ruby
-class UsersFinder < IIFinder::Base
+class ItemsFinder < IIFinder::Base
parameters :name
def name(value)
@relation.where(name: value)
end
@@ -41,58 +41,58 @@
```
Use finder as follows:
```ruby
-UsersFinder.call(name: 'NAME').to_sql
-#=> SELECT "users".* FROM "users" WHERE "users"."name" = 'NAME'
+ItemsFinder.call(name: 'NAME').to_sql
+#=> SELECT "items".* FROM "items" WHERE "items"."name" = 'NAME'
```
You can also specify relation as first argument:
```ruby
-UsersFinder.call(User.where(id: [1, 2, 3]), name: 'NAME').to_sql
-#=> SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3) AND "users"."name" = 'NAME'
+ItemsFinder.call(Item.where(id: [1, 2, 3]), name: 'NAME').to_sql
+#=> SELECT "items".* FROM "items" WHERE "items"."id" IN (1, 2, 3) AND "items"."name" = 'NAME'
```
### Finder
Finder loops keys of `parameters` and call the corresponding method with value of parameter as argument.
Finder method will not be called when the value of parameter is blank.
If you want to receive such value, set `allow_blank` as follows:
```ruby
-class UsersFinder < IIFinder::Base
+class ItemsFinder < IIFinder::Base
parameters :name, allow_blank: true
def name(value)
@relation.where(name: value)
end
end
-UsersFinder.call(name: '').to_sql
-#=> SELECT "users".* FROM "users" WHERE "users"."name" = ''
+ItemsFinder.call(name: '').to_sql
+#=> SELECT "items".* FROM "items" WHERE "items"."name" = ''
```
Finder has following attributes:
```ruby
-class UsersFinder < IIFinder::Base
+class ItemsFinder < IIFinder::Base
parameters :name
def name(value)
puts "relation: #{@relation}"
puts "criteria: #{@criteria}"
puts "model: #{@model}"
puts "table: #{@table}"
end
end
-UsersFinder.call(name: 'NAME')
-#=> relation: #<User::ActiveRecord_Relation:
+ItemsFinder.call(name: 'NAME')
+#=> relation: #<Item::ActiveRecord_Relation:
# criteria: {:name=>'NAME'}
-# model: User
+# model: Item
# table: #<Arel::Table ...>
```
Return value of each finder method is merged into `@relation` if it is a kind of `ActiveRecord::Relation`.
In case you want to merge by yourself, set configuration as follows:
@@ -100,20 +100,20 @@
```ruby
IIFinder.configure do |config|
config.merge_relation = false
end
-class UsersFinder < IIFinder::Base
+class ItemsFinder < IIFinder::Base
parameters :name
def name(value)
@relation = @relation.where(name: value)
end
end
-UsersFinder.call(name: 'NAME').to_sql
-#=> SELECT "users".* FROM "users" WHERE "users"."name" = 'NAME'
+ItemsFinder.call(name: 'NAME').to_sql
+#=> SELECT "items".* FROM "items" WHERE "items"."name" = 'NAME'
```
#### Callbacks
Following callbacks are available.
@@ -123,70 +123,115 @@
* `after_call`
For example:
```ruby
-class UsersFinder < IIFinder::Base
+class ItemsFinder < IIFinder::Base
after_call :default_order
def default_order
@relation = @relation.order(id: :desc)
end
end
-UsersFinder.call.to_sql
-#=> SELECT "users".* FROM "users" ORDER BY "users"."id" DESC
+ItemsFinder.call.to_sql
+#=> SELECT "items".* FROM "items" ORDER BY "items"."id" DESC
```
Note that finder does not handle the return value of callback.
When you want to update `@relation` in the callback,
reassign `@relation` or use methods like `where!` or `order!`.
+#### Chain
+
+You can chain multiple finders by using `chain`. For example:
+
+```ruby
+class NameFinder < IIFinder::Base
+ parameters :name
+
+ def name(value)
+ @relation.where(name: value)
+ end
+end
+
+class AgeFinder < IIFinder::Base
+ parameters :age
+
+ def age(value)
+ @relation.where(age: value)
+ end
+end
+
+class ItemsFinder < IIFinder::Base
+ chain NameFinder, AgeFinder
+end
+
+ItemsFinder.call(Item.all, name: 'name', age: 10).to_sql
+#=> SELECT "items".* FROM "items" WHERE "items"."name" = 'name' AND "items"."age" = 10
+```
+
+You can also use method or block to find finder class dynamically:
+
+```ruby
+class ItemFinder < IIFinder::Base
+ chain -> { NameFinder }
+end
+
+class ItemFinder < IIFinder::Base
+ chain :chain_finder
+
+ def chain_finder
+ NameFinder
+ end
+end
+```
+
### Lookup for model
Finder lookups related model by its class name when the first argument of `call` is not relation.
So the name of finder class should be composed of the name of model class.
For example:
```ruby
-class User < ActiveRecord::Base
+class Item < ActiveRecord::Base
end
-class UsersFinder < IIFinder::Base
+class ItemsFinder < IIFinder::Base
end
-IIFinder::Base.lookup(UsersFinder)
-#=> User
+IIFinder::Base.lookup(ItemsFinder)
+#=> Item
```
Note that superclass of finder is also looked up until related model is found.
```ruby
-class User < ActiveRecord::Base
+class Item < ActiveRecord::Base
end
-class UsersFinder < IIFinder::Base
+class ItemsFinder < IIFinder::Base
end
-class InheritedUsersFinder < UsersFinder
+class InheritedItemsFinder < ItemsFinder
end
-IIFinder::Base.lookup(InheritedUsersFinder)
-#=> User
+IIFinder::Base.lookup(InheritedItemsFinder)
+#=> Item
```
### Scope for model
In case you want to call finder from model, include `IIFinder::Scope` into model as follows:
```ruby
-class User < ActiveRecord::Base
+class Item < ActiveRecord::Base
include IIFinder::Scope
end
-User.finder_scope(name: 'NAME').to_sql
-#=> SELECT "users".* FROM "users" WHERE "users"."name" = 'NAME'
+Item.finder_scope(name: 'NAME').to_sql
+#=> SELECT "items".* FROM "items" WHERE "items"."name" = 'NAME'
```
### Logging
Finder supports instrumentation hook supplied by `ActiveSupport::Notifications`.
@@ -197,10 +242,10 @@
```
This subscriber will write logs in debug mode as the following example:
```
-Called UsersFinder with {:id=>1} (Duration: 9.9ms, Allocations: 915)
+Called ItemsFinder with {:id=>1} (Duration: 9.9ms, Allocations: 915)
```
## Contributing
Bug reports and pull requests are welcome at https://github.com/kanety/ii_finder.