rails_admin authentication with user's boolean admin - ruby-on-rails-4

I am currently using rails 4.2.0beta4 with devise. In my schema, my user had boolean :admin default:false. After installing rails_admin, for the time being, every user is allowed to go to my /admin. But how do I make it so that only the users with boolean is_admin? true people log in?
Should I just do rails generate devise admin? Would that be quicker choice than having to configure again?
Thanks in advance.

I'd create an admin namespace...
1 - In routes.rb
namespace :admin do
resources :your_routes
end
2 - Make sure the following directories exist; app/views/admin, app/controllers/admin, and put any controllers and view templates that you want to restrict to admins in those folders.
3 - Add this to application_controller.rb
def user_is_admin?
signed_in? && current_user.is_admin?
end
4 - Then in any controller inside your app/controllers/admin add a before_filter to check
some_controller.rb
class Admin::YourController < ApplicationController
before_filter :user_is_admin?
end
For what it's worth, you don't have to namespace if you don't want to. You could technically just add the before_filter from steps 3 and 4 to whatever action you want to protect, but I think the namespace is a better idea in the long run.

Related

Routes in Rails SAML IdP

I'm trying to get this gem to work with Rails 4 application that will serve as a SAML identity provider.
The thing that is confusing me is the routes and the template I assume should be rendered. In the gem controller, there is this:
def new
render template: "saml_idp/idp/new"
end
My routes are just the basic setup from the example, which I assume should match the action in my custom controller that inherits from the gem controller.
I have this in my controller.
class SamlIdpController < SamlIdp::IdpController
def idp_authenticate(email, password)
true
end
def idp_make_saml_response(user)
encode_SAMLResponse("you#example.com")
end
end
And my routes.rb file:
get '/saml/auth' => 'saml_idp#new'
get '/saml/metadata' => 'saml_idp#show'
So, what am I missing here? There should be a view rendered, instead I'm getting No Route Matches errors. Thanks.
As per Doc, I think you missed including SamlIdp::IdpController module
please include SamlIdp::IdpController rather than excluding.
Hope, It will work.
The new update for saml_idp gem wants to include SamlIdp::Controller as a module. And the controller class can inherit from ApplicationController
In your case it will be:
class SamlIdpController < ApplicationController
include SamlIdp::Controller
end

Ruby on Rails Pundit's current_user is nil in integration test

I'm using the gems pundit and devise. I have a delete link that only shows up if you are an admin. I have an integration test that I would like to verify that the delete link only shows up for admins.
test 'comment delete link shows when it should' do
log_in_as #admin
get movie_path(#movie)
assert_select 'a[href=?]', movie_comment_path(comments(:one), #movie.id)
end
My test_helper.rb looks like this:
...
class ActiveSupport::TestCase
...
def log_in_as(user, options = {})
password = options[:password] || 'password'
if integration_test?
post user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
else
Devise::TestHelpers.sign_in user
end
end
private
# Returns true inside an integration test.
def integration_test?
defined?(post_via_redirect)
end
end
The response.body looks all right, but indeed there is no delete link. There is one when I run the development server and visit the page myself. I've narrowed this down to the current_user that pundit uses in the policies is being passed in with a value of nil. This is my comment_policy.rb:
class CommentPolicy
attr_reader :current_user, :comment
def initialize(current_user, model)
#current_user = current_user
#comment = model
end
def create?
if #current_user
#current_user.member? or #current_user.content_creator? or #current_user.moderator? or #current_user.admin?
end
end
def destroy?
if #current_user
#current_user == #comment.user or #current_user.moderator? or #current_user.admin?
end
end
end
As a closing remark, I've heard that Rails 5 has opted for integration tests instead of controller tests as we know them from Rails 4 for the default type of tests to be generated for our controllers. If this is the case, devise would be a heck of a lot more useful out of the box when using Rails 5 if the sign_in/sign_out helpers that work in controller tests were made to work in integration tests as well. But would I still have this issue of pundit not knowing what current_user is? I'm assuming this all works fine in controller tests because the current_user is scoped to controllers? Any and all light shed on this topic is much appreciated, but I would really like to figure out how to get integration tests to work with this setup because I have about a billion I want to write right now.
Not that it totally matters, but does it need to be using current_user in the policy or can it just use user in the policy. By this I mean according to the elabs/pundit README on Github I would just use #user and user everywhere instead of current_user. Read the README if I confused you.
Additionally the nil for current_user typically occurs when you don't have a valid CSRF token for your request. When you do this on the website manually by going to localhost:3000 or w/e you are first performing a get on the login path before doing the post on the login path with your credentials. In your integration test I don't seem to see where you are performing that get in order to get the CSRF for your session.
Hope this helps!!!

Rails4: disable edit, delete in dashboard/backend

I want to show my work to clients. Clients could access the front-end and back-end/dashboard but I do not want them to change anything as multiple clients may visit the site. Only user with role 'admin' can access the back-end (user_type!='admin'). It works fine but I cannot disable create,edit,update actions at backend. Not sure why ? I want to keep to the RESTful routes.
Application controller
def authorize_to_backend
if (!current_user or current_user.user_type!='admin')
#login_dashboard is defined in router.rb
redirect_to login_dashboard_url, notice: "Please login"
end
end
i.e Brands controller
class BrandsController < ApplicationController
layout :set_layout
before_action :authorize_to_backend, only: [:create,:edit,:update]
def index
...
end
...
..
end
Added another checking in controller and it works :)
before_action :authorize_to_backend,:redirect_user, only: [:create,:update,:destroy]
private
def redirect_user
redirect_to request.referrer
end

correct way to use routes.rb namespace rails?

I'm trying to create a back-end area to my application, so I've created a folder named backend and backend_controller.rb inside it. I need the folder because the backend area will have multiple folders, so it's better-separated from my others.
my routes.rb looks like:
namespace :backend do
get 'index'
end
my backend_controller.rb:
class BackendController < ApplicationController
def index
end
end
But in this mode Rails will search for my backend_controller.rb inside the controllers folder, not in controller>backend. I've tried many variations, and I get routing errors.
So what is correct way to do that? To set the path /backend to index action instead of /backend/index?
Thanks
What i've done:
based on all answers, principally the one from Cyril DD
I've created the backend_controller.rb on the app/controller folder and in the sub-folder app/controller/backend i created the static_pages_controller.rb and all files looks like this:
app/controllers/backend_controller.rb:
class BackendController < ApplicationController
end
app/controller/backend/static_pages_contter.rb:
class Backend::StaticPagesController < BackendController
def dashboard
end
end
routes.rb:
namespace :backend do
resource :static_pages, path: '', only: [] do
root to:'static_pages#dashboard'
end
this works fine, but cause i'm newbie on rails i must ask. This is a good or a conventional way to do that? to administrate the permissions which user can see on the backend i use the backend_controller.rb right? and at last wy i must use resource: instead just get ''
Answering your question
Alright, namespace :something is a shorthand for scope 'something', module: 'something', as: 'something'
Now your declaration is very ambiguous, because you don't specify a controller. Typical declarations look like (assume you have a controller controllers/backend/some_resources_controller.rb and you want to generate default routes)
namespace :backend do
resources :some_resources
end
Now what you did
namespace :backend
get 'index'
end
is really ambiguous and I'm not surprised it doesn't do what you want. Basically you just tell rails to "look inside subfolder 'backend' and define the route 'index'". oO ? Which file/controller are we even talking about ?
What is your backend_controller.rb supposed to do ? Is it some kind of Control Panel ? Dashboard ? If so you're probably gonna have a lot of non-CRUD actions, but anyways you should go for the following syntax
namespace :backend
# Below line of code will auto-generate the `index` for /backend/backend_controller
resource :backend, only: [:index], path: '' do # we need " path: '' " otherwise we'll have https://xxx/backend/backend/dashboard
# If you have non-CRUD actions, put them here !
get 'dashboard' # https://xxx/backend/dashboard
...
end
# However, this will create URLs like "https://xxx/backend/dashboard", etc.
# If you want to redirect https://xxx/backend/ to your backend_controller#index, use root
root to: 'backend#index' # https://xxx/backend/
end
Last thing as mentionned by other guys, when you namespace a file like your Backend_controller inside /backend/ subfolder, you must rename the class like (/controllers/backend/backend_controller)
class Backend::BackendController < ApplicationController
Remark : if you only have like one or two controller actions, instead of using the resource method, you can declare singular resources
namespace :backend do
root to: 'backend#dashboard'
get 'dashboard', to: 'backend#dashboard' # singular resource
end
An Example of what you may actually really want to do...
I'm not sure you are clear yourself about what you want to do. As an example, here is my architecture
Files
/controllers/application_controller.rb
/controllers/backend_controller.rb
/controllers/backend/static_pages_controller.rb
/controllers/backend/***.rb
The class /controllers/backend_controller.rb will not serve any action, but will override ApplicationController to tune it for backend access (but maybe you don't need to do so)
class BackendController < ApplicationController
# Do you need to change user_access method ? Or any other backend-wide config ?
# If so put this config here, otherwise leave empty
end
Now for every file that goes in the /backend/ subfolder, I inherit the backend_controller
class Backend::StaticPagesController < BackendController
def index
end
# Note : if your index is some kind of dashboard, instead I would declare
def dashboard
end
end
class Backend::SomeResourcesController < BackendController
...
end
Routes
namespace :backend do
root to 'static_pages#index' # https://xxxx/backend/
resource :static_pages, only: [:index], path: '' # https://xxxx/backend/index
resources :some_resources
end
If you choose the dashboard solution in your controller, write instead :
namespace :backend do
root to: static_pages#dashboard # https://xxxx/backend/
resource :static_pages, path: '', only: [] do
get 'dashboard' # https://xxxx/backend/dashboard
end
resources :some_resources
end
Then it's simply
# routes.rb
Rails.application.routes.draw do
namespace :backend, shallow: true do
resource :backend, path:''
end
end
Then in your app/controllers/backend/backend_controller.rb, it'd look like this.
class Backend::BackendController < ApplicationController
def index
end
end
When I use rake routes it shows
Prefix Verb URI Pattern Controller#Action
backend_backends GET /backend(.:format) backend/backends#index
Hope this helps.

Mongoid records embedded in resource in active admin are not displayed

I have the following models
class User::ActiveAdmin::Partner < User::ActiveAdmin::Base
embeds_many :bonuses, class_name: 'User::Bonus'
end
and
class User::Bonus
include Mongoid::Document
embedded_in :partner, class_name: 'User::ActiveAdmin::Partner'
end
and then I register Bonuses in Active Admin
ActiveAdmin.register User::Bonus, as: 'Bonuses' do
config.filters = false
permit_params :number, :order_id
controller do
def scoped_collection
if current_admin_user.is_a? User::ActiveAdmin::Partner
current_admin_user.bonuses.page(params[:page]).per(10)
else
super
end
end
end
the collection is not empty (I have created a couple of bonuses), but in ActiveAdmin index page I see, that there are NO BONUSES. And nothing I can do to make it displayed properly. I have noticed, that User::Bonus table is empty, even if a partner does have any, but as I know, this is the way it works, and this is OK. So how can I make my table to be displayed? Thanks.
The problem in method ActiveAdmin::Helpers::Collection#collection_size. You are using old version of activeadmin-mongoid. Try update activeadmin-mongoid.
In rails4 branch, collection_size isn't correct. You should override this method in your app like here: https://github.com/elia/activeadmin-mongoid/blob/master/lib/active_admin/mongoid/helpers/collection.rb