Closed JeanMertz closed 12 years ago
The reason is that haml-coffee doesn't have some specific logic at render time to handle some kind of attribute value checking, so normal JavaScript rules take place: "" + null = "null"
There are now two options to handle this case:
I think I'm going to implement the second option. In the meanwhile you could add
window.HAML.escape = function(text) {
if (text === null || text === undefined) {
return "";
}
return ("" + text)
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
});
as escaping function as a workaround.
Thank you for the help, I am still new to this whole Backbone/templating stuff. Another quick question on this topic:
Ruby
code on top of these templates?Given this file:
index.hamlc
%td= @email
%td= @first_name
%td= @last_name
%td= @company
%td
%a{ href: "#/#{@id}" } Show
%a{ href: "#/#{@id}/edit" } Edit
%a{ href: "#/#{@id}/destroy" class: 'destroy' } Destroy
I wanted to hide the Destroy
link for the current_user
. I tried several things, but I couldn't find out how to solve this. I also tried renaming the file to index.hamlc.erb
and using:
<% if current_user.id == @user.id %>
%a{ href: "#/#{@id}/destroy" class: 'destroy' } Destroy
<% end %>
But that resulted in undefined local variable or method current_user
. Am I thinking about this the wrong way? Are these templates not processed on the server before they are sent to the client (I asume they are), or should I actually retrieve current_user
in the Backbone model before using it in the views/templates?
I use CanCan for the authorization and every backend resource that my Backbone app gets through the REST API will be decorated with its abilities. So for example when a user requests the all users, the response looks like this:
{
success: true
count: 2
users: [
{ id: 1, name: "User 1", abilities: ['read', 'update', 'destroy'] }
{ id: 2, name: "User 2", abilities: ['read'] }
]
}
Since a real REST API is stateless, the frontend sends the authentication token of the current logged in user, and thus all abilities are for the current user. You can easily extract this into a Rails responder, so you don't have to manually add the abilities for each resource. The advantage of this approach is, you have a single Ability class to control access to the resource for the backend and also the frontend.
Now you can ask the resource if the current user is allowed to destroy it:
- if @user.can('destroy')
%a{ href: "#/#{@id}/destroy" class: 'destroy' } Destroy
Where the can
method is simply:
can: (ability) -> _.include @get('abilities'), ability
Hmm, I see how you do this, that seems like a nice solution. So what you say is that with the abilities added to user 1 and user 2, that means that the current user
is able to update
and destroy
the user
with id 1
but can only view
the user
with id 2
, is that correct?
However, the question that remains, is how I can access the current_user
resource, for example, to check the role
of the user and render specific parts of the UI based on the role? Do I simply send the current_user
resource to the javascript?
Sorry for the totally off-topic discussion here, I really appreciate the help!
You're right with the abilities, that's exactly the way it's meant to be.
If you like to access the current user in your template it's a perfect match for the global context. There's a section in the README about it, but basically the global context is an object that gets automatically merged into the local context (the data you're passing to the render() method). This would be the ideal place to set the current user, so that @currentUser
is always present in every template without the need to explicit pass it with the local context.
Thank you, that seems perfect to me. Re-reading your two posts, I understand how it works, but your javascript implementation of cancan
seems to imply the exact opposite of what it actually does.
Reading your
if @user.can('destroy')
It reads as if you want to ask "Can the user destroy", but what it really does is "Can I destroy this user". I guess I just have to get used to reading it different, but maybe something like can('destroy', @user)
or something would be easier to understand?
Anyway, thanks for helping out. I'm off to implementing this functionality.
I was doing to much things in parallel, and the example is just pseudo code without thinking that hard :P Of course it would make sense to choose a name carefully so that it reflects what it does.
I just switched from using
.jst.eco
for my Backbone templates to usinghamlc
. I love it so far, soo much cleaner. While updating my templates I am bumping into one issue though, I can't seem to get anull
value to parse nothing.In my Backbone Model I do:
This line in
eco
shows the company when there is one, and shows nothing when there isn't:While the new
hamlc
shows the actual textnull
inside the input field when no company is provided:Any ideas?