How do I pass user information to admin templates in Django? - django-admin

I have overridden some admin templates by copying them to my project/templates/admin/... and editing them. I'm now trying to do some simple theming in the templates that require knowing who is viewing the pages, but some pages like add/edit pages aren't getting 'user' passed in their context. I find this a bit strange since change_list pages are getting this in their context.
Here's the error I'm getting.
django.template.TemplateSyntaxError
TemplateSyntaxError: Caught VariableDoesNotExist while rendering: Failed lookup for key [user] in u"[{'csrf_token': <django.utils.functional.__proxy__ object at 0x108fb9e50>, 'show_delete_link': False, 'show_save': True, 'show_save_as_new': False, 'onclick_attrib': '', 'is_popup': False, 'show_save_and_add_another': True, 'show_save_and_continue': True}]"

What about using request.user instead of user? Maybe that would work.

Related

Rails render regular erb partial to active admin layout (arb)

I'm trying to add a view that LOOKS like active admin, but doesn't need to take advantage of active admin's automatic page creations (in fact I can't because I'm not using a model for these views). In my controller, I've added
render "reports/index", layout: "active_admin"
I've seen this done in several other forums. However, I'm getting this error: undefined local variable or method 'view_factory' for :Arbre::Context
which I'm assuming is because I'm not using a full active admin page object or something. Any ideas on how to make this work?
If you don't have a model then use a custom page.

Why Rails defaults creation to a POST on collection in HTML form?

When generating a scaffold, by default the new_resource_path generates a form that will submit to resources_path.
This makes total sense in a RESTful mentality.
But, given that the generated material does not uses it as a REST resource, why does it POST to the collection path?
When the resource is successfully created, Rails will redirect to the created resource path. When any error occurs, Rails will render the new template that will present the errors (generated by scaffolding).
This seems fine, except that when any errors occurs when trying to create the resource, the URL will change to the collection path. This means that if user tries to refresh the page, it will not see the creation form. If the application does not allow listing for this resource, a routing error may happen. In case the application uses any type of authorization and the current user does not has the required authorization to list stuff, it may see a forbidden.
I see Rails scaffold generator as something the community agrees to be the standard way to do basic CRUD in it. So, why this behavior?
It seems that by keeping a purist RESTful resources approach we are breaking user experience a bit.
To see an example of this, just create a new Rails application, scaffold a new entity and try to create it with some validation errors.
$ rails new example
$ cd example
$ rails generate scaffold note text
# edit app/models/note.rb
class Note < ApplicationRecord
validates :text, length: { minimum: 10 }
end
$ rails db:migrate
$ rails server
# go to localhost:3000/notes/new
# click 'Create Note'
# see the error
# hit browser's refresh button
# now you are listing notes, and not creating one
If you think "this should not harm a real application". I've come up with this when writing tests for authentication.
My application is using Devise and fails for this test:
test 'new user should not be able to register with wrong password confirmation' do
email = 'newuser#newdomain.com'
password = 'little$secret'
password_confirmation = 'big$secret'
visit new_user_registration_path
fill_in 'Email', with: email
fill_in 'Password', with: password
fill_in 'Password confirmation', with: password_confirmation
assert_no_difference ->{ User.count } do
click_on 'Sign up'
end
assert page.has_content?("Password confirmation doesn't match Password")
# FAILS:
assert_equal new_user_registration_path, current_path
end
What this means in real life: When user tries to create an account, submit an invalid form, see the error and hit refresh, it is on an invalid path as the resource does not support listing (i.e. /users).
To make that last assertion pass, I had to overwrite the default Devise view to submit the form to /users/sign_up instead of just /users and to add a new route to call create when a POST is made to this URL. Then I realized that this will happen to any controller following the RESTful Resource approach, unless developers create this new route and use a custom URL for submitting creation forms.
Also, the "purist RESTful Resource approach" doesn't seem to be so purist. When you submit your form with invalid data, the POST will result in a 200 OK rendering an HTML with errors, instead of a 400 Bad Request. So, why not submit the form to the same URL the form exists in?
My bet is that I'm missing something, but I can't figure it out. So, what am I missing?
But, given that the generated material does not uses it as a REST
resource, why does it POST to the collection path?
So, why not submit the form to the same URL the form exists in?
Because the rails conventions embrace statelessness.
The form that you see when a create fails shows the result of a POST request. It is not meant to be repeated - or shared.
You could potentially have POST /notes/create and create a GET /notes/create route so that it would show the form after a refresh - but is that a good design from a framework point of view? I would say no.
Forms that POST back to the same URL can give a bad user experience - like the "Confirm form submission" dialog when you hit the back button. This is actually worse than the scenario you are painting up as it can lead to unexpected consequences for the user.
I see Rails scaffold generator as something the community agrees to be
the standard way to do basic CRUD in it.
The rails scaffold command is a rapid prototyping tool. They are not meant as the authoritative source of the "right" way to do rails nor does the community hold them as the word of god.
Also, the "purist RESTful Resource approach" doesn't seem to be so
purist.
The Rails community is not very purist. If anything its quite pragmatic and aims towards embracing concepts like REST but with a focus on developer convenience and "should just work".
When you submit your form with invalid data, the POST will
result in a 200 OK rendering an HTML with errors, instead of a 400 Bad
Request.
This is pragmatism, back in the day Internet Explorer would do all kinds of annoying things when given 4XX response codes. 200 OK guarantees the client will render the response - although it is tecnically wrong.
This seems fine, except that when any errors occurs when trying to
create the resource, the URL will change to the collection path. This
means that if user tries to refresh the page, it will not see the
creation form.
I don't get you : If you refresh the page, it will just re-POST the same parameters and so show the same form with errors. I just re-checked that.
If the application does not allow listing for this resource, a routing
error may happen. In case the application uses any type of
authorization and the current user does not has the required
authorization to list stuff, it may see a forbidden.
So, a user would not be allowed, for example, to view a list of posts, but it would allowed to create a new one ?

Ember singletons - implementing current_user behavior

I'm working on a rails 4, ember-rails, ember-source 1.2.0 application, with devise for authentication.
I have the app successfully issuing authentication requests, receiving the user details, and now I need a good place to store "current_user" throughout the app. I've tried writing my own initializer to do some injection but it doesn't seem to be a well documented code path:
Admin.initializer({
name: 'currentUser',
initialize: function(container, application){
container.optionsForType('user', { instantiate: false, singleton: true });
application.register('user:current',Admin.User.createRecord({}));
application.inject('route','current_user','user:current')
application.inject('controller','current_user','user:current')
application.inject('view','current_user','user:current')
}
})
This code errors because:
Assertion failed: Error while loading route: TypeError: Cannot call method 'set' of undefined
How can I register a single model and make it visible all the way to the view level? Once I have the singleton registered I will issue an ajax login request and fill in its properties or send the user to a login screen.
That's how it works, your error is happening somewhere else. You'll need to show additional information.
http://emberjs.jsbin.com/esEYIrIR/2/edit

Rails - ping user without authenticating?

So I'm writing a Facebook clone for a school project using Rails and I need some way to keep track of which users are logged in. At the moment, I'm a bit time-pressed, so I decided just to update the User model every time they visit a page with a last_seen attribute.
Problem is, the user model requires revalidation to successfully update_attributes. So I'm wondering two things:
Is there a better way to do this that I'm missing?
If not (or if it would take too long) is there a way to bypass the validation?
to 1.: I cant give you an exact answer but I think itwould be better to deal with this problem using a javascript on the clientside with a timer that sends an ajax request all xxx secounds and an action that receives this requests and saves it in a seperate table associated with the User.
to 2.: Yes there are some ways to bypass validations The most pragmatic way is to bypass the :validate => false option when saving the object but then you can use update_attributes:
object.save(:validate => false)
So there is also the possibility to use conditional validations that are only used when a specific condition is complyed. There is a railscast about that => http://railscasts.com/episodes/41-conditional-validations .

AuthLogic automatically loads errors into #base and populates those errors on a signin form

(rdb:1) #account_session = AccountSession.new
# => <AccountSession: no credentials provided>
(rdb:1) #account_session.errors
# => <Authlogic::Session::Validation::Errors:0x213cc78 #errors={}, #base=#<AccountSession: no credentials provided>>
How do I prevent this? Also note, that credentials can't be provided in advance because that will populate the :new form with (incorrect) data. A new signin form should be blank.
Are you validating your model in one of your methods/before-filters,etc?
I reproduced this on a vanilla Rails install that contains only AuthLogic. It revealed that the behavior described in this question is actually AuthLogic design behavior. I don't like this because calling #new on the model shouldn't result in errors if none really exist. And it's also funky if a form has UI elements that show error styling for #base errors. I'll address this on the gem's github issues.

Resources