Rails Routing Admin Error - ruby

I have this AdminController
class Admin::AdminController < ApplicationController
before_filter :is_admin?
def dashboard
end
def is_admin?
redirect_to root_path, :flash => { :alert => "You are not an admin!" } if !current_user.admin?
end
end
and this other controller that inherits from the above:
class Admin::CompetitionEntriesController < Admin::AdminController
before_action :set_competition_entry, only: [:show, :edit, :update, :destroy]
....
end
My route file is:
Foo::Application.routes.draw do
root 'competition_entries#index'
devise_for :users
resources :competition_entries
namespace :admin do
root 'admin#dashboard'
resources :competition_entries
end
....
..
.
end
Now why am I getting this error when I am trying to reach 'http://localhost:3000/admin'
Missing template admin/admin/dashboard...
I am getting this extra admin? Why? I don't want to use scopes I want to use namespaces.
Thanks.

Routes do not affect default search paths for templates. If your controller class is named Foo::BarController, Rails will look for the templates in app/views/foo/bar/ unless you specify otherwise.

Related

Rails 5 with Devise, testing Controllers with Rspec (destroy action)

I am implementing rspec test for destroy action, the concept is that signed in user can only destroy his own posts, and cannot destroy posts creates by other users.
The `new_post` is created by a user named `creator`, and another user named `user1` signed in and try to delete the `new_post`, it should not be able to delete it, because of the ` before_action :authenticate_user!, only: %i[create destroy]` in Posts controller
Posts controller.
class PostsController < ApplicationController
before_action :set_post, only: %i[show edit update destroy]
before_action :current_user, only: %i[create destroy]
before_action :authenticate_user!, only: %i[create destroy]
.
.
.
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:content, :picture)
end
end
users controller spec
require 'rails_helper'
RSpec.describe PostsController, type: :controller do
context 'DELETE #destroy' do
let(:user1) {User.create!(name:"John", email:"john#mail.com", password:"password")}
let(:creator) { User.create!(name: "creator", email: "creaor#gmail.com", password: "password") }
let(:new_post){creator.posts.create!(content: "Neque porro quisquam est qui dolorem ipsum")}
it 'A user cannot delete a post created by other user' do
sign_in user1
p (new_post)
expect { delete :destroy, params: { id: new_post.id } }.to change(Post, :count).by(0)
end
end
end
Failures:
1) PostsController DELETE #destroy A user cannot delete a post created by other user
Failure/Error: expect { delete :destroy, params: { id: new_post.id } }.to change(Post, :count).by(0)
expected `Post.count` to have changed by 0, but was changed by -1
I believe you need to add an authorization check to your code. authenticate_user! authenticates that the person making the request is logged in. However, it does not check if the user is authorized to make the request they're making.
See Authentication versus Authorization for a bit more discussion on the two concepts. And take a look at https://stackoverflow.com/a/25654844/868533 for a good overview of popular authorization gems in Rails. To be clear, you almost definitely want a way to authenticate users (Devise) along with an authorization gem.
Assuming you decide to go with CanCanCan (which is a common option that I've used in past), you'd add an Ability class like:
class Ability
include CanCan::Ability
def initialize(user)
if user.present?
can :destroy, Post, user_id: user.id
end
end
end
Then you could add before_action :check_authorization, only: %i[destroy] as a new before_action on your controller and your tests should pass without any modification.
Remember. you are writing a controller test. So this test is unit test. There are two main ways to authorize in Devise. They are authorize routes and authorize controller. If you using authorize routes, when you write rspec for controller, you must use stub to counterfeit an authorize access.

Could not find devise mapping for path

I have the following routes defined in my routes.rb
devise_for :users, controllers: { registrations: "network/registrations",sessions: 'network/sessions', passwords: 'network/passwords' }
devise_scope :user do
get "registrations/show" => "network/registrations", as: :show_user_profile
end
and when i do rake routes i also see
network_show_user_profile GET /network/registrations/show(.:format) network/registrations#show
But when i try to access the path /network/registrations/show
i get the below exception
Could not find devise mapping for path "/network/registrations/show".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
I tried to modify the routes.rb and added
devise_scope :user do
get 'user_profile' => 'registrations#search', :as => 'user_profile'
end
and when i access user_profile path, i get the error
The action 'show' could not be found for Network::RegistrationsController
but when i add the action show to the controller I again get the same exception message
Could not find devise mapping for path "/network/registrations/show".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
any help as to what i am doing wrong would be appreciated. Thanks.
I tried adding same routes that you did
Rails.application.routes.draw do
devise_for :users, controllers: { registrations: "network/registrations",sessions: 'network/sessions', passwords: 'network/passwords' }
devise_scope :user do
get "registrations/show" => "network/registrations", as: :show_user_profile
end
end
But instead of
network_show_user_profile GET /network/registrations/show(.:format)
I got show_user_profile GET /registrations/show(.:format) registrations#show
So I replaced this routes file with below
Rails.application.routes.draw do
devise_for :users, controllers: { registrations: "network/registrations",sessions: 'network/sessions', passwords: 'network/passwords' }
devise_scope :user do
get "/network/registrations/show" => "network/registrations#show", as: :show_user_profile
end
end
I also created an action show in network/registrations_controller.rb and
everything works perfectly for me.
Hope this helps.

Rails Nameerror with double namespace controller, namespaced model

Can't work out how to get around this. I'm using the mailboxer gem, who have recently updated to a namespaced model. Using the main controller, everything is fine, but I also have a namespaced views/controller for an admin section which is causing the issue.
Model name is
mailboxer_conversations
Main section code (working fine):
routes.rb
namespace :mailboxer, path: '', as: nil do
resources :conversations, only: [:index, :show, :new, :create, :destroy], as: 'conversations', path: 'conversations' do
member do
post :reply
post :trash
post :untrash
end
end
controllers/mailboxer/conversations_controller.rb
class Mailboxer::ConversationsController < ApplicationController
end
The above is all working fine, the controller is namespaced with folders and I can access the Conversation model instance.
The below is the code I'm currently trying for the admin section, using the same model mailboxer_conversations.rb
routes.rb
namespace :admin do
namespace :mailboxer, path: '', as: nil do
resources :conversations, as: 'conversations', path: 'conversations'
end
end
controllers/admin/mailboxer/conversations_controller.rb
class Admin::Mailboxer::ConversationsController < ApplicationController
end
With the above setup, I'm getting a nameerror uninit. constant 'Conversations'. Says to me that it can't access the model, is this because of the double namespace, it's expecting the model.rb file to be in a different folder i.e admin/mailboxer_conversations.rb? I can't move the model, as it's in a gem.
Thanks

Getting around devise authentication requirement

I'm trying to not require authentication for my reports view action. However when I try to use the devise method skip_before_action or skip_before_filter, it will still revert me back to the login page.
Here is my application controller.
class ApplicationController < ActionController::Base
acts_as_token_authentication_handler_for User
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :require_user
layout :check_layout
protected
def check_layout
devise_controller? ? 'legacy' : nil
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email) }
end
private
def require_user
authenticate_user!
end
end
Here is my reports controller
class ReportsController < ApplicationController
skip_before_action :require_user, only: [:view]
skip_before_action :verify_authenticity_token, only: [:transition]
before_action :check_params, only: [:transition]
before_action :set_report, only: [:show, :edit, :update, :destroy, :draft, :copy_edit, :review_and_approve, :revise, :approve, :archive, :mail_merge, :draft_from_queue]
end
How do I do I go about not requiring authentication for the report view action?
Your filters look ok, but the problem is that you are not hitting the view action. You are hitting the index action:
Started GET "/reports" for 10.0.2.2 at 2015-07-31 23:48:55 +0000
...
Processing by ReportsController#index as HTML
Completed 401 Unauthorized in 29ms

Why does respond_with JSON not work?

I'm having a problem when trying to use the return to in a rails controller. This is not working:
class UsersController < ApplicationController
respond_to :json
def create
#user = User.create params[:user_info]
respond_with #user
end
end
This works:
class UsersController < ApplicationController
respond_to :json
def create
#user = User.create params[:user_info]
respond_with #user do |format|
format.json { render json: #user.to_json }
end
end
end
Why? This is the error I have in the server's log when using the one that doesn't work:
NoMethodError (undefined method `user_url' for #<UsersController:0x007fd44d83ea90>):
app/controllers/users_controller.rb:7:in `create'
My route is:
resources :users, :only => [:create]
responds_with tries to redirect to user_url, so it looks for a show method in your user controller, which you don't have, since your route is limited to the create method only. Since the create method redirects to the show method by default this doesn't work. But in your second version you are actually rendering something, so no redirection happens.
You can give a :location option to respond_with if that's what you want, like so:
respond_with(#user, :location => home_url)
or use the render version as you do in your second version.

Resources