NoMethodError after running successful 'create' action - ruby-on-rails-3

I am sending a post request to my API which works fine, it creates a new record. However, after the record is created i get this error in the server log
NoMethodError (undefined method `device_url' for #<Api::V1::DevicesController:0x007fa2f5dde5d8>):app/controllers/api/v1/devices_controller.rb:14:in `create'
This is my create action
def create
respond_with Device.create(params[:device])
end
All my resources are namespaced under Api#V1, here is my routes file
# Api ('/api')
namespace :api do
# Version 1 ('/api/v1')
namespace :v1 do
# Locations ('/api/v1/locations')
resources :locations
# Videos ('/api/v1/videos')
resources :videos
# Devices ('/api/v1/devices')
resources :devices
end
end

For a HTML POST request, after successfully creating the object, respond_with redirects to the object's path, i.e. here it would be equivalent to something like
redirect_to Device.create(params[:device])
which redirects to device_url. But since you have namespaced :devices in your routes, you need to specify that to your respond_with call, which would be
respond_with :api, :v1, Device.create(params[:device])

Related

role based route authentication

I have been using devise and cancancan for authentication and authorisation resp., resque for background jobs. I have been following Ryans screencast number 271 and saw below code snippet for routes.rb file.
authenticate :admin do
mount Resque::Server, :at => "/resque"
end
to authenticated user, but in my case I have only users table and admin is also users separated by role column, Now I would like to authenticate and authorise the route for resque server path based on users role, How can I achieve solution for this problem ?
authenticate :user do
mount Resque::Server, :at => "/resque"
end
works fine for logged in user but i want it to be accessible only to admin user. Any help will be heartly appreciated.
# config/initializers/admin.rb
class CanAccessResque
def self.matches?(request)
current_user = request.env['warden'].user
return false if current_user.blank?
Ability.new(current_user).can? :manage, Resque
end
end
# routes.rb
namespace :admin do
constraints CanAccessResque do
mount Resque::Server, at: 'resque'
end
end
# ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.is_admin?
can :manage, Resque
end
end
end
# user.rb
class User < ActiveRecord::Base
def is_admin?
# your admin logic here for example:
self.role == "admin"
end
end
OR for more information, check this blog out: resque-admin-in-rails-routes-with-cancan
Hope this helps you.

How to customize ActiveRecord::RecordNotFound in Sinatra

in my app.rb I have a get '/posts/:id' I have implemented a rescue ActiveRecord:RecordNotFound but instead of redirecting to the root url it still displays the errors. Is there a way to customize ActiveRecord errors like a custom routing error (not_found)
not_found do
slim :not_found
end
get '/posts/:id' do
begin
#post = Post.find(params[:id])
rescue ActiveRecord::RecordNotFound => e
redirect '/'#or display a view or a flash-notice
end
slim :show_post
end
The Sinatra Book recommends setting an 'error' route and defining the custom error you want to run through it. In your case, it would look something like this
error ActiveRecord::RecordNotFound do
redirect '/'
end
NOTE: You will still see the error page with the stack trace as long as your Sinatra application is set to the "Development" Environment. You can set it to other environment when you run Sinatra:
ruby app.rb -e production
More on Sinatra environments here.

CanCan denies authorization when can :create is called

My CanCan implementation is denying access when I have called the can method with :create specified. Here is my ability implementation:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # User is not logged in (Guest)
if user.id == nil # Guest user
can [:create, :update], Device
else
if user.admin?
can :manage, :all
else
can :manage, Spot, :user_id => user.id
end
end
end
end
Basically I want non-authenticated users to be able to submit POST and PUT requests to the create and update actions of my Devices controller. However, when I try to submit a POST request the request is denied by CanCan (I'm asked to log in).
At the top of my devices controller I simply call load_and_authorize_resouce.
Does anyone see why CanCan would be raising an AccessDenied exception on this?

Rails 3 - Can Active_admin use an existing user model?

Can Active Admin use my current Devise user model? It already has a column named admin, and if it's true, I'd like to bypass the Active admin login, when going to /admin.
Is this possible?
Current routes:
#Active admin
ActiveAdmin.routes(self)
#Devise
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users, :path => "account"
The rest is basically standard Devise + Active admin
Yes you can do that, when running the generator skip the user model creation:
rails generate active_admin:install --skip-users
Then in your config/initializers/active_admin.rb :
# == User Authentication
#
# Active Admin will automatically call an authentication
# method in a before filter of all controller actions to
# ensure that there is a currently logged in admin user.
#
# This setting changes the method which Active Admin calls
# within the controller.
config.authentication_method = :authenticate_admin!
uncomment config.authentication_method and provide your authentication method for your admin, for example:
# app/controllers/application_controller.rb
def authenticate_admin!
redirect_to new_user_session_path unless current_user.is_admin?
end
Restart your server and It should be working. Also Take a look to Active Admin Configuration
Hope this helps.
As stated earlier, you will need to update your config/initializers/active_admin.rb to reflect the correct auth method.
Additionally, however, you will want to update the following settings as well:
# This setting changes the method which Active Admin calls
# to return the currently logged in user.
config.current_user_method = :current_admin_user
to
config.current_user_method = :current_user
and
# This setting changes the path where the link points to. If it's
# a string, the strings is used as the path. If it's a Symbol, we
# will call the method to return the path.
#
# Default:
config.logout_link_path = :destroy_admin_user_session_path
to
config.logout_link_path = :destroy_user_session_path
Of course, you don't HAVE to update these (or the method mentioned in the post), and just over-ride the methods elsewhere, but this seems to be the easiest / cleanest approach. You will obviously need to substitute "user" in each setting (current_USER) with the name of the model using devise authentication.
I would also recommend updating the following setting as well while you are in there:
# This setting changes the http method used when rendering the
# link. For example :get, :delete, :put, etc..
#
# Default:
config.logout_link_method = :get
to
config.logout_link_method = :delete
This last change is required if the default HTTP method used by your devise config is set to :delete, which it is unless you changed it. It matters that they are now synced because if you follow these instructions, you will be using destroy_user_session_path which is a path already defined by devise. Otherwise you will get a message stating that [GET] /users/sign_out route does not exist.
Here's the process if you have already installed ActiveAdmin with default settings, and you want to authenticate users with User.is_admin field on your existing model, and remove admin_user table:
Rollback admin_user migrations (if you didn't use --skip-users when installing Active Admin):
rake db:migrate:down VERSION=20141205110842 # create_active_admin_comments.rb
rake db:migrate:down VERSION=20141205110831 # add_devise_to_admin_users.rb
rake db:migrate:down VERSION=20141205110820 # devise_create_admin_users.rb
Then remove those 3 files.
In routing, remove the line devise_for :admin_users, ActiveAdmin::Devise.config
In application_controller.rb, add:
def authenticate_admin!
if current_user && current_user.is_admin
# fine
else
redirect_to new_user_session_path
end
end
In active_admin.rb:
config.authentication_method = :authenticate_admin!
config.current_user_method = :current_user
config.logout_link_path = :destroy_user_session_path
config.allow_comments = false
config.logout_link_method = :get # couldn't get active_admin to sign out via :delete. So I configure devise to sign out via :get.
To configure devise to sign out via :get, add in devise.rb:
config.sign_out_via = :get
# And for every occurrence of destroy_user_session_path, remove the option method: delete.
Create is_admin migration:
rails g migration add_is_admin_to_user is_admin:boolean
Edit the migration like so:
class AddIsAdminToUser < ActiveRecord::Migration
def change
add_column :users, :is_admin, :boolean, default: false
end
end
And migrate:
rake db:migrate
If in rails 4, don't forget to add is_admin in permit_params. In app/admin/user.rb:
permit_params ....., :is_admin
Add rights to admin users, in a console:
u = User.find(42); u.is_admin = true; u.save
Enjoy
All of what everyone else has said as well as in conjunction with the guide laid out at
http://dan.doezema.com/2012/02/how-to-implement-a-single-user-model-with-rails-activeadmin-and-devise/
that adds some additional bits on information if you are choosing to revert back to the option to have a single user model when you have already implemented an admin_user model (ie right now you have a 'user' as well as an 'admin_user' model).
The additional steps included
remove devise_for :admin_users, ActiveAdmin::Devise.config from routes.rb
copy code from app/admin/admin_user.rb to app/admin/user.rb (only use what is required)
delete app/admin/admin_user.rb (or you will get an Uninitialized constant error on AdminUser) like this guy had (and me as well).

test sign up with devise

Devise 1.2 ruby on rails
I'm having difficulty testing sign up. When the user clicks sign up, they're logged in and i should see a flash message. This works but my test fails. Not sure why. How does sign up work? is there some sort of internal redirect that happens? This step fails:
Then I should see "You have registered successfully. If enabled, a confirmation was sent your e-mail."
Confirmation is not enabled in my user model.
Tehcnically, you shouldn't feel the need to unit test the devise mechanism--the gem itself is well-tested. I can understand wanting to make sure it is behaving the way you configured it though, so:
Devise definitely redirects after a successful authentication. It will set the flash message and then redirect either to what you set as the root in your routes file, or if you attempted to access a page within the site and got redirected to the login page, it will redirect you back to the page you were trying to access.
For your test, try testing that you get redirected to what you set as root in your routes.rb fil. I.e. in the devise instructions, it says to set it like
root :to => "home#index"
So, in your test try something like this:
require 'spec_helper'
describe YourController do
include Devise::TestHelpers
before (:each) do
#user = Factory.create(:user)
sign_in #user
end
describe "GET 'index'" do
it "should be successful" do
get 'index'
response.should be_success
end
it "should redirect to root" do
get 'index'
response.should redirect_to(root_url)
end
end
You can add your flash message test to this as well. Hope this helps!