I need to display some form fields in ActiveAdmin form only to specific users.
But when I try to check user status with this code:
ActiveAdmin.register Store do
# ...
form do |f|
f.inputs "Basic" do
if current_admin_user.super_admin?
f.input :admin_user
end
# ...
end
end
end
I get
undefined local variable or method `current_admin_user' for #<ActiveAdmin::DSL:0xdb8e798>
CanCan methods also don't work in the ActiveAdmin form definition.
Generally my question is: how can I manage admin interface display, based on current user type?
Particularly, how can I get current devise user object from within ActiveAdmin definitions?
It is a matter of scope. You could try accessing the helper method using the f.template object like so:
ActiveAdmin.register Store do
# ...
form do |f|
f.inputs "Basic" do
if f.template.current_admin_user.super_admin?
f.input :admin_user
end
# ...
end
end
end
Good luck.
I've found a workaround for this issue. In /app/admin/stores.rb:
ActiveAdmin.register Store do
# ...
form :partial => 'form'
# ...
end
and then in /app/views/admin/stores/_form.html.haml:
= semantic_form_for [:admin, #store] do |f|
= f.inputs "Basic" do
- if current_admin_user.super_admin?
=f.input :admin_user
It's not convenient at all, but works.
I know this thread is a little old but I just found a nice little fix for this. I'm not using devise, I'm using the Twitter API for logging in my users
In active_admin.rb, look for config.current_user_method and change the default value to current_user from current_admin_user
config.current_user_method = :current_user
Also change the logout_link_path to in your routes to include as: :destroy_user_session
Related
This is partly a problem-solving question, partly a "I'm trying to understand what's going on" question. I hope that's allowed. Basically, I'm trying to get Warden user authentication to work with Ruby/Sinatra and Postgres on Heroku.
I got a lot of help from this handy (but oldish) tutorial.
From some Rails experience I am a bit familiar with Active Record. The tutorial didn't mention anything about creating a migration for the User class. I went ahead and made my own migration, with my own properties ("name", "email", "password"), only to discover later that, lo and behold, the properties I put in that migration weren't being used by (and in fact were rejected by) the actual model in use. When I examined the object instances in the database, I found that they had only the properties Warden provided for me ("username" and "password").
I'm just trying to understand what happened here. I migrated down my (apparently unnecessary and ignored) Users migration, and nothing happened. I mean that I was able to create User instances and log in using them just as before.
Then it occurred to me that this old Warden tutorial (from 2012) uses something called DataMapper, which does what Active Record would do today. Is that right? They are both "ORMs"? I'm still confused about why Sinatra completely ignored the User migration I did. Maybe it's just using a different database--I did notice wht might be a new db.sqlite database in my main file. Pretty sure the one I created for Active Record was db/madlibs.sqlite3.
Although it works on my local machine, I'm pretty sure it won't work on Heroku, since they don't support sqlite (pretty sure). That then means I'll have to go back to the Warden documentation and figure out how to get it to work with my Postgres database...right? Any pointers on how to get started with that? Since this will be my first project using any authentication library like Warden, it's pretty intimidating.
Here's what I have so far (repo):
app.rb:
require 'sinatra'
require 'sinatra/activerecord'
require 'sinatra/base'
require './config/environment'
require 'bundler'
Bundler.require
require './model'
enable :sessions
class Madlib < ActiveRecord::Base
end
class SinatraWardenExample < Sinatra::Base
register Sinatra::Flash
end
use Warden::Manager do |config|
config.serialize_into_session{|user| user.id }
config.serialize_from_session{|id| User.get(id) }
config.scope_defaults :default,
strategies: [:password],
action: 'auth/unauthenticated'
config.failure_app = self
end
Warden::Manager.before_failure do |env,opts|
env['REQUEST_METHOD'] = 'POST'
end
Warden::Strategies.add(:password) do
def valid?
params['user']['username'] && params['user']['password']
end
def authenticate!
user = User.first(username: params['user']['username'])
if user.nil?
fail!("The username you entered does not exist.")
elsif user.authenticate(params['user']['password'])
success!(user)
else
fail!("Could not log in")
end
end
end
...non authentication routes...
post '/auth/login' do
env['warden'].authenticate!
flash[:success] = env['warden'].message
if session[:return_to].nil?
redirect '/'
else
redirect session[:return_to]
end
end
get '/auth/logout' do
env['warden'].raw_session.inspect
env['warden'].logout
flash[:success] = 'Successfully logged out'
redirect '/'
end
post '/auth/unauthenticated' do
session[:return_to] = env['warden.options'][:attempted_path]
puts env['warden.options'][:attempted_path]
flash[:error] = env['warden'].message || "You must log in"
redirect '/auth/login'
end
get '/protected' do
env['warden'].authenticate!
#current_user = env['warden'].user
erb :protected
end
model.rb (just the User model):
require 'rubygems'
require 'data_mapper'
require 'dm-sqlite-adapter'
require 'bcrypt'
DataMapper.setup(:default, "sqlite://#{Dir.pwd}/db.sqlite")
class User
include DataMapper::Resource
include BCrypt
property :id, Serial, :key => true
property :username, String, :length => 3..50
property :password, BCryptHash
def authenticate(attempted_password)
if self.password == attempted_password
true
else
false
end
end
end
DataMapper.finalize
DataMapper.auto_upgrade!
It seems like this repo might have solved the problems I'm facing now. Should I study that? The Warden documentation itself is pretty forbidding for a relative beginner. For example, it says "Warden must be downstream of some kind of session middleware. It must have a failure application declared, and you should declare which strategies to use by default." I don't understand that. And then it gives some code...which I also don't quite understand. Advice?? (Should I be working with a teacher/mentor, maybe?)
I'm creating a mustache template for a Moodle site and want to display some content on the front page but only if the user is not yet logged in. I was hoping I could do something like this in the template:
{{^usernotloggedin}}
My content for users not logged in.
{{/usernotloggedin}}
However I can't find any documentation on the user variables available to mustache to test if a user is authenticated or not.
Any advice of where to look or how to implement this would be great.
You would need to adjust the code that calls the template to add that data to the context that is passed to the template. In that case you can use the isloggedin() function to set the value you want to pass to the template.
I hope I'm not quite late to this question by anyhow I'd like to add my answer to this as well
Your mustache files are simple templates which cannot perform logic. What you can do is
in your controller or the file which calls the render function (which renders the mustache file and gives HTML), apply a check there
require( '/path/to/moodle/config.php' );
if (isloggedin()) {
echo "you are logged in";
}
Once you have applied the check you can send the array with a flag identifier (ONLY TRUE or FALSE) which the mustache files can understand.
for eg
in your controller/block etc you can do the following
$tagcloud = core_tag_collection::get_tag_cloud($this->config->tagcoll, $this->config->showstandard == core_tag_tag::STANDARD_ONLY, $this->config->numberoftags, 'name', '', $this->page->context->id, $this->config->ctx, $this->config->rec);
$content = $tagcloud->export_for_template($OUTPUT);
require( '/path/to/moodle/config.php' );
$flag = isloggedin() ? TRUE : FALSE;
array_push($content, $flag);
$this->content->text = $OUTPUT->render_from_template('core_tag/search_course_by_tags', $content);
and in your mustache file
{{#flag}}
your fancy code here which will onyl work if the user is logged in
{{/flag}}
I am getting the error Mongoid::Errors::DocumentNotFound in UsersController#show whenever I am trying to click on signout in my app which uses mongoid rails 4.0.1 and devise.
My user controller code is
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
end
The error is:
Problem: Document(s) not found for class User with id(s) sign_out. Summary: When calling User.find with an id or array of ids, each parameter must match a document in the database or this error will be raised. The search was for the id(s): sign_out ... (1 total) and the following ids were not found: sign_out. Resolution: Search for an id that is in the database or set the Mongoid.raise_not_found_error configuration option to false, which will cause a nil to be returned instead of raising this error when searching for a single id, or only the matched documents when searching for multiples.
Please help me in this issue.
A similar question, is here.
While all the first answer is important and needs to be checked (make sure you have :method => :delete on your 'Sign Out' link), it is the third answer which fixed it for my Rails 4.1.6 + Mongoid app: adding jquery_ujs.
Specifically, adding //= require jquery_ujs to my application.js file took my broken link and made it sign out sucessfully.
I'm working in Rails 4 and have gotten CanCan to work well with instructions from this issue, except for one use case that I think might be relatively common.
I have a Comment model, which has_many :comments, through: :replies for nested comments. All of this is working well, until I add load_and_authorize_resource to my comments controller. The problem seems to stem from a hidden field sending an optional :parent_comment_id attribute to my create action.
I've permitted this attribute via strong parameters:
def comment_params
params.require(:comment).permit(:content, :parent_comment_id, :post_id, :comment_id, :user_id)
end
So that I can create the association if a :parent_comment_id is included:
if comment_params[:parent_comment_id] != nil
Reply.create({:parent_comment_id => comment_params[:parent_comment_id], :comment_id => #comment.id})
end
But once I add load_and_authorize_resource, I get an unknown attribute error for :parent_comment_id. What am I missing?
Solution came to me in my sleep. Here's what I did to solve the problem:
The only reason comment_params wasn't normally having a problem on create, was because I was excluding the extra :parent_comment_id parameter, like this:
#comment = post.comment.create(comment_params.except(:parent_comment_id))
When CanCan used the comment_params method however, it did no such sanitation. Hence, the problem. It would have been messy to add that sanitation to CanCan on a per-controller basis, so I did what I should have done all along and instead of passing the :parent_comment_id inside :comment, I used hidden_field_tag to pass it outside of :comment and accessed it through plain, old params.
I hope this helps someone else who makes a similar mistake!
I am still learning mojolicious and MVC frameworks in general so this just might be a problem where I am thinking about this wrong so if I am please suggest a better way to do the following.
I have a route /route/:param where param is sometimes defined and sometimes not. I am trying to use "param" in the template for that route but I get an error saying "param" requires explicit package name. I know this is due to :param not matching in the route because when I do call /route/value everything works fine.
Is there a way to be able to use the same template for both when "param" is defined and not defined? I am just trying to pre-populate a form off of what is defined in "param" but not making it required to.
In the template I have
<% if(defined($param)){ %><%= $param %><% } %>
Thanks.
It is always safe to refer to stash("param"), where stash is a helper function defined in Mojolicious::Plugin::DefaultHelpers:
<%= stash "param" %>
<%= defined(stash("param")) && stash("param") %>
etc.
It is possible to define a stash (or a flash) variable as a Perl variable within the epl space/template so that it can be reused, if required. e.g.,
% if (my $param = stash 'param') {
$param
% }
In this case the if condition block will be rendered only when the param is defined in the stash, otherwise, it'll be skipped.
It seems like in this situation using an optional placeholder in the route might be the best option. If the placeholder is defined in the route itself that definition will be used if the placeholder is not given in the url (else the value specified in the URL is used).
For example:
$r->any('/page/:paramVar')->to('page#doTheThing', paramVar => 'cake');
If the the address "/page" is loaded then $self->param('paramVar') == 'cake' else if "/page/tree" is loaded then $self->param('paramVar') == 'tree'.
Note: As with other placeholder values an optional placeholder, such as paramVar used in the above example, can be accessed via the stash function as well as the param function: $self->stash('paramVar').