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

Implement no-route-action rule #2030

Merged
merged 9 commits into from
Aug 11, 2021

Conversation

thiagofesta
Copy link
Contributor

@thiagofesta thiagofesta commented Jul 20, 2021

no-route-action

This rule disallows the usage of route-action.

ember-route-action-helper was a popular addon used to add actions to a route without creating a separate controller. Given the changes in Ember since ember-route-action-helper was a widely used pattern, controllers are now encouraged and we want to discourage the use of route-action.

Most route actions should either be sent to the controller first or encapsulated within a downstream component instead. We should never be escaping the DDAU hierarchy to lob actions up to the route.

Examples

This rule forbids the following:

<CustomComponent @onUpdate={{route-action 'updateFoo'}} />
<CustomComponent @onUpdate={{route-action 'updateFoo' 'bar'}} />
{{custom-component onUpdate=(route-action 'updateFoo')}}
{{custom-component onUpdate=(route-action 'updateFoo' 'bar')}}

With the given route:

// app/routes/foo.js
export default class extends Route {
  @action
  updateFoo(baz) {
    // ...
  }
}

This rule allows the following:

<CustomComponent @onUpdate={{this.updateFoo}} />
<CustomComponent @onUpdate={{fn this.updateFoo 'bar'}} />
{{custom-component onUpdate=this.updateFoo}}
{{custom-component onUpdate=(fn this.updateFoo 'bar')}}

With the given controller:

// app/controllers/foo.js
export default class extends Controller {
  @action
  updateFoo(baz) {
    // ...
  }
}

Migration

The example below shows how to migrate from route-action to controller actions.

Before

// app/routes/posts.js
export default class extends Route {
  model(params) {
    return this.store.query('post', { page: params.page })
  }

  @action
  goToPage(pageNum) {
    this.transitionTo({ queryParams: { page: pageNum } });
  }
}
// app/controllers/posts.js
export default class extends Controller {
  queryParams = ['page'];
  page = 1;
}
{{#each @model as |post|}}
  <Post @title={{post.title}} @content={{post.content}} />
{{/each}}

<button {{action (route-action 'goToPage' 1)}}>1</button>
<button {{action (route-action 'goToPage' 2)}}>2</button>
<button {{action (route-action 'goToPage' 3)}}>3</button>

After

// app/routes/posts.js
export default class extends Route {
  model(params) {
    return this.store.query('post', { page: params.page })
  }
}
// app/controllers/posts.js
export default class extends Controller {
  queryParams = ['page'];
  page = 1;

  @action
  goToPage(pageNum) {
    this.transitionToRoute({ queryParams: { page: pageNum } });
  }
}
{{#each @model as |post|}}
  <Post @title={{post.title}} @content={{post.content}} />
{{/each}}

<button {{on 'click' (fn this.goToPage 1)}}>1</button>
<button {{on 'click' (fn this.goToPage 2)}}>2</button>
<button {{on 'click' (fn this.goToPage 3)}}>3</button>

References

@thiagofesta thiagofesta marked this pull request as ready for review July 20, 2021 19:54
@elwayman02
Copy link
Contributor

I think this is a fantastic rule because, despite still being on Ember 2.14, having no updates in the last 2 years, and having had a warning in its README telling people not to use it for the last 4 years, ember-route-action-helper is still in the top 10% of most downloaded addons: https://emberobserver.com/addons/ember-route-action-helper

It's clear that this is a common problem that would help the community by adding an optional lint rule, and rules like no-mut-helper (which suggests ember-set-helper as replacement/correct code) have already established that it's reasonable to have context of open-source addons within some of the optional lint rules provided by this package.

Copy link
Collaborator

@bertdeblock bertdeblock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about trying to contact the maintainers and see if the addon can officially be deprecated?

docs/rule/no-route-action.md Outdated Show resolved Hide resolved
docs/rule/no-route-action.md Outdated Show resolved Hide resolved
@elwayman02
Copy link
Contributor

@bertdeblock I filed this ticket to see if the maintainers are willing to take action on that suggestion: DockYard/ember-route-action-helper#109

@thiagofesta
Copy link
Contributor Author

@bertdeblock great suggestion, thanks @elwayman02 for sending the request out!

docs/rule/no-route-action.md Outdated Show resolved Hide resolved
docs/rule/no-route-action.md Show resolved Hide resolved
@elwayman02
Copy link
Contributor

@scalvert @bmish @rwjblue are any of you able to take a look at this PR? We'd love to get this merged soon for some ongoing projects.

Copy link
Member

@scalvert scalvert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good overall. I do think it a bit odd to use function.bind rather than methods of the class in the rules, and using a bespoke string replacement mechanism for the error message, but I realize you're just following the pattern in no-action, so I wouldn't suggest changing it now.

Thanks for adding this!

@scalvert
Copy link
Member

It's possible there's more test cases we could/should add, but I'm comfortable merging this for now with an eye to expanding those cases as they arise.

@scalvert scalvert merged commit 42985d5 into ember-template-lint:master Aug 11, 2021
@bertdeblock
Copy link
Collaborator

The addon doesn't contain a route-action modifier, yet this rule checks for it. Any reason?

@thiagofesta
Copy link
Contributor Author

The addon doesn't contain a route-action modifier, yet this rule checks for it. Any reason?

No reason, that is a mistake. As @scalvert mentioned, I based on this from no-action and I didn't notice that route-action doesn't have a modifier, I assumed it had.

I will remove it and put out a PR soon, thanks.

@AmilKey
Copy link

AmilKey commented Dec 17, 2021

@thiagofesta before we called route-actions in child routes, and the action was declared at the top route level, for example:

route1 -> route2 -> route3 (call route-action "route1")
      \-> route4 -> route5 (call route-action "route1")

please tell me what is the best practice in this case 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.

6 participants