-
Notifications
You must be signed in to change notification settings - Fork 50
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
Deprecate old API #79
Conversation
@sukima I need your eyes on this 🙏 |
README.md
Outdated
<img src="https://badge.fury.io/js/ember-can.svg"/> | ||
</a> | ||
|
||
<a href="https://travis-ci.org/minutebase/ember-can" title="Ember Observer"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Exelord I really like the plan you outlined. 👍 However, I still think that providing a computed macro has a lot of value. Basically instead of doing: can: service(), // inject can service
postAbility: computed('post', function() {
return this.get('can').abilityFor('post', this.get('post'));
}) you could do postAbility: ability('post', 'post') Computed macros are pretty common in ember and many addons provide collections of them, as you may know. We could import the macro using import { ability } from 'ember-can'; but I saw in the original issue that you're concerned about accidentally importing the computed macro instead of the We could change the import path or the export name: import { ability } from 'ember-can/macros';
// or
import { abilityMacro } from 'ember-can';
// other options
import { can } from 'ember-can';
import { a } from 'ember-can'; I think they are inferior to the first one because I personally don't think the accidental import is a big problem. |
Will look more at this tomorrow. But so far I am liking the plan. |
I'd agree with @miguelcobain that it'd be nice to keep a computed macro around, makes the API nice and legible ... |
In my opinion using: postAbility: computed('post', function() {
return this.get('can').abilityFor('post', this.get('post'));
}) is much more explicit and more readable way, especialy that it's easily customizable in case when we want to pass custom properties: The use case of this method should be very rare, anyway. But OK :) If you like it so much, let's have it for now and discuss it later on- when the time will come. import { ability } from 'ember-can/computed'; to stay consistent with Ember computed imports eg: import { reads } from '@ember/object/computed'; What do you think guys? |
import { ability } from 'ember-can/computed'; LGTM! And yes the explicit argument is well made and I think it is important that users can always use that option. As for the macro I say keep it in the API; we can always deprecate it later. |
Can someone do the last check here? :) |
README.md
Outdated
|
||
user: computed('session.currentUser', function() { | ||
return this.get('session.currentUser'); | ||
}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to show best practices these should be:
user: reads('session.currentUser'),
canCreate: reads('user.isAdmin')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should even make it read-only:
user: reads('session.currentUser').readOnly(),
canCreate: reads('user.isAdmin').readOnly()
But my purpose here was to explain the use case for everyone even for the beginners which may be not so familiar how the macros work exactly. Of course, the advanced developers will know how to improve it ;)
What do u think? Is it a good point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why readOnly? What nefarious reason do we need to prevent a developer from setting a user?
If we attempt to test this and want to change the property of canCreate
we cannot instead we would have to go into the source see that it is a read only property from user and attempt to set user oh but we can't because that too is read only so now we have to mock out session and set its currentUser with an isAdmin property all so we can manipulate canCreate. I fail to see the benifit for telling the world never ever ever try to set this property to something you really think it should be
The only use cases I've found for read only is in cases where the integrity of the class is dependent on the calculations done in a getter. For example in ember-data setting to the models' attributes
would be problematic and so it makes sense it is a read only value. Where as in this case these are aliases not a derived values. They are not calculated, they are used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep in mind that this is just an example. But here are my thoughts.
Abilities shouldn't be overriden. That can break a lot. We can't have in one place the ability canCreate
-> true
and in the other false
for the same model even if we want to. The readOnly
will help to keep integrity between those states.
Second thing. We don't write code for easier testing. And even in tests, we shouldn't override the ability, just set the isAdmin
or (more PRO) mock it using eg. Sinon.js.
I don't want to teach people here why they should (or not) use it, that's why I didn't add it. But as you know reads
has some disadvantages and can mislead the expected behavior. More about it, eg. here: https://m.alphasights.com/the-risks-you-take-when-you-use-ember-computed-oneway-f2c008a14404
BTW. Im always making the property readOnly
if I don't expect it to be ever overridden. Like using const
and let
. And I don't expect to override any ability on the fronted, as I'm not in charge to control what I can or not. That's a backend part. If you are creating abilities which are not dependent on the API and used only eg for display sth on UI, then you may want to set it on your own. In that case, there is no other choice than NOT to use readOnly
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Abilities shouldn't be overriden. That can break a lot. We can't have in one place the ability canCreate -> true and in the other false for the same model even if we want to. The readOnly will help to keep integrity between those states.
Ok, in this instance your argument has convinced me. Thank you.
Im always making the property readOnly if I don't expect it to be ever overridden.
However, I do disagree with this. We have a dev on our team that is vehement about adding readOnly
to everything and I've had many WTF moments and lost time trying to understand why things break. It has been my experience that it is better to be permissive then it is to introduce weird errors and unexpected crashes because someone somewhere felt they knew the future better then I. Personal opinion obviously.
I prefer to stick with the default for most cases and add a readOnly
after I've convinced myself that changes to that property would be bad. As in your example above about abilities it is arguably true that changing an ability property manually would not be beneficial and readOnly
makes sense there.
Thank you for the time to explain your perspective. It has helped me learn something new today.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are definitely right. We shouldn't add it everywhere we can. We have to be very careful with it. Of course, your experience will help you a lot with it, so with time, you will feel which are readOnly and which are not. The same as with consts. That requires some skill. But trust me there are some cases when this mark can save you a lot of trouble. You have to just use it wisely and exactly know the purpose. Not by guessing ;)
At the beginning of the Ember journey, I totally agree and do not recommend to use it until the moment you will realize that you really need it right now. Then you will be ready to control the force 😅
No problem. That's what for the community is. Good to know your concerns as well :)
Anyway, you still think we should change the example to reads
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the reads are good because most newbies don't realize they are there
addon/computed.js
Outdated
}); | ||
} | ||
}; | ||
return computed(resourceName, function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should either support or document the use case where we have more then just the resource to deal with. Some abilities might have need for named properties.
}); | ||
} | ||
}; | ||
return computed(resourceName, function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should either support or document the use case where the ability needs named properties (not just a resource) to work.
UPGRADING.md
Outdated
@@ -4,6 +4,11 @@ Whilst experimenting with the API & benefiting from changes in Ember, we've had | |||
|
|||
Here are the details on updating from previous versions. | |||
|
|||
## From v2.0.0 | |||
1. You will not longer be able to import `CanMixin` and `computed` as they will be removed. You can reproduce theirs behaviours using `can` service and its methods. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be inaccurate as the computed macro still exists. It's just imported differently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some old stuff :/
This is last chance to talk about your thoughts and concerns according to this PR. 🤔➡👌⭐️ Don't bother to mark this comment as 👍 if you are ok to merge it. |
UPGRADING.md
Outdated
|
||
### Notable changes | ||
1. You have to pass a `null` model if you want to pass only parameters to `can` or `cannot` methods of `can` service. Eg: `this.get('canService').can('post', null, { test: true})` | ||
2. The `model` passed to helpers or `can` service methods, as from now on, can be anything. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't aware that there were any restrictions earlier, to be honest. Looking at the changes it seems like we could only use Ember.Object instances before. Perhaps we should make that clear using:
The
model
passed to helpers orcan
service methods, as from now on, can be anything instead of anEmber.Object
instance.
This isn't super important, by any means. I'll leave this to your consideration.
Again, great job on this.
UPGRADING.md
Outdated
4. `build` method of `can` service will be replaced by `abilityFor` | ||
|
||
### Notable changes | ||
1. You have to pass a `null` model if you want to pass only parameters to `can` or `cannot` methods of `can` service. Eg: `this.get('canService').can('post', null, { test: true})` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My OCD is telling me that we need a space after true
.
This PR will deprecate old fashion API. The deprecations will stay until
v2.0.0
Deprecations
CanMixin
as it will be removed. You can reproduce its behavior usingcan
service and its methods.import { CanService } from 'ember-can'
->import CanService from 'ember-can/services/can'
import { ability } from 'ember-can'
->import { ability } from 'ember-can/computed'
build
method ofcan
service will be replaced byabilityFor
Notable changes
null
model if you want to pass only parameters tocan
orcannot
methods ofcan
service. Eg:this.get('canService').can('post', null, { test: true})
model
passed to helpers orcan
service methods, as from now on, can be anything.