Solargraph: Rails support

Created on 17 Sep 2018  路  93Comments  路  Source: castwide/solargraph

I know Rails support is only partial at the moment, but I have installed the Solargraph gem, and am using the VSCode extension, and when I am in a Rails application, I am not getting any Rails-related completions/suggestions whatsoever.

I don't even get a suggestion for the "Rails" class. I just want to make sure I am not getting the wrong end of the stick in terms of what amount of Rails support Solargraph actually has? Solargraph itself is working fine - I am getting standard Ruby suggestions no problem.

Most helpful comment

There are a couple of things you can try.

  1. Make sure you have gem documentation installed by running yard gems.

  2. Add a .solargraph.yml file to the app's root directory (you can generate a default one by running solargraph config) and make the following change to the require section:

    require:
    - actioncable
    - actionmailer
    - actionpack
    - actionview
    - activejob
    - activemodel
    - activerecord
    - activestorage
    - activesupport
    

That should get you closer, but it's still far from perfect. Improving Rails support has been on the roadmap for a while. The amount of runtime magic involved makes it challenging, but I have some updates in the works that should help.

All 93 comments

There are a couple of things you can try.

  1. Make sure you have gem documentation installed by running yard gems.

  2. Add a .solargraph.yml file to the app's root directory (you can generate a default one by running solargraph config) and make the following change to the require section:

    require:
    - actioncable
    - actionmailer
    - actionpack
    - actionview
    - activejob
    - activemodel
    - activerecord
    - activestorage
    - activesupport
    

That should get you closer, but it's still far from perfect. Improving Rails support has been on the roadmap for a while. The amount of runtime magic involved makes it challenging, but I have some updates in the works that should help.

I hope it's fine if I add my thoughts here. First of all, thanks for your work! I've found this thread after noticing that Solargraph wouldn't know how to handle a goto definition click on has_many :users, where I'd expect it to open the User class. I'm not sure how much runtime magic is involved here but having this would be a big improvement.

Hi, any news on this?

Is there any dedicated branch for Rails where we could help you to implement it?

Solargraph's YARD support is at a point where some of the missing Rails intellisense can be filled with a small @!parse directive. I created a gist for it here: https://gist.github.com/castwide/28b349566a223dfb439a337aea29713e

I'm looking for ways to improve it, including ways to make it easy to install and maintain. Any suggestions are welcome.

@castwide Using the gist above, it works well in many cases... thank you! However, in the 'activesupport' gem, there is a method blank? which is not getting picked up... is there a workaround? (.gem/ruby/2.5.3/gems/activesupport-5.2.2.1/lib/active_support/core_ext/object/blank.rb)

@mathieushopify It works in circumstances where a type can be inferred:

obj = Object.new
obj.b # <= suggests blank?

str = 'str'
str.b # <= suggests blank?

If those don't work, make sure you have the latest gem version (0.33.0 was released this morning) and run yard gems to make sure they're documented.

Completion won't work on on unknown types, which is unfortunately the status of most of the Rails API; for example, completion will suggest ApplicationRecord.find, but doesn't know what type find returns, so it won't make any suggestions for methods chained to it.

Makes sense, thanks for the prompt reply! :-)

@castwide Don't most types inherit from Object, though?

Although the lack of completions it can be a useful indicator that the type is in not inferred. "Some completions" is not always better than "no completions".

@dgutov Yeah, my personal preference is for undefined types to return no completions instead of assuming Object. It's less ambiguous about whether a type was detected.

If anyone finds it more useful to assume Object for untagged methods, we might be able to make it a configuration option.

Version 0.34.0 introduces some new features that should add some improvements to Rails support.

Quick Start

  1. Install the latest Solargraph gem.
  2. Run solargraph bundle from your Rails app's root directory.
  3. Add the most recent version of this file: https://gist.github.com/castwide/28b349566a223dfb439a337aea29713e

How It Works

  • solargraph bundle makes sure that YARD documentation is installed for all your gems. Rails gems get parsed with RDoc first, then converted to YARD and saved in Solargraph's cache directory.
  • The YardMap detects that the code calls Bundler.require and automatically adds gem dependencies to the map, so the @!parse require directives are no longer necessary.
  • The gist file adds explicit references to a few more modules that Rails automagically includes and extends.
  • The @!override in the gist applies overloaded methods with return types to ActiveRecord::FinderMethods#find.

Known Issues

  • Although this process fills in a lot more methods, practically none of them have documented return types. The @!override directive might be a way to fix that, but I'm not sure if it'll be a long-term solution.
  • Using go-to-definition on a symbol with custom documentation should open the correct file, but it always goes to the first line. (Go-to-definition on other gems still works correctly.)
  • The RDoc-to-YARD conversion is necessary so Rails magic methods documented in RDoc will be visible in Solargraph. It might be a good idea to implement this feature as a YARD plugin.
  • If the custom documentation gives you any trouble, you can run solargraph clear && solargraph download-core to reset it.
  • There are a lot more includes and extends that could be added to the gist. Any help is appreciated.

When you intend to fix this issue?

Using go-to-definition on a symbol with custom documentation should open the correct file, but it always goes to the first line. (Go-to-definition on other gems still works correctly.)

I think it should go to the correct line.

@castwide thanks for the update!

Great stuff! Thanks!

@castwide can you tell me that if that was an ordinary work or it have an issue??

@minkir014 I'm sorry, I don't know what you mean.

Gem 0.34.1 fixes some issues that occurred in certain bundler environments.

As I know about go to definition that it must go to a certain line that the class or any other thing is defined and you said

Using go-to-definition on a symbol with custom documentation should open the correct file, but it always goes to the first line. (Go-to-definition on other gems still works correctly.)

That means that some gems have problems with go to definition. So, when do you intend to fix this issue???

@minkir014 I don't know when it will be fixed because I don't even know what the root cause is. When the RdocToYard component generates an RDoc store, all the code objects have nil line numbers.

You could file an issue against RdocToYard gem. It maybe a problem with it.

Is there a way to manage models values with Solargraph?
E.g for the User model, to have autocompletion on user.id, user.created_at, etc...

@tvallois I'm working on a Rails convention that should be able to map model attributes from the database schema.

Right now the only other option is to document them yourself, e.g., with the @!attribute directive:

class User < ActiveRecord::Base
  # @!attribute id
  #   @return [Integer]
  # @!attribute name
  #   @return [String]
end

@castwide Hey, I was thinking of building a script that uses annotations built by annotate gem to add types to models. You said that you're working on something similar? Have you pushed any code towards that? I would like to help and start building it myself if you haven't :man_technologist:

# == Schema Information
#
# Table name: groups
#
#  id           :bigint(8)        not null, primary key
#  name         :string
#  created_at   :datetime         not null
#  updated_at   :datetime         not null
#  namespace_id :bigint(8)        indexed
#

class Group < ApplicationRecord
  # @!attribute id
  #   @return [Integer]
  # @!attribute name
  #   @return [String]
  # @!attribute created_at
  #   @return [Date]
  # @!attribute updated_at
  #   @return [Date]
  # @!attribute namespace_id
  #   @return [Integer]

  ...
end

@Zeko369 I don't have anything substantial. If you can build something, that would be awesome. I'm not sure how integration will work yet, but we can worry about those details after we have a working implementation.

@Zeko369 I would be happy to collaborate on this as well.

hi @castwide ,
I'm working on an implementation to generate yard documentation for models with annotate_models gem however when i have an attribute like:

# @!attribute generating
#   @return [TrueClass]
#   @return [FalseClass]

Solargraph only return TrueClass on the autocompletion. Is it a bug or normal behavior?

That's a known limitation. When you have multiple return tags, it should report all the types, but right now it only processes the first one. It works correctly if you add multiple types to a single tag, e.g., @return [TrueClass, FalseClass]. Support for multiple tags is on the roadmap. It's been a low priority, but it shouldn't be difficult.

In this case, you might prefer to use @return [Boolean] instead. It's not a real class, but YARD conveniently understands it.

2\. solargraph bundle

Sorry for this really newbie question, but where is located the rails.rbfile? I'm trying to diagnose why I always have the message

Starting the Solargraph language server

Thanks.

@romu70 Create a rails.rb file in the root of your project add do something like this https://gist.github.com/castwide/28b349566a223dfb439a337aea29713e

Thanks @Zeko369 . Is this normal all the text in this file is commented out?

Having all the text commented is normal, yes. It uses YARD directives to augment the API maps without affecting real code.

The rails.rb file should be a temporary solution while we hammer out the details for proper Rails support. Eventually I'd like to have a plugin that automatically fills the gaps in the Rails API, similar to how the Solargraph core provides overrides for the Ruby stdlib and a "convention" for Gemfiles.

Ok thanks. I restarted my VSCode, but I'm still getting the permanent message "Starting the Solargraph language server"

Ok thanks. I restarted my VSCode, but I'm still getting the permanent message "Starting the Solargraph language server"

Try running solargraph stdio to start a server in your console, rather than vscode starting it for you. It should be easier to debug any issues it has starting that way.

@romu70 A few other things to help you troubleshoot:

  1. Make sure you're using the latest version of Solargraph (currently v0.38.5)
  2. Check if you have any errors in the developer console (Help -> Toggle Developer Tools)
  3. Run solargraph scan -v to check for problems mapping your project (https://solargraph.org/guides/scanning-workspaces)

Thanks for the help.

  1. I run 0.38.5
  2. In the dev tools, I get 5 warnings about the syntax grammar overrides, and one error related to Ruby (not sure if it is related to Solargraph tough):

Error: Unable to read file (EntryNotFound (FileSystemError): Error: ENOENT: no such file or directory, open '/Users/romu/.vscode/extensions/rebornix.ruby-0.26.0/language-configuration-ruby.json')

  1. solargraph scan -vprocessed 27727 pins in 16.6 seconds (approx).

That error comes from the main Ruby extension. Their repo has an issue for it.

Since the scan seems okay, you might be encountering a bug in starting or connecting to the language server. If the problem persists, please start a new issue for it, and I'll try to help you continue troubleshooting.

I tried to get this file and put it into the rebornix folder shown in the error message.

Now, no more error.

Screenshot 2020-02-11 at 20 33 14

And it seems to work correctly.

Screenshot 2020-02-11 at 20 36 18

Even if, I've still the message in the status bar.

Screenshot 2020-02-11 at 20 36 54

So I do confirm the problem was the language-configuration-ruby.json file was missing.

Is there a known way to gracefully handle has_many-like constructs?

I currently use:

# @!attribute members
#   @return [ActiveRecord::Associations::CollectionProxy]
has_many :members,
         through: :organizations_users,
         source: :user

But really what would be awesome would be something like ActiveRecord::Associations::CollectionProxy<Users::User>, like an array. So that accesses to the elements have type information.

Seeing a bit of a strange behaviour here with Solargraph 0.39.8. I have a pretty standard application_record.rb file:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

When I try to find definition of ActiveRecord::Base, solargraph finds the active_record/base.rb file, but does not navigate to the ActiveRecord::Base class itself.

I'm also not seeing model magic methods, like where and so on, even though I have the tweaks from https://gist.github.com/castwide/28b349566a223dfb439a337aea29713e under config/solargraph.rb.

Could these two things be related?

@immerrr

  1. There's a known issue with the custom documentation generated for Rails gems. The first step is to build RDoc documentation, and for some reason this process drops line numbers. I'm working on a fix, but can't provide an ETA yet.
  2. Is the config directory (or, at least, the config/solargraph.rb file) included in your .solargraph.yml configuration?

re: 2: solargraph.yml is the default one, that includes

include:
- "**/*.rb"

I suppose that means config/solargraph.rb should be included. Any way I can confirm that with more certainty?

I suppose that means config/solargraph.rb should be included. Any way I can confirm that with more certainty?

@immerrr Hmm, that's a good candidate for an enhancement. One workaround is to add a line like Class CanYouSeeMe; end to it and see if CanYouSeeMe is a completion suggestion in other files.

Have you tried running solargraph bundle from your project's root?

I commented this on the wrong issue, hopefully nobody gets spammed.
I've also been struggling getting the ActiveRecord to work well with solargraph. I'm not sure if I'm missing anything crucial. I've followed all the rails related help I could find.
I made a small generator using activerecord reflections, here is the gist
It just generates classes with yard / solargraph comments in them.
@Zeko369 @tvallois @qortex @castwide

@immerrr Update on the line number issue. There's a fix in the master branch that will be included in the next patch release.

The fix for line numbers is released in v0.39.9. You might need to run solargraph bundle --rebuild to regenerate cached documentation.

Just tried that out, failed with NoMethodError:

$ solargraph bundle --rebuild
Documenting rake 13.0.1
Documenting concurrent-ruby 1.1.6
Documenting aasm 4.12.3
Documenting i18n 1.8.2
Documenting minitest 5.10.3
Documenting thread_safe 0.3.6
Documenting tzinfo 1.2.7
Documenting activesupport 5.0.7.2
Caching custom documentation for activesupport 5.0.7.2
Traceback (most recent call last):
    20: from /home/immerrr/.rvm/gems/ruby-2.5.8/bin/ruby_executable_hooks:24:in `<main>'
    19: from /home/immerrr/.rvm/gems/ruby-2.5.8/bin/ruby_executable_hooks:24:in `eval'
    18: from /home/immerrr/.rvm/gems/ruby-2.5.8/bin/solargraph:23:in `<main>'
    17: from /home/immerrr/.rvm/gems/ruby-2.5.8/bin/solargraph:23:in `load'
    16: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/bin/solargraph:5:in `<top (required)>'
    15: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/thor-1.0.1/lib/thor/base.rb:485:in `start'
    14: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
    13: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
    12: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
    11: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/shell.rb:193:in `bundle'
    10: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/documentor.rb:26:in `document'
     9: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/documentor.rb:26:in `each_pair'
     8: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/documentor.rb:44:in `block in document'
     7: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/yard_map/rdoc_to_yard.rb:17:in `run'
     6: from /home/immerrr/.rvm/rubies/ruby-2.5.8/lib/ruby/2.5.0/tmpdir.rb:93:in `mktmpdir'
     5: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/yard_map/rdoc_to_yard.rb:20:in `block in run'
     4: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/yard_map/rdoc_to_yard.rb:20:in `chdir'
     3: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/yard_map/rdoc_to_yard.rb:34:in `block (2 levels) in run'
     2: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/yard_map/rdoc_to_yard.rb:34:in `each'
     1: from /home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/yard_map/rdoc_to_yard.rb:41:in `block (3 levels) in run'
/home/immerrr/.rvm/gems/ruby-2.5.8/gems/solargraph-0.39.9/lib/solargraph/yard_map/rdoc_to_yard.rb:112:in `commentary': undefined method `parts' for #<String:0x0000000004d19cd8> (NoMethodError)

Just tried that out, failed with NoMethodError:

That's weird. I'm sure I've never seen that attribute be a String before.

Fixed and released in v0.39.10.

Adding the gist seems to crash solargraph when running solargraph scan. It seems to be failing at the parse directive (removing it solves the issue), although it could be affecting any directive:

bundle exec solargraph scan
Traceback (most recent call last):
        25: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/bin/ruby_executable_hooks:24:in `<main>'
        24: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/bin/ruby_executable_hooks:24:in `eval'
        23: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/bin/solargraph:23:in `<main>'
        22: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/bin/solargraph:23:in `load'
        21: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/bin/solargraph:5:in `<top (required)>'
        20: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/thor-1.0.1/lib/thor/base.rb:485:in `start'
        19: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
        18: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
        17: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
        16: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/shell.rb:171:in `scan'
        15: from /Users/ferdaber.rvm/rubies/ruby-2.7.1/lib/ruby/2.7.0/benchmark.rb:293:in `measure'
        14: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/shell.rb:172:in `block in scan'
        13: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/api_map.rb:170:in `load'
        12: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/api_map.rb:67:in `catalog'
        11: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/api_map.rb:67:in `each'
        10: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/api_map.rb:85:in `block in catalog'
         9: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map.rb:156:in `map'
         8: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:50:in `map'
         7: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:27:in `map'
         6: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:203:in `process_comment_directives'
         5: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:203:in `each'
         4: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:206:in `block in process_comment_directives'
         3: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:69:in `process_comment'
         2: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:69:in `each'
         1: from /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:72:in `block in process_comment'
            /Users/ferdaber.rvm/gems/ruby-2.7.1@ferdaber/gems/solargraph-0.39.10/lib/solargraph/source_map/mapper.rb:158:in `process_directive': undefined method `strip' for nil:NilClass (NoMethodError)

I'm working on a fix. For now the workaround is to remove the comments above the @!parse directive. See also #329.

Fix released in v0.39.11.

Here is my latest gist for documenting AR attributes and relations on models, heavily influenced/plagiarized from other gists in this issue: https://gist.github.com/iftheshoefritz/7a195eb5676bb790cdbff91ab7d42f31. It generates files in config/yard, one per class, and my editor is now doing autocomplete nicely based on them.

Now I'm trying to look at how to go to definition. My editor takes me to the generated YARD files instead of to the original model source. I'm wondering if there is any way to get YARD to point readers to a location in a different file for the original source?

I'm guessing that solargraph bundle behaves similarly to this? Assuming it doesn't actually alter gem source but actually generates separate docs and has some record of the real source location. How does Solargraph do this?

Seeing a bit of a strange behaviour here with Solargraph 0.39.8. I have a pretty standard application_record.rb file:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

I have the same generated application_record.rb and I find that with Strict typing I get this error:

/path/to/app/models/application_record.rb:2 - Unresolved call to abstract_class=

I do have the gist installed and confirmed working via the "CanYouSeeMe trick".

I tried adding a line include ActiveRecord::Inheritance to try to pull in the right definitions but it didn't work.

Is it expected that this fails? I'm a bit at a loss as to how to fix this.

@amake The line should be extend ActiveRecord::Inheritance::ClassMethods

I added it to the gist.

Thanks, that did it 馃憤

Hey, dunno if I'm missing something but I followed the instructions (installed the gist, ensured it works with the CanYouSeeMe trick), but even with a simple AR class I'm not seeing any finders or anything.

$ bundle exec solargraph scan -v | grep Employee
Employee (/Users/tyler/projects/movati/app/models/employee.rb 0)
Employee | ApplicationRecord (/Users/tyler/projects/movati/app/models/employee.rb 0)

How can I investigate further?

Hi, same here, everything is working very well, except that I don't have any inherited Rails methods.Ruby's methods and my project's methods are processed correctly. I followed all instructions previously given.
On all Rails methods (has_many, validates, ...) I get a unresolved call error (even if I require Rails gems in .solargraph.yml). I apparently have the same issue as @amake , but the gist update did not do the trick.
Putting @!attribute tags in models inherited from ActiveRecord does not fix the problem either. Are we supposed to write some other @parse tags or some sort in our classes? I don't know how to solve this unresolved call.
I forgot to mention that this behaviour appears on strict type checking mode only.

Thank you very much for your awesome work!

@tyler-boyd @Mate2xo What versions of Ruby and Rails are you using? It looks like the Rails gist doesn't work on certain combinations. For example, I got it to work as expected on Ruby 2.6.3 and Rails 6.0.3.2, but not on Ruby 2.3.0 and Rails 5.0.7.2.

@castwide For my current project, I am using Ruby 2.6.6 and Rails 6.0.3.3. I have actually noticed that I don't have autocompletion from Rails methods (e.g. no #find methods), but I get a few suggestions for a few class names.

E.g. I can type Active and then get the suggestion for ActiveRecord, I can then type :: (so to give ActiveRecord::), and then get suggestion forActiveRecord::Base; these suggestions come from the language server. All existing classes are not suggested though, and the only methods that are suggested are Ruby core methods (fromClass,ModuleandObject`)

So I have autocompletion for Ruby core definitions, and for everything I have defined in my project. I am using Vim with the Coc.nvim plugin, which actually uses VSCode's language server (if that's useful to know).
I will try to use it with Rails 5.2 and Ruby 2.5 on another project to see if I see any difference, and give you the feedback

I tried to get this file and put it into the rebornix folder shown in the error message.

Now, no more error.

Screenshot 2020-02-11 at 20 33 14

And it seems to work correctly.

Screenshot 2020-02-11 at 20 36 18

Even if, I've still the message in the status bar.

Screenshot 2020-02-11 at 20 36 54

So I do confirm the problem was the language-configuration-ruby.json file was missing.

@romu70 How did you manage to get all of the activerecord methods?

-----------
Platform: x86_64-linux
Shell: /bin/zsh
Ruby Version: 2.7.1
RuboCop Version: 0.92.0
Rails Version: 6.0.3.3

Solargraph
---------------
vscode-solargraph: v0.21.1
Solargraph Version: 0.39.17
Core Documentation Version: 2.7.1
Core Cache Directory: ~/.solargraph/cache
Using Bundler: true
Project
Config: {"completion"=>true, "hover"=>true, "symbols"=>true, "definitions"=>true, "rename"=>true, "references"=>true, "autoformat"=>true, "diagnostics"=>true, "formatting"=>true, "folding"=>false, "logLevel"=>"warn", "enablePages"=>true, "viewsPath"=>"~/.vscode-insiders/extensions/castwide.solargraph-0.21.1/views", "transport"=>"socket", "externalServer"=>{"host"=>"localhost", "port"=>8708}, "commandPath"=>"$HOME/.rbenv/shims/solargraph", "useBundler"=>true, "bundlerPath"=>"bundle", "checkGemVersion"=>true}

@castwide I tried including the definitions.rb from https://gist.github.com/castwide/28b349566a223dfb439a337aea29713e and also did bundle exec yard gems and bundle exec solargraph bundle --rebuild.

But still hover infos/defintions for certain callback methods etc are not shown in vscode, even though YARD docs exist. I'm wondering if it's an issue from my side or if it's a problem with the configuration.

Example of hover info I was referring to/expected hover info(this is taken from RubyMine):-
Screenshot_20201009_120826

As you can see the before_action gets correct hover info in RubyMine. Not sure what their mechanism is. In vscode, we should get the same kinda info since I had added the following to the definitions.rb file in root of project. That is expectable, right?:-

# @!parse
#   class ActionController::Base
#     include ActionController::MimeResponds
#     extend ActiveSupport::Callbacks::ClassMethods
#     extend AbstractController::Callbacks::ClassMethods #--------> This should provide the info for before_action, right?
#   end

Currently in vscode no hover info/go to definition is available for before_action and other callback methods etc.

I can definitely help and provide any other configurations or debug info required. Do let me know.

Current bundle exec solargraph scan -v reports an error which I don't know if it's the reason for not showing hover info/definitions(the errors have been cut short since it's very long):-

RubyVM::AbstractSyntaxTree
RubyVM::AbstractSyntaxTree::Node
RubyVM::AbstractSyntaxTree::Node | Object
Errno::ENOTEMPTY
Errno::ENOTEMPTY | SystemCallError
Errno::ENOTNAM
Errno::ENOTNAM | SystemCallError
.
.
.
Errno::ENOTCONN
Errno::ENOTCONN | SystemCallError
Errno::ENOTDIR
Errno::ENOTDIR | SystemCallError
Scanned ~/granite (20340 pins) in 8.750855500999933 seconds.

My .solargraph.yml:-

---
include:
  - "**/*.rb"
  - "config/model_definitions/task.rb"
  - "definitions.rb"
exclude:
  - spec/**/*
  - test/**/*
  - vendor/**/*
  - ".bundle/**/*"
require:
  - actioncontroller
  - actioncable
  - actionmailer
  - actionpack
  - actionview
  - activejob
  - activemodel
  - activerecord
  - activestorage
  - activesupport
domains: []
reporters:
  - rubocop
  - require_not_found
  - typecheck
require_paths:
  - "config/model_definitions"
plugins: []
max_files: 10000

Solargraph in Gemfile:-

group :development do
  gem 'rubocop', require: false
  gem 'rubocop-rails', require: false
  gem 'rubocop-performance', require: false
  gem 'reek', require: false
  gem 'solargraph', require: false
  gem 'yard', require: false
end

Extras

Running the local bundle exec yard server --gems within the project, shows me the docs related to all gems and showsAbstractController::Callbacks::ClassMethods for actionpack which we included in definitions.rb. So if yard has the docs related to a particular method, then wouldn't solargraph be able to use that directly?
image

Another Example where YARD docs are not being read

class TasksController < ApplicationController
  before_action :load_task, only: %i[show edit update destroy]

  # @!parse extend ActionController::Instrumentation
  def new
    p method(:render).owner.ancestors
    render # ------------------------------------------> I don't get any definitions for public method render from ActionController::Instrumentation in vscode even when I had added the YARD comment above
  end

Expectation(screenshot from RubyMine)

Screenshot_20201009_132401

As I have created setup for my project and included the Gist, latest version of solargraph does not provide any ActiveRecord class methods for AR classes. Just generic list of Object methods. not sure if I am doing everything right but I have completed steps in a comment above.
image

seems to be the same case as @Mate2xo

upon further inspection scan does not include any methods from rails gems for some reason(with or without defintions.rb).

rails 6.0.3.3
ruby 2.6.5
solargraph 0.39.17

Having the same issue, no AR methods. Using rails.rb definitions.


I did have success with @iftheshoefritz script for methods: https://gist.github.com/iftheshoefritz/7a195eb5676bb790cdbff91ab7d42f31

But no class level methods.

Rails 6.0.3.4
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin19]
solargraph (0.39.17)

Having done some digging I can verify that methods do appear in v0.38.6, did a bit more skip testing:

  • v0.39.0 fails to bundle,
  • v0.39.5 bundle success, no methods appear,
  • v0.39.10 bundle success, fails to start server,
  • v0.39.15 bundle success, no methods appear

Cheers

@RobertLowe I'm wondering if it's a compatibility issue with the Ruby version. Can you please check if you get proper intellisense and auto-completions for solargraph v0.38.6 which worked for you and somewhat latest ruby version say 2.7.2 or 2.7.1?
Thanks

Also, if possible, let me know whether your solargraph was installed via Gemfile or globally. I always handled both yard and solargraph from my Gemfile.

@yedhink locally bundle install'd gems no globally install ones:

v0.38.6 + ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19], bundle success, methods appear
v0.39.17 + ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19], bundle success, no methods appear

Cheers

Another thing:

# extend ActiveRecord::Persistence::ClassMethods

Should be added to class ActiveRecord::Base in https://gist.github.com/castwide/28b349566a223dfb439a337aea29713e

@RobertLowe How do I run that gists you have posted https://gist.github.com/iftheshoefritz/7a195eb5676bb790cdbff91ab7d42f31

@guledali From the comments in the script:-

 # run the script as a rails runner:
 # bundle exec rails r ./bin/generate_solar_models.rb

Make sure you customise the paths appropriately to suit your project, within the script. Ultimately, after running that script, we get instance methods and variables associated with a particular model/table i believe. And I also think, we might've to run it often, when adding new attributes to the table.

[Edit] I think using it as rake task can workout.

require 'fileutils'

namespace :solargraph do
  task update_model_definitions: :environment do
    if Rails.env.development?
      Rails.application.eager_load! unless Rails.application.config.cache_classes
      Zeitwerk::Loader.eager_load_all if defined?(Zeitwerk)

      # model_definitions should be replaced whatever dir name you want in config dir
      ApplicationRecord.descendants.each do |model|
        def_file = Rails.root.join('config', 'model_definitions', "#{model.name.underscore}.rb")
        FileUtils.mkdir_p File.dirname(def_file)

        File.open(def_file, 'w') do |file|
          file << "class #{model.name}\n"
          klass = model.name.constantize
          klass.attribute_names.each do |name|
            file << "#   @!attribute [rw] #{name}\n"
            file << "#     @return [#{ruby_type[klass.type_for_attribute(name).type]}]\n"
          end
          file << "end\n"
        end
      end
    end
  end

  task generate: :environment do
    # Add the folder you choose in your config/application.rb
    # example:
    # config.autoload_paths << Rails.root.join('app/solargraph')
    gen_directory = Rails.root.join('config', 'model_definitions')

    # run the script as a rails runner:
    # jundle exec rails r ./bin/generate_solar_models.rb

    # if you wanted to choose specific models to generate for
    # models =  [User]
    Rails.application.eager_load!
    models = ApplicationRecord.descendants
    puts("generating for #{models.count} models")

    models.each do |model|
      puts "processing #{model.name}."
      columns = model.columns.map do |col|
        type = type_translation[col.type]
        <<~TXT
          # @!attribute #{col.name}
          #   @return [#{type}]
        TXT
      end

      reflections = model.reflections.map do |key, reflection|
        type = reflection_comment(reflection)
        puts "KEY: #{key} TYPE: #{type}"
        next if type.nil?

        <<~TXT
          # @!attribute #{key}
          #   @return #{type}
        TXT
      end

      generated_attributes = <<~TXT
        class #{model.name}
          #{reflections.join("\n")}
          #{columns.join("\n")}
        end
      TXT

      path = gen_directory.join("#{model.model_name.singular}.rb")
      File.write(path, generated_attributes)
      puts("written : #{path}")
    end
  end

  def type_translation
    {
      array: 'Array',
      boolean: 'Boolean',
      date: 'Date',
      datetime: 'DateTime',
      decimal: 'Decimal',
      float: 'Float',
      integer: 'Integer',
      string: 'String',
      text: 'String',
      time: 'Time'
    }
  end

  def class_for(name)
    name = name.to_s
    found = ApplicationRecord.descendants.detect do |model|
      model.model_name.plural == name || model.model_name.singular == name
    end
    found&.first&.model_name&.name
  end

  def reflection_type(reflection)
    puts "Reflecting with #{reflection}"
    case reflection
    when ActiveRecord::Reflection::HasManyReflection
      :many
    when ActiveRecord::Reflection::HasAndBelongsToManyReflection
      :many
    when ActiveRecord::Reflection::HasOneReflection
      :one
    when ActiveRecord::Reflection::BelongsToReflection
      :one
    when ActiveRecord::Reflection::ThroughReflection
      reflection_type(reflection.through_reflection)
    else
      puts("# cannot infer association for #{reflection.name} -> #{reflection.class}")
      nil
    end
  end

  def reflection_class_name(reflection)
    case reflection
    when ActiveRecord::Reflection::HasManyReflection
      class_name =
        reflection.options[:class_name].presence || class_for(reflection.name)
      class_name
    when ActiveRecord::Reflection::ThroughReflection
      class_name =
        reflection.options[:class_name].presence || class_for(reflection.name)
      class_name
    when ActiveRecord::Reflection::HasAndBelongsToManyReflection
      class_name =
        reflection.options[:class_name].presence || class_for(reflection.name)
      class_name
    when ActiveRecord::Reflection::HasOneReflection
      reflection.name.to_s.capitalize
    when ActiveRecord::Reflection::BelongsToReflection
      reflection.name.to_s.capitalize
    else
      puts("# cannot infer association for #{reflection.name} -> #{reflection.class}")
      nil
    end
  end

  def reflection_comment(reflection)
    case reflection_type(reflection)
    when :one
      "[#{reflection_class_name(reflection)}]"
    when :many
      "[Array<#{reflection_class_name(reflection)}>]"
    end
  end
end

def ruby_type
  {
    array: 'Array',
    boolean: 'Boolean',
    date: 'Date',
    datetime: 'DateTime',
    decimal: 'Decimal',
    float: 'Float',
    integer: 'Integer',
    string: 'String',
    text: 'String',
    time: 'Time'
  }
end

@yedhink Where do I put the file? In the root and what do you mean by this,

_"Make sure you customise the paths appropriately to suit your project, within the script"_

I have placed the script in lib/generate_solar_models.rb and I have not modified the script above
Screenshot 2020-10-25 at 12 52 49

Running the command gives bundle exec rails r lib/generate_solar_models.rb
Screenshot 2020-10-25 at 12 50 17

Gives this result,
Screenshot 2020-10-25 at 12 55 01

@yedhink The question now is have I missed some?

You forgot to add

   require 'rake'

at the top of the file

@RobertLowe I can confirm that intellisense works pretty good with v0.38.6 as you suggested. Thanks again. Until a further notice from the developer about the issue, I will stick with this version.

@guledali just make it a rake task and run bundle exec rake solargraph:update_model_definitions

Put in the lib/tasks/generate_solar_models.rake adding .rake at the end and the running the

bundle exec rake solargraph:update_model_definitions

@yedhink you're welcome @guledali yes, make it rake task just like that

cheers all

Hi, I still can't up and run completion for AR attributes, i run the above script and i have this structure.
before:
Screenshot_20201110_114112
after:
Screenshot_20201110_114116

The problem is that you have to configure the rails.rb

# The following comments fill some of the gaps in Solargraph's understanding of
# Rails apps. Since they're all in YARD, they get mapped in Solargraph but
# ignored at runtime.
#
# You can put this file anywhere in the project, as long as it gets included in
# the workspace maps. It's recommended that you keep it in a standalone file
# instead of pasting it into an existing one.
#
# @!parse
#   class ActionController::Base
#     include ActionController::MimeResponds
#     extend ActiveSupport::Callbacks::ClassMethods
#     extend AbstractController::Callbacks::ClassMethods
#   end
#   class ActiveRecord::Base
#     extend ActiveRecord::QueryMethods
#     extend ActiveRecord::FinderMethods
#     extend ActiveRecord::Associations::ClassMethods
#     extend ActiveRecord::Inheritance::ClassMethods
#     include ActiveRecord::Persistence
#   end
# @!override ActiveRecord::FinderMethods#find
#   @overload find(id)
#     @param id [Integer]
#     @return [self]
#   @overload find(list)
#     @param list [Array]
#     @return [Array<self>]
#   @overload find(*args)
#     @return [Array<self>]
#   @return [self, Array<self>]

This does not cover rails at all, so many autocompletion missing both in the controller and model, obviously you could extend that file but who has the time for that. Alternative there is free version for rubymine https://www.jetbrains.com/ruby/nextversion/

@amirhosseinak20 looks like you are expecting your editor to give you completion about AR attributes on the class. They are instance level attributes, so you need to try completion on an instance. What happens if you type User.new.? Do you see the attributes then?

@amirhosseinak20 looks like you are expecting your editor to give you completion about AR attributes on the class. They are instance level attributes, so you need to try completion on an instance. What happens if you type User.new.? Do you see the attributes then?

When i type sth like "User.fi" it doesn't show any completion (i expect to show first), but when i type "a = User.new; a.em" it shows email.

Help is ~on the way~ in progress. I've started https://github.com/iftheshoefritz/solargraph_rails which is a SG plugin that parses Annotate comments to give magical IDE help on ActiveRecord attributes. It does this without generating any local files that confuse go-to-definition. Associations will come later, but those are IMO an easier problem to solve.

It relies on an unreleased feature of Solargraph (Conventions), but if you're willing to build things from source you can use it now. I've tested it on a Rails API that is a few years old and it does what I need. The API is far from the biggest, dirtiest Rails app that I work on, so there are probably lots more issues to find, and plenty of refactoring and performance stuff to think about.

(shoutout to @castwide for implementing Conventions in master, do we have any timelines on when v.0.40 will be released?)

Help is ~on the way~ in progress. I've started [iftheshoefritz/solargraph_rails](https://github.com

on here be dragons where does one find solargraph 40.1 ? reading shoutout, want to forgo unnecessary yak shaving.
Suppose I can push version to 40.1 by hand. Not sure if that what you have done.

on here be dragons where does one find solargraph 40.1 ? reading shoutout, want to forgo unnecessary yak shaving.

You have to build solargraph from source, and set the version number to that (which I chose arbitrarily, Castwide actually said the next version would be v0.40.0).

on here be dragons where does one find solargraph 40.1 ? reading shoutout, want to forgo unnecessary yak shaving.

You have to build solargraph from source, and set the version number to that (which I chose arbitrarily, Castwide actually said the next version would be v0.40.0).

Also probably better find a different name, there is already solargraph-rails, which I have installed instead of this one on the first go.

Also probably better find a different name, there is already solargraph-rails

馃う and I see it is owned by Castwide himself

@iftheshoefritz The current solargraph-rails gem is a legacy Rails app that I've been meaning to deprecate. I'm on board with publishing your plugin under that name to stay consistent with existing plugin conventions.

(shoutout to @castwide for implementing Conventions in master, do we have any timelines on when v.0.40 will be released?)

I delayed it while I was researching a wart in how convention changes get applied to api maps. Then I got temporarily sidetracked with other work. 馃う I'll try to have an update and an ETA before the end of the week.

@castwide Thanks! Is the convention solargraph-rails or solargraph_rails (minus or underscore)?

@iftheshoefritz dash imo

Yep, solargraph-rails. Current examples include solargraph-reek and solargraph-standardrb.

With the release of gem v0.40.0, I think we're about ready to develop a proper Rails plugin for Solargraph. My proposal is to combine the Rails supplemental file with iftheshoefritz's model annotation. This would take a lot of the maintenance out of users' hands while still allowing them to apply their own supplemental file if necessary.

@iftheshoefritz, any thoughts on this? As I said earlier, I'd be happy to yank the legacy solargraph-rails gem so we can repurpose the name. That just leaves the question of how to coordinate collaboration and maintenance.

@castwide that sounds good! If you could remove solargraph-rails, I'll rename my project and upload version 0.1.1pre or some such to rubygems.org

@iftheshoefritz is your RubyGems username also iftheshoefritz? I figure the safest way to switch is for me to make you an owner, so it doesn't get squatted mid-transfer. You can also email me so we can coordinate more directly (my email is in my profile).

@castwide yes, I am iftheshoefritz there too :)

Was this page helpful?
0 / 5 - 0 ratings