chanzuckerberg / sorbet-rails Goto Github PK
View Code? Open in Web Editor NEWA set of tools to make the Sorbet typechecker work with Ruby on Rails seamlessly.
License: MIT License
A set of tools to make the Sorbet typechecker work with Ruby on Rails seamlessly.
License: MIT License
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:
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.
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:
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.
Describe the bug:
Getting NoMethodError: undefined method `length' for nil:NilClass
when your run "rake rails_rbi:helpers" command.
Steps to reproduce:
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:
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:
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.
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:
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?
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?
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:
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:
What does this mean when I run into "rake rails_rbi:models": Skip method ... because it is not autogenerated by Rails.
Flagged on Sorbet Slack
https://sorbet-ruby.slack.com/archives/CJL5B3CEN/p1561129789024600
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:
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:
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?
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
These have barely any usage on GitHub, so I'm honestly not sure why they haven't been deprecated, but they do technically exist.
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!
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:
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.
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
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
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:
Describe the bug:
Steps to reproduce:
Expected behavior:
Versions:
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:
Currently, the README says:
Sorbet does not allow us to define multiple signatures for a function.
But it seems to work for Enumerable#first for instance, and the definition in Sorbet uses multiple signatures for a function: https://github.com/sorbet/sorbet/blob/119e937e9e3b03ec27308cd8874f482791d15864/rbi/core/enumerable.rbi#L167-L174
Probably that was in an earlier version of Sorbet and now it could work out of the box?
Rails 5 add a new API that let users define a custom type for attributes in a model. Currently Sorbet-rails read the attribute type from the database definition.
Learn more about attributes api: https://blog.bigbinary.com/2018/12/11/rails-5-attributes-api.html
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:
rails g job myjob
false
or higherrake rails_rbi:all
ack perform_now sorbet/rails-rbi
no occurrencesExpected behavior:
rake rails_rbi:all
should generate RBI for perform_now
and perform_later
.
Versions:
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.
Steps to Reproduce:
Describe the bug:
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
Failure/Error:
expect {
ta.assert('<string>')
}.to raise_error(some-error)
expected <some-error> but nothing was raised
Here is the "rake" log gist: https://gist.github.com/jasnow/9fd8dcd8ba7b31eb37827c01921d059a
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.
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
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!
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)
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:
Note that this also happened for Ruby 2.6 and Rails 6.0 repos.
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
See issue #33
We should use "::#{reflection.klass.name}"
instead of reflection.class_name
to avoid the problem
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>
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
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 :/
If we refactor the ModelRbiFormatter to be more modular, we will be able to support custom generation logic:
Customize the header.
Great for us to be able to tag rbi file as autogenerated in code review tools (eg Phabricator)
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.
(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
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
rake "rails_rbi:models[Document]
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:
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
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:
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.
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.
The routes formatter should be updated like the model formatter to use Parlour, for consistency :)
Please add instance methods for:
Versions:
Thanks
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:
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.
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
)
Should we upgrade repo to latest Ruby 2.4.x (2.4.6) release?
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:
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:
Describe the bug:
We can improve the code for finding out the assignable type for attribute writter.
See #223
Steps to reproduce:
Expected behavior:
Versions:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.