Kaminari pagination is not supported by Tapioca

Open
#1,859 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
38/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
rails, ruby
Domain
tooling

Research direction

Start with Rails' activerecord/lib/active_record/relation/delegation.rb, especially the generated relation methods and the generate_relation_method(:page) entry point described in the report. Trace Tapioca's RBI generation for ActiveRecord relations and reproduce the Kaminari page/per case; done means Tapioca generates signatures for those methods without the initializer workaround.

Written by the indexing model from the issue text.

Description

Trying to update tapioca from 0.12.0 to 0.13.1 results in this error:

path/to/file.rb:32: Method page does not exist on Model::PrivateAssociationRelation https://srb.help/7003
    32 |    @records = Model.all.page(params[:page]).per(25)

Investigation

The page method is defined on the class by kaminari:
https://github.com/kaminari/kaminari/blob/9182d065c144afa45c6b7cf444f810bea1fd7201/kaminari-activerecord/lib/kaminari/activerecord/active_record_model_extension.rb#L14-L23

But attempting to introspect it at runtime yields nothing:

pry(main)> Model.all.method(:page)
=> #<Method: Model::ActiveRecord_Relation#page(*)>
pry(main)> Model.all.method(:page).source_location
=> nil
pry(main)> Model.all.method(:page).owner
=> Model::ActiveRecord_Relation
pry(main)> Model.all.method(:page).owner.instance_method(:page)
NameError: undefined method `page' for class `ActiveRecord::Relation'
from (pry):1:in `instance_method'from (pry):35:in `method'
pry(main)> Model.all.methods.include?(:page)
=> false

This is because it is delegated by https://github.com/rails/rails/blob/d37c533139f70efdcd95f8dadd48c10eba429f94/activerecord/lib/active_record/relation/delegation.rb#L71-L88

Which is generated on demand when the method is missing:
https://github.com/rails/rails/blob/d37c533139f70efdcd95f8dadd48c10eba429f94/activerecord/lib/active_record/relation/delegation.rb#L115-L124

Attempting the same as above after calling the method once does yield something a bit more interesting:

pry(main)> Model.all.method(:page)
=> #<Method: Model::ActiveRecord_Relation(Model::GeneratedRelationMethods)#page(...) /Users/seb/.gem/ruby/3.2.2/gems/activerecord-7.1.3.2/lib/active_record/relation/delegation.rb:78>
pry(main)> Model.all.method(:page).source_location
=> ["/Users/seb/.gem/ruby/3.2.2/gems/activerecord-7.1.3.2/lib/active_record/relation/delegation.rb", 78]
pry(main)> Model.all.method(:page).owner
=> Model::GeneratedRelationMethods
pry(main)> Model.all.method(:page).owner.instance_method(:page)
=> #<UnboundMethod: Model::GeneratedRelationMethods#page(...) /Users/seb/.gem/ruby/3.2.2/gems/activerecord-7.1.3.2/lib/active_record/relation/delegation.rb:78>
pry(main)> Model.all.methods.include?(:page)
=> true

The same can be achieved by calling Model.generate_relation_method(:page)

Workaround

Adding this in config/initializers/kaminari.rb makes tapioca generate the methods:

if defined?(Tapioca)
  Rails.application.config.after_initialize do
    Rails.application.eager_load!

    ActiveRecord::Base.descendants.each do |model|
      model.generate_relation_method(:page)
      model.generate_relation_method(:per)
    end
  end
end
Dominant language
Ruby
Stars
873
Forks
164
Avg merge
4d 27m
Merged PRs (30d)
9

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Shopify/tapioca

All issues in Shopify/tapioca

Similar issues

More Ruby issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.