I am having issues with devise current_user confusing my model's :id as the users :id.
routes:
match "/causes/:id/:slug" => "causes#show", :as => :cause, :via => 'get'
match "/causes/:id/:slug/edit" => "causes#edit", :as => :edit_cause, :via => 'get'
match "/causes/:id/:slug" => "causes#update", :via => 'put'
resources :causes, :only => [:index, :new, :create]
in my :causes controller:
before_filter :check_privileges, only: [:new, :create, :edit, :new, :update]
def check_privileges
#when I use this code everyone can access edit, etc.
redirect_to root_path unless current_user
end
and in my :causes model
belongs_to :user
For some reason, when I use current_user at all, in this controller, it always thinks that current_user is equal to the id in /causes/:id/:slug/
I have tried putting the check privileges code in the application controller,
I have even tried assigning code like this:
def check_privileges
#when I use this code no one can access edit, etc
#user = User.find_by_id(params[:id])
redirect_to root_path unless #user
end
I need help, anyone have suggestions? All I want it to do is verify the user is the current user so not everyone can edit the cause.
Your post is a bit confusing. IIRC devise stores the current user id in the session and does not ever get it from the url.
Seeing that this is a problem associated with privileges and rolling out your own solution. I would highly recommend an alternative.
https://github.com/ryanb/cancan
This works great with devise and should solve your problems
Related
I have a problem with the devise gem, I have this controller.
class AdminController < ApplicationController
before_action :authenticate_user!
def index
end
def per
end
def po
end
end
When redirect to sign_in form , shows nothing
sign_in form
These are my routes:
match 'po' => 'admin#po', :via => :get
match 'per' => 'admin#per', :via => :get
match 'admin' => 'admin#index', :via => :get
match 'admin/index' => 'admin#index', :via => :get
match 'admin/per' => 'admin#per', :via => :get
match 'admin/po' => 'admin#po', :via => :get
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
root 'home#index'
I have three templates: application, admin and home
I overwrite the default route after log in
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
#before_action :authenticate_user!
def after_sign_in_path_for(resource)
#request.env['omniauth.origin'] || stored_location_for(resource) || admin_path
admin_path
end
end
My last gem installed:
gem 'bootstrap-sass'
You need to run the generator for Devise views which will copy the necessary files in your views folder:
Run:
rails g devise:views
There is more information on configuring the Devise views here
Your problem probably isn't with Devise, it looks systemic to me.
#config/routes.rb
namespace :admin do
root "application#index" #->
resources :model_controller, path: "", only: :index do #-> url.com/admin/...
collection do
get :po #-> you shouldn't really have this
get :per #-> you shouldn't really have this
end
end
end
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
This will give you the following:
#app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ApplicationController
before_action :authenticate_user!
def index
# do something here
end
end
This gives you the ability to create a custom "dashboard" type page for your admin area, from which you'll be able to use controllers bound to models.
Your po and per actions really shouldn't be there - they are not part of the CRUD system
In regards to your Devise views, the other answers are correct in that you would be best to generate the Devise views in your app:
rails generate devise:views
This won't solve your problem (hence why I downvoted the other answers). It will simply put the views in your app. It will do nothing apart from put code in a different place.
You will need to debug the issue:
Check the action you're seeing at /users/sign_in
Check the code in the <body> tags (which you haven't shown)
If the HTML is there, there will be some other issue preventing it from loading
If there is no HTML, it will likely mean a problem with the core of Devise
What I would recommend you do is the following:
Generate your views
From your screenshot, show us the contents of the <body> tag
Screenshot your console log (this will show any errors)
Update your question with the above
This will give you a much clearer perspective on what the potential issue will be, and allow other community members to better define the solution.
I've got these three bottom routes below which are very error-prone because of other routes declared normally:
# normal routes
resources :documents, :except => [:show, :edit, :update]
resources :photos, :except => [:show, :index]
...
# error-prone routes
get ":client_code" => "share#index", :as => :shares, :format => false
get ":client_code/:id" => "share#show", :as => :share, :format => false
get ":client_code/:document_id/more/:component_id" => "share#more", :as => :more, :format => false
I've got a few methods in the ShareController to deal with the requests like so:
def show
get_user_by_parameter
if get_document_by_user_or_issue and #document.is_showable? and #parameter_user == #document.user
...
end
private
def get_user_by_parameter
#parameter_user = User.where(:client_code => params[:client_code]).first
end
def get_document_by_user_or_issue
if params[:id].match(/\D/)
#document = Document.where(:user_id => #user.id, :issue => params[:id]).first
else
#document = Document.find(params[:id])
end
end
I need the routes to be that minimal, but not only is this ugly and un-RESTful but it's very error prone.
The :client_code will always be the owner of the #document being viewed. It's kinda like a safety check/ownership kinda function. But, because of all the reasons listed above: is there a better way to write this? There's gotta be a better way than that.
Thanks.
Controller Based Check:
before_filter :find_document
def find_document
Document.find(params[:id])
end
def is_owner?(document)
redirect_to root_path if current_user.id != document.owner_id
end
Isn't a check like this much easier? I'm not sure why you have a share controller, so I don't want to be presumptuous here.
Which will allow you to do:
resources :shares, only: [:index, :show]
Also:
User.where(:client_code => params[:client_code]).first
Can be refactored to:
User.find_by(client_code: params[:client_code])
Assuming you are on latest rails version, else:
User.find_by_client_code(params[:client_code])
Let me know what the shares are for, I'm not sure I provided the full solution for you.
Cheers.
EDIT
if you are using shares to provide a different view, i suggest doing this:
Within the controller,
def index
if params[:shares]
render 'shares'
end
end
Unless you really wish to have a different route for it. This allows you to not have a shares controller for essentially what is the document model.
I have a controller where:
caches_action :show
cache_sweeper :the_model_sweeper, :only => [:update, :destroy]
and sweeper:
observe TheModel
def after_save(the_model)
expire_cache(the_model)
end
def after_destroy(the_model)
expire_cache(the_model)
end
def expire_cache(the_model)
expire_action :controller => '/the_model', :action => 'show'
end
and am getting:
ActionController::RoutingError (No route matches {:controller=>"/the_model", :action=>"show"}):
The problem I'm guessing is becuase the sweeper is called after_save, when on a new record there will be nothing to destroy, even though I have specifically said for it only to sweep on update or delete.
(I have obviously renamed the model to "The Model" for example purposes)
The problem was due to using ActiveAdmin, and forgetting (doh...) to add :only => [:update, :destroy] to the active admin config for that model
I have two models for users ; the Plans model has_many users. Now, what I would like to do is to allow users to upgrade/downgrade their plans, by changing the plan_id. I've set up a form, as well as the appropriate action, but when I hit submit, it doesn't seem to do what the PUT action says. It seems to use the update action.
Here's my form :
<%= form_tag("/users/update_plan", :method => "put" ) do %>
<%= hidden_field_tag :plan_id, plan.id %>
<%= submit_tag("Change To Plan", :class => "signup") %>
<% end %>
Here's my update action
def update_plan
#user = current_user
#user.plan_id = params[:plan_id]
#user.save
sign_in #user
redirect_to change_plan
end
When I submit the form above though, it not only doesn't register the change, but I think it uses the update action, and not the update_plan action. The reason I think this is because it redirects to the what's in the update action, and it flashes the same thing as the update action.
def update
#user = current_user
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to edit_user_path(#user)
else
render 'edit'
end
end
Here's my routes.rb file
Dentist::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :phones, only: [:new, :create, :destroy]
resources :find_numbers, only: [:new, :create, :destroy]
put 'users/update_plan'
match '/signup', to: 'users#new'
match '/login', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/change_plan', to: 'users#change_plan'
root to: 'static_pages#home'
match '/product_demo', to: 'static_pages#product_demo'
match '/pricing', to: 'plans#index'
match '/contact', to: 'static_pages#contact'
And here's a console screenshot of what's happening:
http://stepanp.com/debug3.jpg
It seems to say it's using the update_plan action, but... :S
Any help on trying to get Update_plan action to function would be greatly appreciated!
The form is going to the right place (/users/update_plan), but that is being routed to:
UsersController#update
as it says on the second line of your console log. So not the action you expect, and the problem is in your routes. Try this to list all your routes:
rake routes
Probably the users update route (created by resources :users) is catching this first:
PUT /users/:id(.:format) users#update
There are no restrictions on the content of id, and format is optional, so users/update_plan would call users/update with an id of update_plan (in fact you can see that is happening at the edge of your console log screenshot, look for the :id => parameter).
So I would move your custom route to the top of the routes file first above resources :users, and also try change it to direct to the action you want, not sure what a route with no action specified does...
put '/users/update_plan', to: 'users#update_plan'
I want to give authorization to a specific action if a session variable is set in my app. I can't figure out how to do this. Something like:
has_permission_on :admin, :to => :action do
true if session[:key]
end
I don't understand how to accomplish this basic task. Any help appreciated.
You want to use a before_filter on the function e.g.
before_filter :authorize, :only => :action
private
def authorize
unless session[:key]
flash[:notice] = "Cannot do this"
redirect_to(:controller => "controller", :action => "otheraction")
end