Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore implicit locals if not declared by templates with strict locals #49782

Merged
merged 1 commit into from Oct 25, 2023

Conversation

byroot
Copy link
Member

@byroot byroot commented Oct 25, 2023

Fix: #49780
Fix: #49761

CollectionRenderer implictly inject <name>_counter and <name>_iteration locals, but in the overwhelming majority of cases they aren't used.

So when the rendered template has strict locals we shouldn't require these to be declared, and if they aren't we should simply not pass them.

Co-Authored-By: @HolyWalley

@HolyWalley I hope you don't mind, I directly refactored your PR to save a bit of time. Most of it was good, but I had to change the parameters parsing a bit.

Fix: rails#49780
Fix: rails#49761

`CollectionRenderer` implictly inject `<name>_counter` and `<name>_iteration`
locals, but in the overwhelming majority of cases they aren't used.

So when the rendered template has strict locals we shouldn't require
these to be declared, and if they aren't we should simply not pass them.

Co-Authored-By: HolyWalley <yakau@hey.com>
@rails-bot rails-bot bot added the actionview label Oct 25, 2023
@byroot byroot merged commit aa94960 into rails:main Oct 25, 2023
3 of 4 checks passed
byroot added a commit that referenced this pull request Oct 25, 2023
Ignore implicit locals if not declared by templates with strict locals
@HolyWalley
Copy link
Contributor

yeah, no problem, haven't noticed that we can use existing call to instance_method to extract params instead of parsing them using regexp, nice :)

@longstackup
Copy link

longstackup commented Nov 14, 2023

@byroot so now how can we pass <name>_counter and <name>_counter to partial ?

Follow the line in changelog: Now they are only passed if the template will actually accept them., I try to declare like this in magic comment: <%# locals: (user:, user_counter:) -%> and use user_counter in partial, it raises the error: missing local: :user_counter in template

If magic comment is: <%# locals: (user:) -%> , it raises error: undefined local variable or method user_counter in partial

Tried some other ways with implicit_locals in template but all not work

@byroot
Copy link
Member Author

byroot commented Nov 14, 2023

@longstackup it should work yes.

I try to declare like this in magic comment: <%# locals: (user:, user_counter:) -%> and use user_counter in partial, it raises the error: missing local: :user_counter in template

Were you invoking that template with render collection:?

There is a test that demonstrate it works, so if you are still having issues It would be best to provide reproduction steps (or even better script).

@longstackup
Copy link

longstackup commented Nov 14, 2023

Were you invoking that template with render collection:?

There is a test that demonstrate it works, so if you are still having issues It would be best to provide reproduction steps (or even better script).

@byroot yes I'm invoking that template with render collection.

Steps to reproduce

Create few users inside a company. And in company show view we will show the list of users belongs this company :

<%# app/views/company/show.html.erb %>

<div id="users">
  <%= render partial: "user", collection: @users %>
</div>

Set a strict local in the _post partial:

<%# app/views/company/_user.html.erb %>

<%# locals: (user:) %>

<div id="<%= dom_id user %>">
  <p>
    <strong>No.:</strong>
    <%= user_counter %>
  </p>

  <p>
    <strong>Name:</strong>
    <%= user.name %>
  </p>

</div>

Expected behavior
The show view should render successfully.

Actual behavior
An error is thrown and the view doesn't render.

Completed 500 Internal Server Error in 263ms (ActiveRecord: 101.6ms | Allocations: 125098)

ActionView::Template::Error (undefined local variable or method `user_counter' for #<ActionView::Base:0x00000000109b40>

If I remove magic comment in partial, this error goes away

@byroot
Copy link
Member Author

byroot commented Nov 14, 2023

<%# locals: (user:) %>

That's your bug, you must declare that argument:

<%# locals: (user:, user_counter:) %>

or

<%# locals: (user:, user_counter: nil) %>

@longstackup
Copy link

I tried

<%# locals: (user:, user_counter:) %>

the error become: ActionView::Template::Error (missing local: :user_counter): in template.
If I declare default nil value for user counter like your 2nd suggestion, show view render with blank user counter

Also if it raises, it means you are not using the latest Rails 7.1.2

I updated to Rails 7.1.2. This is my Gemfile.lock

Gemfile.lock
GEM
  remote: https://rubygems.org/
  specs:
    actioncable (7.1.2)
      actionpack (= 7.1.2)
      activesupport (= 7.1.2)
      nio4r (~> 2.0)
      websocket-driver (>= 0.6.1)
      zeitwerk (~> 2.6)
    actionmailbox (7.1.2)
      actionpack (= 7.1.2)
      activejob (= 7.1.2)
      activerecord (= 7.1.2)
      activestorage (= 7.1.2)
      activesupport (= 7.1.2)
      mail (>= 2.7.1)
      net-imap
      net-pop
      net-smtp
    actionmailer (7.1.2)
      actionpack (= 7.1.2)
      actionview (= 7.1.2)
      activejob (= 7.1.2)
      activesupport (= 7.1.2)
      mail (~> 2.5, >= 2.5.4)
      net-imap
      net-pop
      net-smtp
      rails-dom-testing (~> 2.2)
    actionpack (7.1.2)
      actionview (= 7.1.2)
      activesupport (= 7.1.2)
      nokogiri (>= 1.8.5)
      racc
      rack (>= 2.2.4)
      rack-session (>= 1.0.1)
      rack-test (>= 0.6.3)
      rails-dom-testing (~> 2.2)
      rails-html-sanitizer (~> 1.6)
    actiontext (7.1.2)
      actionpack (= 7.1.2)
      activerecord (= 7.1.2)
      activestorage (= 7.1.2)
      activesupport (= 7.1.2)
      globalid (>= 0.6.0)
      nokogiri (>= 1.8.5)
    actionview (7.1.2)
      activesupport (= 7.1.2)
      builder (~> 3.1)
      erubi (~> 1.11)
      rails-dom-testing (~> 2.2)
      rails-html-sanitizer (~> 1.6)
    active_storage_validations (1.0.4)
      activejob (>= 5.2.0)
      activemodel (>= 5.2.0)
      activestorage (>= 5.2.0)
      activesupport (>= 5.2.0)
    activejob (7.1.2)
      activesupport (= 7.1.2)
      globalid (>= 0.3.6)
    activemodel (7.1.2)
      activesupport (= 7.1.2)
    activerecord (7.1.2)
      activemodel (= 7.1.2)
      activesupport (= 7.1.2)
      timeout (>= 0.4.0)
    activerecord-cte (0.3.0)
      activerecord
    activestorage (7.1.2)
      actionpack (= 7.1.2)
      activejob (= 7.1.2)
      activerecord (= 7.1.2)
      activesupport (= 7.1.2)
      marcel (~> 1.0)
    activesupport (7.1.2)
      base64
      bigdecimal
      concurrent-ruby (~> 1.0, >= 1.0.2)
      connection_pool (>= 2.2.5)
      drb
      i18n (>= 1.6, < 2)
      minitest (>= 5.1)
      mutex_m
      tzinfo (~> 2.0)
    addressable (2.8.5)
      public_suffix (>= 2.0.2, < 6.0)
    aes_key_wrap (1.1.0)
    after_commit_everywhere (1.3.1)
      activerecord (>= 4.2)
      activesupport
    anyway_config (2.5.4)
      ruby-next-core (>= 0.14.0)
    ast (2.4.2)
    attr_required (1.0.1)
    aws-eventstream (1.2.0)
    aws-partitions (1.843.0)
    aws-sdk-core (3.185.1)
      aws-eventstream (~> 1, >= 1.0.2)
      aws-partitions (~> 1, >= 1.651.0)
      aws-sigv4 (~> 1.5)
      jmespath (~> 1, >= 1.6.1)
    aws-sdk-kms (1.72.0)
      aws-sdk-core (~> 3, >= 3.184.0)
      aws-sigv4 (~> 1.1)
    aws-sdk-s3 (1.136.0)
      aws-sdk-core (~> 3, >= 3.181.0)
      aws-sdk-kms (~> 1)
      aws-sigv4 (~> 1.6)
    aws-sigv4 (1.6.1)
      aws-eventstream (~> 1, >= 1.0.2)
    base64 (0.2.0)
    bcrypt (3.1.19)
    bigdecimal (3.1.4)
    bindata (2.4.15)
    bindex (0.8.1)
    bootsnap (1.17.0)
      msgpack (~> 1.2)
    brakeman (6.0.1)
    builder (3.2.4)
    bundle-audit (0.1.0)
      bundler-audit
    bundler-audit (0.9.1)
      bundler (>= 1.2.0, < 3)
      thor (~> 1.0)
    capybara (3.39.2)
      addressable
      matrix
      mini_mime (>= 0.1.3)
      nokogiri (~> 1.8)
      rack (>= 1.6.0)
      rack-test (>= 0.6.3)
      regexp_parser (>= 1.5, < 3.0)
      xpath (~> 3.2)
    concurrent-ruby (1.2.2)
    connection_pool (2.4.1)
    crass (1.0.6)
    date (3.3.4)
    debug (1.8.0)
      irb (>= 1.5.0)
      reline (>= 0.3.1)
    diff-lcs (1.5.0)
    docile (1.4.0)
    dotenv (2.8.1)
    dotenv-rails (2.8.1)
      dotenv (= 2.8.1)
      railties (>= 3.2)
    drb (2.2.0)
      ruby2_keywords
    dry-configurable (1.1.0)
      dry-core (~> 1.0, < 2)
      zeitwerk (~> 2.6)
    dry-core (1.0.1)
      concurrent-ruby (~> 1.0)
      zeitwerk (~> 2.6)
    dry-initializer (3.1.1)
    erubi (1.12.0)
    et-orbi (1.2.7)
      tzinfo
    factory_bot (6.2.1)
      activesupport (>= 5.0.0)
    factory_bot_rails (6.2.0)
      factory_bot (~> 6.2.0)
      railties (>= 5.0.0)
    faker (3.2.1)
      i18n (>= 1.8.11, < 2)
    faraday (2.7.11)
      base64
      faraday-net_http (>= 2.0, < 3.1)
      ruby2_keywords (>= 0.0.4)
    faraday-follow_redirects (0.3.0)
      faraday (>= 1, < 3)
    faraday-net_http (3.0.2)
    ffi (1.16.3)
    fugit (1.9.0)
      et-orbi (~> 1, >= 1.2.7)
      raabro (~> 1.4)
    globalid (1.2.1)
      activesupport (>= 6.1)
    good_job (3.20.0)
      activejob (>= 6.0.0)
      activerecord (>= 6.0.0)
      concurrent-ruby (>= 1.0.2)
      fugit (>= 1.1)
      railties (>= 6.0.0)
      thor (>= 0.14.1)
    google-protobuf (3.24.4-arm64-darwin)
    google-protobuf (3.24.4-x86_64-linux)
    hashie (5.0.0)
    honeybadger (5.3.0)
    i18n (1.14.1)
      concurrent-ruby (~> 1.0)
    image_processing (1.12.2)
      mini_magick (>= 4.9.5, < 5)
      ruby-vips (>= 2.0.17, < 3)
    importmap-rails (1.2.3)
      actionpack (>= 6.0.0)
      activesupport (>= 6.0.0)
      railties (>= 6.0.0)
    io-console (0.6.0)
    irb (1.9.0)
      rdoc
      reline (>= 0.3.8)
    isolator (0.11.0)
      sniffer (>= 0.5.0)
    jbuilder (2.11.5)
      actionview (>= 5.0.0)
      activesupport (>= 5.0.0)
    jmespath (1.6.2)
    job-iteration (1.4.1)
      activejob (>= 5.2)
    json (2.6.3)
    json-jwt (1.16.3)
      activesupport (>= 4.2)
      aes_key_wrap
      bindata
      faraday (~> 2.0)
      faraday-follow_redirects
    jwt (2.7.1)
    language_server-protocol (3.17.0.3)
    lograge (0.14.0)
      actionpack (>= 4)
      activesupport (>= 4)
      railties (>= 4)
      request_store (~> 1.0)
    lograge-sql (2.3.0)
      activerecord (>= 5, < 7.2)
      lograge (~> 0.11)
    logstop (0.3.1)
    loofah (2.21.4)
      crass (~> 1.0.2)
      nokogiri (>= 1.12.0)
    mail (2.8.1)
      mini_mime (>= 0.1.1)
      net-imap
      net-pop
      net-smtp
    maintenance_tasks (2.3.3)
      actionpack (>= 6.0)
      activejob (>= 6.0)
      activerecord (>= 6.0)
      job-iteration (>= 1.3.6)
      railties (>= 6.0)
    marcel (1.0.2)
    matrix (0.4.2)
    mini_magick (4.12.0)
    mini_mime (1.1.5)
    minitest (5.20.0)
    msgpack (1.7.2)
    mutex_m (0.2.0)
    net-imap (0.4.4)
      date
      net-protocol
    net-pop (0.1.2)
      net-protocol
    net-protocol (0.2.2)
      timeout
    net-smtp (0.4.0)
      net-protocol
    nio4r (2.5.9)
    nokogiri (1.15.4-arm64-darwin)
      racc (~> 1.4)
    nokogiri (1.15.4-x86_64-linux)
      racc (~> 1.4)
    omniauth (2.1.1)
      hashie (>= 3.4.6)
      rack (>= 2.2.3)
      rack-protection
    omniauth_openid_connect (0.7.1)
      omniauth (>= 1.9, < 3)
      openid_connect (~> 2.2)
    openid_connect (2.2.0)
      activemodel
      attr_required (>= 1.0.0)
      faraday (~> 2.0)
      faraday-follow_redirects
      json-jwt (>= 1.16)
      net-smtp
      rack-oauth2 (~> 2.2)
      swd (~> 2.0)
      tzinfo
      validate_email
      validate_url
      webfinger (~> 2.0)
    parallel (1.23.0)
    parser (3.2.2.4)
      ast (~> 2.4.1)
      racc
    pg (1.3.5)
    pg_query (4.2.3)
      google-protobuf (>= 3.22.3)
    prosopite (1.4.1)
    psych (5.1.1.1)
      stringio
    public_suffix (5.0.3)
    puma (6.4.0)
      nio4r (~> 2.0)
    pundit (2.3.1)
      activesupport (>= 3.0.0)
    pundit-matchers (1.8.4)
      rspec-rails (>= 3.0.0)
    raabro (1.4.0)
    racc (1.7.3)
    rack (3.0.8)
    rack-oauth2 (2.2.0)
      activesupport
      attr_required
      faraday (~> 2.0)
      faraday-follow_redirects
      json-jwt (>= 1.11.0)
      rack (>= 2.1.0)
    rack-protection (3.0.6)
      rack
    rack-session (2.0.0)
      rack (>= 3.0.0)
    rack-test (2.1.0)
      rack (>= 1.3)
    rackup (2.1.0)
      rack (>= 3)
      webrick (~> 1.8)
    rails (7.1.2)
      actioncable (= 7.1.2)
      actionmailbox (= 7.1.2)
      actionmailer (= 7.1.2)
      actionpack (= 7.1.2)
      actiontext (= 7.1.2)
      actionview (= 7.1.2)
      activejob (= 7.1.2)
      activemodel (= 7.1.2)
      activerecord (= 7.1.2)
      activestorage (= 7.1.2)
      activesupport (= 7.1.2)
      bundler (>= 1.15.0)
      railties (= 7.1.2)
    rails-controller-testing (1.0.5)
      actionpack (>= 5.0.1.rc1)
      actionview (>= 5.0.1.rc1)
      activesupport (>= 5.0.1.rc1)
    rails-dom-testing (2.2.0)
      activesupport (>= 5.0.0)
      minitest
      nokogiri (>= 1.6)
    rails-html-sanitizer (1.6.0)
      loofah (~> 2.21)
      nokogiri (~> 1.14)
    railties (7.1.2)
      actionpack (= 7.1.2)
      activesupport (= 7.1.2)
      irb
      rackup (>= 1.0.0)
      rake (>= 12.2)
      thor (~> 1.0, >= 1.2.2)
      zeitwerk (~> 2.6)
    rainbow (3.1.1)
    rake (13.1.0)
    rdoc (6.6.0)
      psych (>= 4.0.0)
    recaptcha (5.16.0)
    redcarpet (3.6.0)
    redis (4.8.1)
    regexp_parser (2.8.2)
    reline (0.4.0)
      io-console (~> 0.5)
    request_store (1.5.1)
      rack (>= 1.4)
    requestjs-rails (0.0.10)
      rails (>= 6.0.0)
    rexml (3.2.6)
    roda (3.73.0)
      rack
    rodauth (2.32.0)
      roda (>= 2.6.0)
      sequel (>= 4)
    rodauth-i18n (0.7.1)
      i18n (~> 1.0)
      rodauth (~> 2.19)
    rodauth-model (0.2.1)
      rodauth (~> 2.0)
    rodauth-omniauth (0.3.3)
      omniauth (~> 2.0)
      rodauth (~> 2.13)
    rodauth-rails (1.12.0)
      bcrypt
      railties (>= 5.0, < 8)
      roda (~> 3.73)
      rodauth (~> 2.30)
      rodauth-model (~> 0.2)
      sequel-activerecord_connection (~> 1.1)
      tilt
    rspec-core (3.12.2)
      rspec-support (~> 3.12.0)
    rspec-expectations (3.12.3)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.12.0)
    rspec-mocks (3.12.6)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.12.0)
    rspec-rails (6.0.3)
      actionpack (>= 6.1)
      activesupport (>= 6.1)
      railties (>= 6.1)
      rspec-core (~> 3.12)
      rspec-expectations (~> 3.12)
      rspec-mocks (~> 3.12)
      rspec-support (~> 3.12)
    rspec-support (3.12.1)
    rubocop (1.57.2)
      json (~> 2.3)
      language_server-protocol (>= 3.17.0)
      parallel (~> 1.10)
      parser (>= 3.2.2.4)
      rainbow (>= 2.2.2, < 4.0)
      regexp_parser (>= 1.8, < 3.0)
      rexml (>= 3.2.5, < 4.0)
      rubocop-ast (>= 1.28.1, < 2.0)
      ruby-progressbar (~> 1.7)
      unicode-display_width (>= 2.4.0, < 3.0)
    rubocop-ast (1.30.0)
      parser (>= 3.2.1.0)
    ruby-next-core (0.15.3)
    ruby-progressbar (1.13.0)
    ruby-vips (2.2.0)
      ffi (~> 1.12)
    ruby2_keywords (0.0.5)
    rubyzip (2.3.2)
    selenium-webdriver (4.15.0)
      rexml (~> 3.2, >= 3.2.5)
      rubyzip (>= 1.2.2, < 3.0)
      websocket (~> 1.0)
    sequel (5.73.0)
      bigdecimal
    sequel-activerecord_connection (1.3.1)
      activerecord (>= 4.2, < 8)
      after_commit_everywhere (~> 1.1)
      sequel (~> 5.38)
    shoulda-matchers (5.3.0)
      activesupport (>= 5.2.0)
    simple_form (5.3.0)
      actionpack (>= 5.2)
      activemodel (>= 5.2)
    simplecov (0.22.0)
      docile (~> 1.1)
      simplecov-html (~> 0.11)
      simplecov_json_formatter (~> 0.1)
    simplecov-html (0.12.3)
    simplecov_json_formatter (0.1.4)
    sniffer (0.5.0)
      anyway_config (>= 1.0)
      dry-initializer (~> 3)
    sprockets (4.2.1)
      concurrent-ruby (~> 1.0)
      rack (>= 2.2.4, < 4)
    sprockets-rails (3.4.2)
      actionpack (>= 5.2)
      activesupport (>= 5.2)
      sprockets (>= 3.0.0)
    stimulus-rails (1.3.0)
      railties (>= 6.0.0)
    stringex (2.8.6)
    stringio (3.0.9)
    strong_migrations (1.6.4)
      activerecord (>= 5.2)
    swd (2.0.2)
      activesupport (>= 3)
      attr_required (>= 0.0.5)
      faraday (~> 2.0)
      faraday-follow_redirects
    tailwindcss-rails (2.0.32-arm64-darwin)
      railties (>= 6.0.0)
    tailwindcss-rails (2.0.32-x86_64-linux)
      railties (>= 6.0.0)
    telephone_number (1.4.20)
    thor (1.3.0)
    tilt (2.3.0)
    timeout (0.4.1)
    turbo-rails (1.5.0)
      actionpack (>= 6.0.0)
      activejob (>= 6.0.0)
      railties (>= 6.0.0)
    twilio-ruby (6.8.0)
      faraday (>= 0.9, < 3.0)
      jwt (>= 1.5, < 3.0)
      nokogiri (>= 1.6, < 2.0)
    tzinfo (2.0.6)
      concurrent-ruby (~> 1.0)
    unicode-display_width (2.5.0)
    validate_email (0.1.6)
      activemodel (>= 3.0)
      mail (>= 2.2.5)
    validate_url (1.0.15)
      activemodel (>= 3.0.0)
      public_suffix
    validates_email_format_of (1.7.2)
      i18n
    web-console (4.2.1)
      actionview (>= 6.0.0)
      activemodel (>= 6.0.0)
      bindex (>= 0.4.0)
      railties (>= 6.0.0)
    webfinger (2.1.2)
      activesupport
      faraday (~> 2.0)
      faraday-follow_redirects
    webrick (1.8.1)
    websocket (1.2.10)
    websocket-driver (0.7.6)
      websocket-extensions (>= 0.1.0)
    websocket-extensions (0.1.5)
    xpath (3.2.0)
      nokogiri (~> 1.8)
    zeitwerk (2.6.12)

PLATFORMS
  arm64-darwin-21
  x86_64-linux

DEPENDENCIES
  active_storage_validations
  aws-sdk-s3
  bootsnap
  brakeman
  bundle-audit
  capybara
  debug
  dotenv-rails
  factory_bot_rails
  faker
  good_job
  honeybadger
  image_processing (~> 1.2)
  importmap-rails
  isolator
  jbuilder
  lograge
  lograge-sql
  logstop
  maintenance_tasks
  nokogiri (>= 1.14.3)
  pg (~> 1.3.1)
  pg_query
  prosopite
  puma (~> 6.3)
  pundit
  pundit-matchers (~> 1.8.4)
  rails (~> 7.1.1)
  rails-controller-testing
  recaptcha
  redcarpet
  redis (~> 4.0)
  requestjs-rails
  rodauth-i18n (~> 0.3)
  rodauth-omniauth (~> 0.3.3)
  rodauth-rails (~> 1.3)
  rspec-rails (~> 6.0)
  rubocop
  selenium-webdriver
  shoulda-matchers (~> 5.0)
  simple_form
  simplecov
  simplecov_json_formatter
  sprockets-rails
  stackup_bridge (= 0.1.68)!
  stackup_rebac (= 0.2.3)!
  stimulus-rails
  stringex
  strong_migrations (~> 1.6)
  tailwindcss-rails (~> 2.0)
  telephone_number
  turbo-rails
  twilio-ruby
  tzinfo-data
  validates_email_format_of
  web-console

RUBY VERSION
   ruby 3.1.1p18

BUNDLED WITH
   2.4.17

@byroot
Copy link
Member Author

byroot commented Nov 14, 2023

Ok, I found the bug, I'll prepare another fix. I need to figure out how our test didn't catch that one though.

casperisfine pushed a commit to Shopify/rails that referenced this pull request Nov 14, 2023
Fix: rails#49782

There was a bug in how we computed the list of required keys which
wasn't caught by the test.
casperisfine pushed a commit to Shopify/rails that referenced this pull request Nov 14, 2023
Fix: rails#49782

There was a bug in how we computed the list of required keys which
wasn't caught by the test.
@longstackup
Copy link

yep. Thank you.

@byroot
Copy link
Member Author

byroot commented Nov 14, 2023

Ok, merged and backported. 7-1-stable should work for you now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Strict locals cause an error when implicitly rendering a collection
3 participants