Shopify / Shopify/tapioca

Kaminari pagination is not supported by Tapioca

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

Nobody has claimed this yet.

Dominant language
Ruby
Stars
873
Forks
164
Avg merge
4d 27m
Merged PRs (30d)
9

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

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.

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.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.