# app/models/post.rb
class Post < ApplicationRecord
include BulkLoader::DSL
bulk_loader :comment_count, :id, default: 0 do |ids|
Comment.where(id: ids).group(:post_id).count
end
end
You can use this like followings:
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.limit(10)
# load comment_count blocks with mapping by #id
# you can avoid N+1 queries.
Post.bulk_loader.load(:comment_count, @posts)
render(json: @posts.map {|post| { id: post.id, comment_count: post.comment_count } })
end
end
BulkLoader::DSL only create bulk_loader class method and bulk_loader method. So you can use with any object that is not ActiveRecord.
If you include BulkLoader::DSL, you can use bulk_loader class method.
class YourModel
include BulkLoader::DSL
bulk_loader :name, :mapped_key, default: nil do |mapped_keys|
# something with mapped_keys
{
mapped_key => value, # you should return Hash that has mapped_key as key.
}
end
end
that create a instance method that name is :name.
mapped_key is Symbol or Proc. if you want to use original object, you can pass ->(your_model) { your_model }
.
If block's result return Hash that cannot mapped to original object, you can return value using default option. If you does not pass default option, default is nil.
If you want to pass object like Array, you should use with lambda.
class YourModel
include BulkLoader::DSL
bulk_loader :name, :mapped_key, default: -> { [] } do |mapped_keys|
# something with mapped_keys
{
mapped_key => value, # you should return Hash that has mapped_key as key.
}
end
end
:name method is just shorthand for bulk_loader.public_send(:name). So if you not want to create :name method, you can pass export: false to bulk_loader definition.
class YourModel
include BulkLoader::DSL
bulk_loader :name, :mapped_key, default: nil, export: false do |mapped_keys|
# something with mapped_keys
end
end
then you can use this like followings.
YourModel.new.bulk_loader.name
If you set this option to false, +BulkLoader::UnloadAccessError+ occured when you does not call +YourModel.bulk_loader.load explicitly on :name method.
class YourModel
include BulkLoader::DSL
bulk_loader :name, :mapped_key, default: nil, autoload: false do |mapped_keys|
# something with mapped_keys
end
end
YourModel.new.name #=> raise error BulkLoader::UnloadAccessError
You can pass this by calling load explicitly.
model = YourModel.new
YourModel.bulk_loader.load(:name, [model])
model.name #=> it does not raise BulkLoader::UnloadAccessError
Add this line to your application's Gemfile:
gem 'bulk_loader'
And then execute:
$ bundle
Or install it yourself as:
$ gem install bulk_loader
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/walf443/bulk_loader.