Code Monkey home page Code Monkey logo

sorbet-rails's Issues

Define 'new' method on model classes

Describe the bug:
ActiveRecord overrides the new method for all Model classes, e.g. User.new.

It's defined like this in activerecord.rbi:

module ActiveRecord::Inheritance::ClassMethods
  def new(attributes = nil, &block); end
end

And then User, or any other model, inherits that method.

Expected behavior:

I could have an app/controllers/users_controller.rb file like this:

class UsersController < ApplicationController
  def create
    @user = User.new({ username: 'connor' }) # @user is T.untyped because `new` is overridden.
    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, success: "#{@user.username} was successfully created." }
    end
  end
end

The method should be generated as part of Sorbet Rails so its return type can be dynamically set:

class User
  sig { params(args: T.untyped, block: T.untyped).returns(User) }
  def self.new(*args, &block); end
end

Unfortunately it can't just be self_type because that doesn't return an instance of the caller :/

Generate perform_now and perform_later

Describe the bug feature:

In #238 Harry suggested that we should generate RBI for perform_now and perform_later.

For sorbet-rails, I think we can generate perform_later and perform_now class methods based on the manually written signature, much like how we generate delivery method for mailers. If you're interested in doing that, I can give you more direction on how to do it. It should be simple because sorbet-rails already has a library method that extracts sorbet signature from a method

Steps to reproduce:

  1. rails g job myjob
  2. set job sigil to false or higher
  3. rake rails_rbi:all
  4. ack perform_now sorbet/rails-rbi no occurrences

Expected behavior:

rake rails_rbi:all should generate RBI for perform_now and perform_later.

Versions:

  • Ruby: all supported
  • Rails: all supported
  • Sorbet: all supported
  • Sorbet-Rails: future ๐Ÿ˜

Generate methods for ActiveStorage attachments

Describe the bug:

SorbetRails doesn't currently generate methods for ActiveStorage attachments. For example, in my Rails app users have avatars and games have covers, but neither of these are typed.

Steps to reproduce:

class User < ApplicationRecord
  has_one_attached :avatar
end
class Game < ApplicationRecord
  has_one_attached :cover
end

In hidden.rbi we have some methods like this:

module User::GeneratedAssociationMethods
  def avatar(); end

  def avatar=(attachable); end
end

Expected behavior:

It should return either ActiveStorage::Attached::One or ActiveStorage::Attached::Many depending on the definition in the model.

This is what I'd expect to see in game.rbi:

module Game::GeneratedAttributeMethods
  extend T::Sig
  
  sig { returns(T.nilable(ActiveStorage::Attached::One)) }
  def cover; end

  sig { params(attachable: T.untyped).returns(T.untyped) }
  def cover=(attachable); end

  # or, if we had something defined like `has_many_attached :covers`
  sig { returns(T.nilable(ActiveStorage::Attached::Many)) }
  def covers; end

  sig { params(attachable: T.untyped).returns(T.untyped) }
  def covers=(*attachables); end
end

I'm not entirely sure what the setters take or return, unfortunately.

Versions:

  • Ruby: 2.6.2
  • Rails: 6.0.0
  • Sorbet:
  • Sorbet-Rails: 0.5.3 (master)

New model plugin: Paperclip

This plugin is working locally for me:

  # https://github.com/thoughtbot/paperclip
  class HasAttachedFileSorbetPlugin < SorbetRails::ModelPlugins::Base
    sig { params(root: Parlour::RbiGenerator::Namespace).void.override }
    def generate(root)
      # method added here: https://github.com/thoughtbot/paperclip/blob/v5.2.1/lib/paperclip/has_attached_file.rb#L110

      return unless model_class.respond_to?(:attachment_definitions)

      module_name = self.model_module_name("GeneratedPaperclipMethods")
      module_rbi = root.create_module(module_name)
      module_rbi.create_extend("T::Sig")

      model_class_rbi = root.create_class(self.model_class_name)
      model_class_rbi.create_include(module_name)

      Paperclip::AttachmentRegistry.names_for(model_class).each do |attachment|
        # https://github.com/thoughtbot/paperclip/blob/v5.2.1/lib/paperclip/has_attached_file.rb#L42
        module_rbi.create_method(
          attachment.to_s,
          return_type: "::Paperclip::Attachment",
        )

        # https://github.com/thoughtbot/paperclip/blob/v5.2.1/lib/paperclip/attachment.rb#L100
        module_rbi.create_method(
          "#{attachment}=",
          parameters: [
            Parameter.new("uploaded_file", type: "T.untyped") # could be a variety of things
          ],
          return_type: nil,
        )
      end
    end
  end

Given paperclip is deprecated, would you still accept a PR that adds it to this project? Also: keen for any feedback on the plugin structure.

5 bundled_rbi related "srb tc" errors in rails_app5_2 repo for gems/sorbet-rails.rbi file

Describe the bug:

5 bundled_rbi related "srb tc" errors in https://github.com/jasnow/rails_app5_2 repo for gems/sorbet-rails.rbi file

Steps to reproduce:

On October 9, when I changed typed from false to true for
sorbet/rbi/gems/sorbet-rails.rbi and ran "srb tc", I got 5 errors.
See gist below for details.
https://gist.github.com/jasnow/b99bc9f4e4ccc5c50b7f219b0767cc78

Today when I repeat it, I get 9 errors.
Ran "srb rbi hidden-definitions" and got it down to 6 errors.
Ran "srb init"/etc again and got it down to the above 5 errors.

All 5 errors appear to be related to the sorbet-rails/bundled_rbi files.
If I comment out the contents of these files, "srb tc" is clean.

Expected behavior:

No errors

Versions:

  • Ruby: 2.4.9p362 (2019-10-02 revision 67824) [x86_64-darwin16]
  • Rails: 5.2.3
  • Sorbet: 0.4.4865
  • Sorbet-Rails: 0.5.7

Type of Rails.application should be YourApp::Application

Moved from: sorbet/sorbet-typed#83

Describe the bug:
In a Rails application the type of Rails.application is actually a subclass of Rails::Application that is generated when you type rails new. For example, rails new blog, Rails.application will create a class called Blog::Application defined in config/application.rb.

I am willing to make an attempt at fixing this if you think it's a valid change - let me know then I'll send a PR.

Steps to reproduce:

The impact of this is that any custom methods you define in application.rb on Blog::Application will not be visible to the type checker. If I have config/application.rb that looks like this:

# typed: true
require_relative 'boot'
require 'rails'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Blog
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    def name
      "Brad's awesome blog"
    end
  end
end

then I can't call Rails.application.name in a type-safe way.

Versions:

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]

$ rails --version
Rails 5.2.1

$ srb --version
Sorbet typechecker 0.4.4429 git 51504253c985d0a967d3df6a39ac44b25db2c481 built on 2019-07-12 00:02:11 GMT with debug symbols

Unexpected modified files after running "run_all_specs.sh" today

Describe the bug:

Unexpected modified files after running "run_all_specs.sh" today

Steps to reproduce:

After upgrading sorbet-rails repos (488 files) this morning, I ran "./spec/bin/run_all_specs.sh" and it resulted in 35 modified files (new "typed:" lins I think) in sorbet-rails/spec/support/v5.2-no-sorbet. Confirmed connection with PR#117 and #126 .

Expected behavior:

No modified files after upgrading to latest sorbet-rails repo.

Versions:

  • Ruby: ruby 2.4.6p354 (2019-04-01 revision 67394) [x86_64-darwin16]
  • Rails: 5.2.3
  • Sorbet: 0.4.4602
  • Sorbet-Rails: 0.5.0

Use HashWithIndifferentAccess for enum values

Currently sorbet-rails uses T::Hash[T.any(String, Symbol), Integer] for enum values of a model. This works but the keys method would return an array of Symbol or String. Rails actually use HashWithIndifferentAccess, which guarantee (softly) that .keys would return an array of String.

It's blocking on the typedef of HashWithIndifferentAccess itself (which should/could be added to sorbet-typed)

Mark expected rbi files as generated

Describe the bug:
Currently, whenever some code changes the expected files, all changes are expanded. It shows repetitive changes and makes it harder to review the PR. It'll be useful to mark those files as "generated"

See instructions:
https://sorbet-ruby.slack.com/archives/CHN2L03NH/p1577557587024400
https://github.com/github/linguist#vendored-code

Steps to reproduce:
Create a PR with changes in expected rbi files

Expected behavior:

Changes in "expected_*.rbi" are not expanded in the PR view.

Versions:

  • Ruby:
  • Rails:
  • Sorbet:
  • Sorbet-Rails:

undefined method `through_reflection?' for #<ActiveRecord::Reflection::HasManyReflection:0x00007f9e72ce1b08>

When running rake rails_rbi:models I got this error for nearly every model.

-- Generate sigs for Invoice --
---
Error when handling model Invoice: undefined method `through_reflection?' for #<ActiveRecord::Reflection::HasManyReflection:0x00007f9e8ddc1418>
Did you mean?  through_reflection

I'm on Rails 4.2.10 and Ruby 2.4.2. Is this a version thing? I don't see anywhere that says that Rails 4 is covered, but I also don't see that it isn't covered.

Thanks!

Support for mailers

Describe the bug:

Rails mailer actions are defined as instance methods but called as class methods. Sorbet is aware of the former, but not the later.

Is it silly that rails works this way?

Probably.

Steps to reproduce:

# typed: true
class UserMailer < ApplicationMailer
  def new_user_password(user)
    # ...
  end
end

# typed: true
class BatchPasswordGenerator
  # ..
  sig { params(user: ::User).void }
  def enqueue_new_user_password_email(user)
    ::UserMailer.
      new_user_password(user).
      deliver_later
  end
  # ..
end

Produces:

bin/srb t
redacted/batch_password_generator.rb:38: Method new_user_password does not exist on T.class_of(UserMailer) https://srb.help/7003
    38 |      ::UserMailer.
    39 |        new_user_password(redacted).
    app/mailers/user_mailer.rb:24: Did you mean: UserMailer#new_user_password?
    24 |  def new_user_password(redacted)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Errors: 1

Expected behavior:

srb t should not produce error.

Versions:

bin/rails -v
Rails 6.0.0
ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]
bundle | grep sorb
Using sorbet-runtime 0.4.4686
Using sorbet-static 0.4.4686 (universal-darwin-18)
Using sorbet 0.4.4686
Using sorbet-progress 0.2.3
Using sorbet-rails 0.5.2

Support Rails version 5.1

Some preliminary discussion around this problem can be found in this slack thread

when i run rake rails_rbi:models it skips all of the instance methods for attributes defined in the schema

e.g.

-- Generate sigs for ServiceProviderUsersServiceClientUser --
Skip method 'created_at' because it is not autogenerated by Rails.
Skip method 'created_at=' because it is not autogenerated by Rails.
Skip method 'hourly_rate_in_cents' because it is not autogenerated by Rails.
Skip method 'hourly_rate_in_cents=' because it is not autogenerated by Rails.

but in a console:

irb(main):005:0> ServiceProviderUsersServiceClientUser.instance_method(:hourly_rate_in_cents).source_location
=> ["/bundle/gems/activerecord-5.1.7/lib/active_record/attribute_methods/read.rb", 34]

irb(main):004:0> ServiceProviderUsersServiceClientUser.instance_method(:hourly_rate_in_cents).owner   
=> #<#<Class:0x0000563fdf89fd58>:0x0000563fdf89fda8>

Deps

  • ruby 2.6.2
  • rails-5.1.7
  • activerecord-5.1.7
  • sorbet-0.4.4253
  • sorbet-runtime-0.4.4253
  • sorbet-rails-0.1.3

Please add instance methods for 4 items

Please add instance methods for:

  • ActiveStorage::Attachment
  • ActiveStorage::Blob
  • ActionMailbox::InboundEmail
  • ActionText::RichText

Versions:

  • Ruby: 2.4.6, 2.6.3
  • Rails: 5.2, 6.0, 6.1
  • Sorbet: Sorbet typechecker 0.4.4435
  • Sorbet-Rails: 0.4.0

Thanks

Add pluck_to_tstruct to Model & Relation

Describe the bug:
This will be a convenient thing for getting structured objects out of a relation.

Expected behavior:
Wizard.all.pluck_to_struct(TA[StructName].new, :attribute1, :attribute2) -> T::Array[StructName]

Versions:

  • Ruby:
  • Rails:
  • Sorbet:
  • Sorbet-Rails:

Readme mentions tasks that no longer exist?

Hi
Just giving this a spin and the README mentions

โฏ rake rails_rbi:helpers
โฏ rake rails_rbi:mailers
โฏ rake rails_rbi:custom
โฏ rake rails_rbi:all

But I dont seem to have any of these.

Documentation out of date?

New "Can't find gem for", "srb tc" errors, and todo.rbi line

Describe the bug:

7 new "srb tc" errors with latest sorbet-rails version

Steps to reproduce:

Try this after upgrading to edge (master version of) sorbet-rails gem.

  1. Run sorbet "bundle install" with sorbet-rails pointing to a
    local updated copy of sorbet-rails
  2. Run "srb init" then "rake rails_rbi:routes" then "rake rbi:models" then "srb tc".
  3. Results:
  • Lots of new "Can't find gem for" messages.
  • This is new in sorbet/rbi/todo.rbi file: module T::InterfaceWrapper::Helpers; end
  • I got 8 "srb tc" errors - all Wizard or Wand related. Previously it was 0 errors. One example:
sorbet/rbi/hidden-definitions/hidden.rbi:19042: Method `Wizard.Slytherin` redefined without matching argument count. Expected: `0`, got: `1` https://srb.help/4010
       19042 |  def self.Slytherin(*args); end
                ^^^^^^^^^^^^^^^^^^^^^^^^^
    sorbet/rails-rbi/models/wizard.rbi:161: Previous definition
     161 |  def self.Slytherin; end
            ^^^^^^^^^^^^^^^^^^

Expected behavior:

Expect "srb tc" to produce 0 errors.
No "Can't find gem for" messages.
No new todo.rbi line.

Versions:

  • Ruby: ruby 2.4.6p354 (2019-04-01 revision 67394) [x86_64-darwin16]
  • Rails: Rails 5.2.3
  • Sorbet: 0.4.4602
  • Sorbet-Rails: 0.4.0 using "path: '../sorbet-rails' to use edge version.

Support configurable generator for Model

If we refactor the ModelRbiFormatter to be more modular, we will be able to support custom generation logic:

  1. Customize the header.
    Great for us to be able to tag rbi file as autogenerated in code review tools (eg Phabricator)

  2. Add custom methods generator.
    People can add custom methods from a library or from an internal module.
    Would be nice to extract Rails methods to its own library too.
    We also has some need for this for Shrine & internal modules.

  3. (Extended) Ability to override ModelRbiFormatter with custom subclass in the rake task.
    In a rails initializer, people can set a subclass of ModelRbiFormatter so that it uses a custom one

Ability to call a model's class methods on the model's CollectionProxy

Describe the bug:

Rails has the ability to call class methods on a model's CollectionProxy. See this SO for an example:

https://stackoverflow.com/questions/22304809/rails-ability-to-call-my-class-method-on-an-array

This behavior is not currently supported in sorbet-rails

Steps to reproduce:

N/A

Expected behavior:

It should typecheck

Versions:

  • Ruby: ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]
  • Rails: Rails 5.2.3
  • Sorbet: Sorbet typechecker 0.4.4507 git d12b7144d2222398e0f28a772b7759fe26b2b9ba built on 2019-07-25 20:18:14 GMT with debug symbols
  • Sorbet-Rails: 0.4.0

Add rake rails_rbi:all

I'd like to regenerate the RBIs for models, routes, and helpers with one task. rake rails_rbi:all (or maybe just rake rails_rbi?) should invoke each of the three RBI tasks.

Fix warning "class variable access from toplevel"

Describe the bug:

We would like to get rid of this warning
lib/sorbet-rails/tasks/rails_rbi.rake:7: warning: class variable access from toplevel

Steps to reproduce:

It's because I added the following code in rails_rbi.rake. If we find another way to copy file, it'll be fine

# this is ugly but it's a way to get the current directory of this script
# maybe someone coming along will know a better way
@@sorbet_rails_rake_dir = File.dirname(__FILE__)

Expected behavior:
No warning

Versions:

  • Ruby:
  • Rails:
  • Sorbet:
  • Sorbet-Rails: 0.4.0

Improve Strictness of Attribute methods

Describe the bug:

Currently the attribute methods are applied to the base class via a module. ::GeneratedAttributeMethods This means however that they are not enforced.

Steps to reproduce:

# typed: true
# == Schema Information
#
# Table name: payments
#
#  id                                   :integer          not null, primary key
#  amount_in_cents                      :integer          not null
class Payment < ActiveRecord
  def amount
    "a bad string" # should fail type check
  end
end

For more context: https://sorbet-ruby.slack.com/archives/CHN2L03NH/p1570153844191700

Solution:

The solution is in the generated RBI to apply these directly to the class. I'm pretty sure this would be a breaking change as existing code may break.

Getting "expected \<some-error> but nothing was raised" during "rake" run

Steps to Reproduce:

Describe the bug:

  1. Yesterday and today, when I run "rake", I get these 6 failed tests:
rspec ./spec/custom_params_methods_spec.rb:58
rspec ./spec/custom_params_methods_spec.rb:64
rspec ./spec/custom_params_methods_spec.rb:98
rspec ./spec/custom_params_methods_spec.rb:131
rspec ./spec/boolean_string_spec.rb:52
rspec ./spec/integer_string_spec.rb:39
  1. All 6 error messages are of this format:
     Failure/Error:
       expect {
         ta.assert('<string>')
       }.to raise_error(some-error)

       expected <some-error> but nothing was raised
  1. Here is the "rake" log gist: https://gist.github.com/jasnow/9fd8dcd8ba7b31eb37827c01921d059a

  2. Yesterday when I was trying to debug this, I ran all the
    "rake update_spec_v#_#" commands and the
    spec/bin/update_test_data.sh script. Looking at my current
    fork on GitHub, I see updated gem and ruby versions in Gemfile
    and Gemfile.lock files and several "typed" changes.

  3. My local code is sync'ed with my fork on GitHub.

Expected behavior:

I expect all the test to pass as they do on TravisCI.

6. Versions:
-- Ruby: 2.5.6p201 (2019-08-28 revision 67796) [x86_64-darwin16]
-- Rails: 5.2.3
-- Sorbet: 0.4.4761
-- Sorbet-rails: 0.5.5.1
-- OS: 10.12.6

Should we support jobs with specific arguments?

Describe the bug:

When hidden.rbi contains something like this,

class DeleteBooksJob
  def perform(*args, &blk); end
end

(I'll refer to these as "non-specific" arguments.)

And jobs/delete_books_job.rb looks like this,

  sig {
    params(
      acting_user_id: Integer,
      book_ids: T::Array[Integer]
    )
  }
  def perform(acting_user_id, book_ids)

(I'll refer to these as "specific" arguments.)

then srb produces an error

be srb t
sorbet/rbi/hidden-definitions/hidden.rbi:8786: Method DeleteBooksJob#perform redefined without matching argument count. Expected: 2, got: 1 https://srb.help/4010
    8786 |  def perform(*args, &blk); end
            ^^^^^^^^^^^^^^^^^^^^^^^^
    app/jobs/delete_books_job.rb:13: Previous definition
    13 |  def perform(acting_user_id, book_ids)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Errors: 1

My question is:

Should we support jobs with specific arguments, according to my definition of "specific" given above?

Steps to reproduce:

rails new sorbet_rails_issue
bin/rails g model books title:string
bin/rails db:migrate
bin/rails g job delete_books
# install sorbet, then sorbet-rails according to standard instructions

Edit jobs/delete_books_job.rb as follows:

# typed: false

class DeleteBooksJob < ApplicationJob
  extend T::Sig
  queue_as :default

  sig {
    params(
      acting_user_id: Integer,
      book_ids: T::Array[Integer]
    ).void
  }
  def perform(acting_user_id, book_ids)
    # Do something later
  end
end

Notice the typed: false.

Run srb, see error:

sorbet/rbi/hidden-definitions/hidden.rbi:8786: Method DeleteBooksJob#perform redefined without matching argument count. Expected: 2, got: 1 https://srb.help/4010
    8786 |  def perform(*args, &blk); end
            ^^^^^^^^^^^^^^^^^^^^^^^^
    app/jobs/delete_books_job.rb:13: Previous definition
    13 |  def perform(acting_user_id, book_ids)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expected behavior:

srb should not produce error.

Versions:

  • Ruby: 2.6.5
  • Rails: 6.0.1
  • Sorbet: 0.4.5133
  • Sorbet-Rails: 0.5.8.1

Running tests raises a NameError for sigs receiving or returning an ActiveRecord_AssociationRelation

Describe the bug:

When you declare a method which receives or returns an ActiveRecord_AssociationRelation of some sort, tests fail with:

     NameError:
       private constant #<Class:0x00007fa75c4e8d28>::ActiveRecord_AssociationRelation referenced

Steps to reproduce:

create a method which returns an association relation on a model

class Post < ApplicationRecord
  belongs_to :user

  scope :published ->() { where(published: true) }
end

class User < ApplicationRecord
  extend T::Sig

  has_many :posts

  sig { returns(Post::ActiveRecord_AssociationRelation) }
  def published_posts
    posts.published
  end
end

RSpec.describe User do
  describe '#published_posts' do
    it 'returns only the published posts' do
      user = User.create!
      published = user.posts.create(published: true)
      user.posts.create(published: false)

      expect(user.published_posts).to eq([published])
    end
  end
end

This would raise a NameError claming that Post::ActiveRecord_AssociationRelation is a private class.

Note as well that in my case the models are on a rails engine.

Expected behavior:

The test passes

Versions:

  • Ruby: 2.4
  • Rails: 5.2.3
  • Sorbet: Sorbet typechecker 0.4.4891 git 4c9a4534439483b46e869c7212007ad103923203 built on 2019-10-17 22:56:24 GMT debug_symbols=true
  • Sorbet-Rails: 0.5.8

Problem with spec/support/5.2.3/db/migrate symbolic link

FYI:

When I "git pull upstream" this morning to resync your code with my fork, I got:

Broken symlinks detected:
/Users/USER/Projects/sorbet-rails/spec/support/5.2.3/db/migrate

โœ— One or more pre-commit hooks failed

Tried all kinds of things but the only thing that worked was to delete it from my copy.
Then "git commit" and "git push" worked.
Then I tried to add it back and got the same error as above.

ActiveRecord_Relation used in types is private

Describe the bug:

Method signatures for models in many cases use Model::ActiveRecord_Relation.
However, that is a private constant (rails/rails#30943)

Steps to reproduce:

Generate any model types

  1. rake "rails_rbi:models[Document]
  2. This creates rbi file with multiple method signatures that look like
  sig { params(args: T.untyped).returns(Document::ActiveRecord_Relation) }
  def self.sorted_by(*args); end

Expected behavior:

Not entirely sure.

What's interesting is that when I try to access the constant in development but not in non-dev environments.

irb(main):002:0> Rails.env
=> "development"
irb(main):003:0> Document::ActiveRecord_Relation
=> Document::ActiveRecord_Relation
irb(main):024:0> Rails.env
=> "qa"
irb(main):025:0> Document::ActiveRecord_Relation
Traceback (most recent call last):
        1: from (irb):25
NameError (private constant #<Class:0x0000559833e401d0>::ActiveRecord_Relation referenced)

Versions:

  • Ruby: 2.6.0p0
  • Rails: 5.2.3
  • Sorbet: 0.4.4782
  • Sorbet-Rails: 0.5.8.1

Generate sigs for scope, has_many, etc.

It is not possible to generate the sigs right now because T.proc support is limited right now.
For example:
It doesn't work with generic sorbet/sorbet#1139
It doesn't work with variable inputs sorbet/sorbet#1142
T.proc.bind doesn't work with T.nilable sorbet/sorbet#498
T.proc.bind doesn't work with lambda sorbet/sorbet#1143

Once support is improved, we can generate scope it like this

  sig { 
    params(
      name: Symbol, 
      body: T.proc.bind(District::Relation).returns(T.untyped), 
      block: T.nilable(T.proc.void),
    ).void
  }
  def scope(name, body, &block); end

Bugs: generated sig for mailer method doesn't include default value

Describe the bug:

  def notify(parent_id:, login_token: nil, should_update_sent_flag: true)

Generate

  sig { params(parent_id: T.untyped, login_token: T.untyped, should_update_sent_flag: T.untyped).returns(ActionMailer::MessageDelivery) }
  def self.notify(parent_id:, login_token:, should_update_sent_flag:); end

Steps to reproduce:

Expected behavior:

Versions:

  • Ruby:
  • Rails:
  • Sorbet:
  • Sorbet-Rails:

Add cursed methods to Rails models

These are all a mess and I'd prefer not to implement them, but I wanted to at least document them here, since they're taking up a lot of my hidden.rbi.

Is there a way to remove these from hidden.rbi without adding a bunch of useless methods to these classes?

Association Callback Methods

For every attribute on a model that has a relation with any other model, ActiveRecord/ActiveModel will have 12 methods. For example, let's say you add a relation on a Post that assigns a User as an author. Rails would create these methods:

# before add
def before_add_for_author; end
def before_add_for_author?; end
def before_add_for_author=(val); end

# before remove
def before_remove_for_author; end
def before_remove_for_author?; end
def before_remove_for_author=(val); end

# after add
def after_add_for_author; end
def after_add_for_author?; end
def after_add_for_author=(val); end

# after remove
def after_remove_for_author; end
def after_remove_for_author?; end
def after_remove_for_author=(val); end

Defined here: https://github.com/rails/rails/blob/5-2-stable/activerecord/lib/active_record/associations/builder/collection_association.rb#L32

These have barely any usage on GitHub, so I'm honestly not sure why they haven't been deprecated, but they do technically exist.

Dirty Methods

These only found their way into my hidden.rbi with Rails 6, but it seems like they've been there since at least 5.2? I'm not really sure why Sorbet couldn't find them before.

In 6.0 they're defined here: https://github.com/rails/rails/blob/v6.0.0.rc2/activemodel/lib/active_model/dirty.rb#L124-L126

If you declare an attribute name, you get these:

def name_change(*args); end
def name_changed?(*args); end
def name_previous_change(*args); end
def name_previously_changed?(*args); end
def name_was(*args); end
def name_will_change!(*args); end
def restore_name!(*args); end

There are also a few defined here: https://github.com/rails/rails/blob/v6.0.0.rc2/activerecord/lib/active_record/attribute_methods/dirty.rb#L19-L26

def saved_change_to_name?(*args); end
def saved_change_to_name(*args); end
def name_before_last_save(*args); end
def will_save_change_to_name?(*args); end
def name_change_to_be_saved(*args); end
def name_in_database(*args); end

And two here: https://github.com/rails/rails/blob/v6.0.0.rc2/activerecord/lib/active_record/attribute_methods/before_type_cast.rb#L32-L33

def name_before_type_cast(*args); end
def name_came_from_user?(*args); end

So that's 15 methods added per attribute (and this isn't counting the setter, getter, or asker), fun!

Support for serialize?

Just trying out Sorbet and this gem for the first time, so maybe there's a way to handle this already?

I have an ActiveRecord class that uses serialize field_name, Hash and the rake rails_rbi:models command has generated an rbi file where both the getter and setter methods for field_name are down as using the datatype T.nilable(String), which is the datatype of the underlying database field, rather than referencing Hash which is what those methods use thanks to serialize.

I've edited the generated rbi file for now, but wondered if there's a sig or something I should be writing on the class to make this work already? Or maybe this is a feature request for the gem?

A lot more "typed: ignore" files are been generated with srb commands

Describe the bug:

Yesterday, I saw a lot more "typed: ignore" files for my repos after running srb commands.
I saw several of them went from 0 "typed: ignore"s to 30+.
Sample repo: https://github.com/jasnow/rails_5.2_new .
Gist of "typed: ignore" files: https://gist.github.com/jasnow/b26be8a79da4ff230c68e31769ae5f69

Steps to reproduce:

To see "srb tc" errors, just change "ignore" to "false" and run "srb tc". Thanks.

Expected behavior:

Very few or zero "typed: ignore" files

Versions:

For the above sample repo:

  • Ruby: 2.4.7
  • Rails: 5.2.3
  • Sorbet: 0.4.4709
  • Sorbet-Rails: 0.5.3

Note that this also happened for Ruby 2.6 and Rails 6.0 repos.

5 failed specs after upgrading sorbet-rails

Describe the bug:

Failed specs after upgrading sorbet-rails

Steps to reproduce:

After updating my fork of sorbet-rails this morning and running "bundle update" and "rake", I get 5 failed specs.

Failed examples:

spec ./spec/rake_rails_rbi_models_spec.rb:10 # rake rails_rbi:models generates model files correctly
rspec ./spec/rake_rails_rbi_models_spec.rb:51 # rake rails_rbi:models generates more than 1 selected models correctly
rspec ./spec/sorbet_spec.rb:54 # sorbet returns expected sorbet tc result
rspec ./spec/sorbet_spec.rb:64 # sorbet passes sorbet dynamic checks
rspec ./spec/sorbet_spec.rb:71 # sorbet runs with srb tc --lsp

Expected behavior:

No failed specs.

Versions:

  • Ruby: 2.5.5p157
  • Rails: 5.2.3
  • Sorbet: 0.4.4673
  • Sorbet-Rails: 0.5.2

Gem Plugin Loading

Describe the bug:
It doesn't seem like the Kaminari plugin is being loaded (I only noticed now because I was just using my custom version until now). The page method isn't being generated by rake rails_rbi:models.

Steps to reproduce:

  1. Create a Rails app with Kaminari installed/configured
  2. Add sorbet and sorbet-rails
  3. Generate your model RBIs
  4. Note that uses of page still cause type errors because the method doesn't exist on any relevant model classes.

Expected behavior:
If I have Kaminari set up, the page method should be included in my RBIs.

Or, preferably, I could configure which plugins to load from the sorbet_rails.rb initializer.

Versions:

  • Ruby: 2.6.3
  • Rails: 6.0.0
  • Sorbet: 0.4.4667
  • Sorbet-Rails: 0.5.2

Generate a helpers.rbi

Rails helpers are generated with no parent, so Sorbet thinks they don't include Kernel, which means something like this will cause the typechecker to fail, despite being perfectly valid:

# typed: true
module ApplicationHelper
  def example
    puts "test"
  end
end

If a Rails app has helper modules, a helpers.rbi should be generated like so:

# typed: strong
module ApplicationHelper
  include Kernel
end

module GamesHelper
  include Kernel
end

module SettingsHelper
  include Kernel
end

I'm not sure if this is quite the correct fix, but I think it makes sense. It'd also be a base to build from for better helper support in the gem.

Improve gem tests by running Sorbet on a sample input

Gem's tests compare expected output from templates with the output from the code.
It is very useful as it proves that the rbi files are generated.

However there's no test that proves that generated rbi files are valid.

Task:
test generated rbi files against a sample code using sorbet

Select has incorrect return type when passed a block

Describe the bug:
ApplicationRecord.select has two different modes: one that takes a block and returns an Array, and one that takes any number of fields and returns an ActiveRecord::Relation. The sig that sorbet-rails generates claims it can only return a Relation.

Steps to reproduce:

class User < ApplicationRecord
end

Generated rbi file:

  sig { params(args: T.untyped, block: T.nilable(T.proc.void)).returns(User::ActiveRecord_Relation) }
  def select(*args, &block); end

Expected behavior:
To be honest, I'm not quite sure. Making the return type of select be T.any(User::ActiveRecord_Relation, T::Array[User]) is not great, because callers will always have to check which type is being returned, even though it can always be inferred from the argument type. But it might be the best we can do, since ruby doesn't support overloading.

Versions:

  • Ruby: 2.6.2
  • Rails: Rails 5.2.3
  • Sorbet: 0.4.4651
  • Sorbet-Rails: 0.5.0

Add config line to v5.0's config/application.rb file

Added the line below to the bottom of sorbet-rails/spec/support/v5.0/config/application.rb file
to get rid of "DEPRECATION WARNING: Time columns will become time zone aware in Rails 5.1." messages.

config.active_record.time_zone_aware_types = [:datetime]

Only v5.0 needs this line.

Getting NoMethodError when your run "rake rails_rbi:helpers" command.

Describe the bug:

Getting NoMethodError: undefined method `length' for nil:NilClass
when your run "rake rails_rbi:helpers" command.

Steps to reproduce:

  1. Clone my https://github.com/jasnow/rails_app5_2 repo.
  2. Run "rake rails_rbi:helpers" and you get:
rake aborted!
NoMethodError: undefined method `length' for nil:NilClass
/Users/USER/.rvm/gems/[email protected]/gems/sorbet-rails-0.5.0/lib/sorbet-rails/tasks/rails_rbi.rake:53:in `block (2 levels) in <top (required)>'
/Users/USER/.rvm/gems/[email protected]/gems/rake-12.3.3/exe/rake:27:in `<top (required)>'
/Users/USER/.rvm/gems/[email protected]/bin/ruby_executable_hooks:24:in `eval'
/Users/USER/.rvm/gems/[email protected]/bin/ruby_executable_hooks:24:in `<main>'
Tasks: TOP => rails_rbi:helpers
(See full trace by running task with --trace)

Expected behavior:

-- Generate sigs for helpers --

Versions:

  • Ruby: ruby 2.4.6p354 (2019-04-01 revision 67394) [x86_64-darwin16]
  • Rails: 5.2.3
  • Sorbet: 0.4.4602
  • Sorbet-Rails: 0.5.0

Add support for helpers method in controllers

Rails 5.0+ has a method called helpers which is available in controllers. https://blog.bigbinary.com/2016/06/26/rails-add-helpers-method-to-ease-usage-of-helper-modules-in-controllers.html

So, for example if you had this application_helper.rb:

module ApplicationHelper
  extend T::Sig

  sig { returns(Integer) }
  def forty_two
    return 42
  end
end

Then, in users_controller.rb you could have code like helpers.forty_two. helpers will include methods from any of the helper classes you've created.

class UsersController < ApplicationController
  def index
    @number = helpers.forty_two
  end
end

It's not possible to create a type signature for this method statically, it has to be done dynamically.

e.g. like this:

module ActionController::Helpers
  sig { returns(T.all(ApplicationHelper, GamesHelper, UsersHelper)) }
  def helpers; end
end

Negative enum scope support on Rails 6.0

Negative enum scopes are a feature in Rails 6, it'd be nice if they were generated as part of sorbet-rails :)

Expected behavior:
sorbet-rails would generate negative enum scopes, e.g. if you had an enum for User, like so:

enum role: {
  member: 0,
  moderator: 1,
  admin: 2
}

Then you could write code like this:

user = User.new
return PermissionsError if user.not_admin?

Currently, it doesn't seem that sorbet-rails generates these.

Segmentation fault on 0.4.4295

cat Gemfile
...
group :development do
  gem 'sorbet'
  gem 'sorbet-runtime'
  gem 'sorbet-rails'
end
...
bundle install
bundle exec srb rbi sorbet-typed
rake rails_rbi:routes
rake rails_rbi:models

but when I tried

bundle exec srb tc --suggest-typed --typed=strict --error-white-list=7022 --autocorrect

I got following error

vendor/bundler/ruby/2.6.0/gems/sorbet-0.4.4295/bin/srb: line 43: 83774 Segmentation fault: 11  "${sorbet[0]}" "${args[@]}"

Can you help me to figure out it?

OS: macOS Mojave 10.14.5 (18F132)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.