[Rails] After upgrade to 7.2.2 / NoMethodError: undefined method `actions' for nil:NilClass / Heroku Review apps

Hi,

Following yesterday’s incident, I updated the gem to 7.2.2.

I use Heroku Review apps to build and release apps from pull requests. I have an associated Release Phase which is a basic script that runs database related operations.

The first command of the script is:

bundle exec rails --trace db:version

But my first release after update fails, and it seems related to forest_liana. Here is the full stack trace:

⏳   [Release Phase]: Retrieving the database schema version.
** Invoke db:version (first_time)
** Invoke db:load_config (first_time)
** Invoke environment (first_time)
** Execute environment
rails aborted!
NoMethodError: undefined method `actions' for nil:NilClass
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:53:in `get_action'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:60:in `block (2 levels) in generate_action_hooks'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:58:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:58:in `block in generate_action_hooks'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:57:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:57:in `generate_action_hooks'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:84:in `generate_apimap'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/bootstrapper.rb:33:in `initialize'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/engine.rb:88:in `new'
/app/vendor/bundle/ruby/2.7.0/gems/forest_liana-7.2.2/lib/forest_liana/engine.rb:88:in `block in <class:Engine>'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/lazy_load_hooks.rb:68:in `block in execute_hook'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/lazy_load_hooks.rb:61:in `with_execution_control'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/lazy_load_hooks.rb:66:in `execute_hook'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/lazy_load_hooks.rb:52:in `block in run_load_hooks'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/lazy_load_hooks.rb:51:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/lazy_load_hooks.rb:51:in `run_load_hooks'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/application/finisher.rb:140:in `block in <module:Finisher>'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/initializable.rb:32:in `instance_exec'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/initializable.rb:32:in `run'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/initializable.rb:61:in `block in run_initializers'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:228:in `block in tsort_each'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:431:in `each_strongly_connected_component_from'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:349:in `block in each_strongly_connected_component'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:347:in `each'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:347:in `call'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:347:in `each_strongly_connected_component'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:226:in `tsort_each'
/app/vendor/ruby-2.7.4/lib/ruby/2.7.0/tsort.rb:205:in `tsort_each'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/initializable.rb:60:in `run_initializers'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/application.rb:391:in `initialize!'
/app/config/environment.rb:7:in `<main>'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
/app/vendor/bundle/ruby/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/kernel.rb:34:in `require'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/dependencies.rb:332:in `block in require'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/dependencies.rb:299:in `load_dependency'
/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/dependencies.rb:332:in `require'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/application.rb:367:in `require_environment!'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/application.rb:533:in `block in run_tasks_blocks'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `block in execute'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `execute'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:243:in `block in invoke_prerequisites'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `invoke_prerequisites'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:243:in `block in invoke_prerequisites'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `invoke_prerequisites'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/task.rb:188:in `invoke'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:160:in `invoke_task'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `block (2 levels) in top_level'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `block in top_level'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:125:in `run_with_threads'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:110:in `top_level'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/commands/rake/rake_command.rb:24:in `block (2 levels) in perform'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:186:in `standard_exception_handling'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/commands/rake/rake_command.rb:24:in `block in perform'
/app/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/rake_module.rb:59:in `with_application'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/commands/rake/rake_command.rb:18:in `perform'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/command.rb:50:in `invoke'
/app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.4.1/lib/rails/commands.rb:18:in `<main>'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
/app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:version => db:load_config => environment

The only ForestAdmin-related change I made was upgrade to 7.2.2, plus I have a very basic usage of the tool.

I suppose that my only option to temporarily fix my production pipeline is to disable my Release Phase.
Anything I can investigate more on my side?

Hi @pil0u,

Do you know which version you were using before the upgrade?

Yes, sorry, I was using version 6.2.3. I decided for a big jump since no breaking changes had impact on my side.

@pil0u,

Could you give the 6.6.3 a shot instead ?
v7 contains breaking changes, especially related to smart action. (See our upgrade note)

6.6.3 only contains the fix from yesterday issue.

Please let me know :pray:

1 Like

@jeffladiray Just downgraded to 6.6.3 on a separate branch, same error.
I do not use SmartActions, so as I said v7 had no breaking changes for me.

I’ll check the changelog between 6.2.3 and 6.6.3 to see if anything could have introduced this.

Do you use smart action or do you have any smart action definition that could give that error on schema generation ?

In the meantime, the monkey patch is still available on the main incident thread, and should hopefully unlock the situation on your end using the 6.2.3

Thanks for the support, appreciate it.

I run the Community Plan, so my usage is, for now, pretty basic. I have one Dashboard (only one allowed) that uses basic available charts, I am not sure if that counts for Smart Actions.

I just downgraded from 6.6.3 to 6.2.3 on my separate branch and the error disappears, so there is indeed some kind of breaking change between those two.

I can narrow it down the breaking version for you and let you know here.

1 Like

I’m currently not able to reproduce, so I guess that would be great.

Smart actions is a custom code & route you have to code in order to perform actions on a set of records in a collection.
In fact, if you are not using it, you should not see this kind of error.

However, I would find weird that we introduced a breaking change between 6.2.3 & 6.6.3, but since you are experiencing an issue, I may be wrong.

Thanks for the support, appreciate it.

6.6.3 was released yesterday after successfully managing to fix the issue on 7.2.2, so any issue and feedback on 6.6.3 are more than welcome :+1:. Thanks you for reporting this :pray:

(Also, if you could provide your project name or project id that would also be great, so I can have a look to check if I can spot any issue on my end)

Smart actions is a custom code & route you have to code in order to perform actions on a set of records in a collection. In fact, if you are not using it, you should not see this kind of error.

I have 0 line of code related to ForestAdmin apart from of the basic initial setup, so no Smart Action on my side.

I tried to change and deploy with all these versions progressively:

7.2.2 - NOK
6.6.3 - NOK
6.2.3 - OK
6.3.8 - OK
6.4.1 - OK
6.5.1 - OK
6.6.0 - OK
6.6.1 - OK
6.6.2 - OK
6.6.3 - OK (???)
7.0.2 - OK
7.1.0 - OK
7.2.1 - OK
7.2.2 - OK (???)

It seems that bumping versions progressively up until the latest version removes the problem. Which is extremely weird. In the branch I am currently testing, I now cannot reproduce the issue.

In the initial branch where I first encountered the issue, I was able to remove the problem following that (faster) path:

7.2.2 > 6.2.3 > 6.5.1 > 7.1.0 > 7.2.2

I have no rational explanation for that behaviour, and I will see what happens when I open a new PR.

How can I find my project ID?

Project name would be enough (The one displayed in your project list).

I have no rational explanation for that behaviour, and I will see what happens when I open a new PR.

Sadly, neither do I. I did a few tests between 6.2.3 & 6.6.3 today, and still so far, I’m not able to reproduce this issue. So … indeed, this looks weird. According to the latest new I got, the issue we had yesterday may also implies to clear the rails cache. But in your case, that does not seems to match.

Let me know if you are able to either reproduce specifically this issue, or if we should consider the topic as closed if you are now able to use your admin panel as expected :slight_smile:

I spent my day on this too 🥲

I prefer to wait for the next fresh PR, see if that happens again. I’ll let you know here.

Yes, yesterday’s fix worked on my side to access my panel :+1:

1 Like

Unfortunately, creating a new PR triggers the same error at first release.
Steps to reproduce:

  1. Have a functional release on Heroku using v7.2.2 of the gem
  2. Create a new branch with some random commit (does not really matter)
  3. Push it. This triggers a Review App build and the associated Release Phase
  4. Build succeeds, release fails on first command: bundle exec rails --trace db:version

Follow-up.

This time, instead of starting back from my original version (6.2.3) and increment gradually, I decremented gradually:

7.2.2 - NOK
7.2.1 - NOK
6.5.1 - NOK
6.4.1 - NOK
6.3.8 - NOK
6.2.3 - OK (!)
7.2.2 - OK

I don’t have an explanation, maybe it has something to do with Heroku’s cache handling for Review Apps. I have no idea. Till next time.

I am going to set version 7.2.1 and manually add the monkey patch, to see what happens for the next PR.

Follow-up.

Sticking with 7.2.1 with the manual monkey patch did not do the trick, I still have a broken release on first attempt when creating an empty PR.

6.3.3

is the problematic version, (associated PR: fix: allow actions hooks in production by GuillaumeCisco · Pull Request #455 · ForestAdmin/forest-rails · GitHub)

I have identified it following that process:

  1. Rollback to 6.2.3, push, deploy (OK)
  2. Create an empty commit and push to trigger an new Release
  3. If this very first Release passes (OK), bump to the next patch version and merge
  4. Repeat step 2. until the very first Release breaks.

Upgrading to 6.3.2 (from my initial 6.2.3) with the manual monkey patch appears to be the only working solution that does not break my Release Phase.

I am afraid I cannot do much more on my side, but my problem seems to come from that version and not from the 2-day old patch.

If that helps, note that in my .forestadmin-schema.json file, the only actions that is not an empty array is in my User model:

{
  "collections": [
    {
      "..."
    }, {
      "name": "User",
      "name_old": "users",
      "icon": null,
      "is_read_only": false,
      "is_searchable": true,
      "is_virtual": false,
      "only_for_relationships": false,
      "pagination_type": "page",
      "fields": [{
        "..."
      }, {
        "..."
      }],
      "segments": [],
      "actions": [{
        "name": "Change password",
        "type": "bulk",
        "base_url": null,
        "endpoint": "forest/actions/change-password",
        "http_method": "POST",
        "redirect": null,
        "download": false,
        "fields": [{
          "field": "New password",
          "type": "String",
          "default_value": null,
          "enums": null,
          "is_required": false,
          "is_read_only": false,
          "reference": null,
          "description": null,
          "position": 0,
          "widget": null
        }],
        "hooks": {
          "load": false,
          "change": []
        }
      }]
    }, {
      "..."
    }
  ],
  "meta": {
    "database_type": "postgresql",
    "liana": "forest-rails",
    "liana_version": "6.3.3",
    "orm_version": "6.1.4.1"
  }
}

@pil0u,

Upgrading to 6.3.2 (from my initial 6.2.3) with the manual monkey patch appears to be the only working solution that does not break my Release Phase.

I know this is far from being the best solution, but happy to see that this is working for you. However, it would be way better to have your backend on the latest 6.x/7.x, so let’s debug your issue.

I am afraid I cannot do much more on my side, but my problem seems to come from that version and not from the 2-day old patch.

Could you share here or as a private message both the definition & the implementation of the smart action change password you seems to have?
The commit/version you mentioned is the v6/v7 version that introduced the hooks feature. It is actually commonly used, but we may have missed something here.
With the smart action definition, I might be able to reproduce.

Thanks for your help here :pray:

Where can I find this definition? Again, I did not code a single line for ForestAdmin actions, it is something that was generated automatically in my .forestadmin-schema.json file.

Again, I did not code a single line for ForestAdmin actions

Well ok, so this is most likely the source of the issue + this is weird since I’m pretty sure we don’t generate smart actions by default.

Usually, smart actions are declared in lib/forest_liana/collections.

Here’s an example I have on a running project

Being able to locate the smart action and commenting it (If possible) may help here. However, I would be more than happy to understand how you could have a smart action declared in your .forestadmin-schema.json without specifically declaring one :thinking:

Thanks in advance

Here is what I see when I click on “Actions” on a User in my panel:
Screenshot from 2021-10-04 10-51-10

I confirm I do not have such code in my project, this is the only ForestLiana related code I have:
Screenshot from 2021-10-04 10-54-38

I tried to delete the declared action in the .forestadmin-schema.json file, like this:

{
  "collections": [
    {
      "..."
    }, {
      "name": "User",
      "name_old": "users",
      "icon": null,
      "is_read_only": false,
      "is_searchable": true,
      "is_virtual": false,
      "only_for_relationships": false,
      "pagination_type": "page",
      "fields": [{
        "..."
      }, {
        "..."
      }],
      "segments": [],
      "actions": []
    }, {
      "..."
    }
  ],
  "meta": {
    "database_type": "postgresql",
    "liana": "forest-rails",
    "liana_version": "6.3.3",
    "orm_version": "6.1.4.1"
  }
}

but it is re-generated as soon as I run rails db:migrate. Here is the detailed trace of the command:

❯ rails db:migrate --trace
** Invoke db:migrate (first_time)
** Invoke db:load_config (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:load_config
** Execute db:migrate
   (0.2ms)  SELECT pg_try_advisory_lock(6955016089055575695)
   (0.4ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
  ActiveRecord::InternalMetadata Load (0.3ms)  SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2  [["key", "environment"], ["LIMIT", 1]]
   (0.3ms)  SELECT pg_advisory_unlock(6955016089055575695)
** Invoke db:_dump (first_time)
** Execute db:_dump
** Invoke db:schema:dump (first_time)
** Invoke db:load_config 
** Invoke environment 
** Execute db:schema:dump

And no reference in your code for change-password or Change password?

I’ve never encountered such case, but if you were to have this action, and since it is bulk, you would have to select records in order to see it in the action dropdown.

I’m very confused about this issue here, but I’m pretty sure this comes down to this mysterious action.

Thanks.

I don’t have any “Actions” button when I select multiple Users.

As for references:
Screenshot from 2021-10-04 11-30-15
Screenshot from 2021-10-04 11-30-44

I am using Devise for authentication, if that helps.