Right let me explain a little in code, I'm trying to get the user to stay on the edit action until the user is completely valid. So far I have the following code in the application controller:
def check_privileges!
redirect_to "/users/edit" until current_user.valid?
end
registrations_controller.rb
before_filter :check_privileges!, only: [:new, :create]
jobs_controller.rb
before_filter :check_privileges!, only: [:index]
Now when I click on the link to jobs#index it gives me the following error. I cannot see a redirect in jobs#index
AbstractController::DoubleRenderError in JobsController#index
No clue how to sort this, I've tried and return but I cannot figure this out. I've been doing this all day as a user has to complete their profile before they have full access to the application.
Any clues, this is really bugging me now and I have no smart programming friends to help me.
I think what you want is unless not until... until will cause a loop of redirect_to (thus leading to multiple redirects) if the current_user is not valid.
Try:
def check_privileges!
redirect_to "/users/edit" unless current_user.valid?
end
Related
I got a really strange issue here. Here is the line causing all the trouble in my ability.rb
can [:edit, :update, :destroy], User, id: user.id
When I launch the rails console, I got the expected behaviour:
u = User.last
a = Ability.new(u)
a.can?(:edit, u)
=> true
a.can?(:edit, User.first)
=> false
However when I launch a web browser, log me in as a user and try to edit another one, CanCanCan remains silent.
If I replace can by cannot, I can't edit any user. It's as if it didn't lookup the condition.
My UsersController got this line on top
authorize_resource
I'm stuck with this, any help would be gladly appreciated.
cancancan 2.3.0
rails 5.2.1
Make sure that your instance (#user) is loaded before authorize_resource action runs, otherwise it will check if user can access some Users (can?(:edit, User), which is always true), instead of exact user.
before_action :load_user, except:[:index, :new, :create]
authorize_resource
...
private def load_user
#user = User.accessible_by(current_ability, action_name.to_sym).find(params[:id])
end
I have links in a users page where I keep getting redirected to home page if I'm not the signed in user.
routes.rb
resources :users, only: [:show] do
resources :interests, only: [:create]
member do
get 'interests'
get 'likes'
get 'followers'
get 'following'
end
end
views/users/show.haml
= link_to user_path do
User
= link_to likes_user_path do
Likes
= link_to followers_user_path do
Followers
= link_to following_user_path do
Following
If I'm viewing my own user page, all links work. But if I'm viewing someone else's page, only the user_path work correctly, but the other links just redirects me to home page as if I can't access it unless I'm the signed in user.
users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def show
#user = User.friendly.find(params[:id])
end
end
I find it odd that I don't even need to have a method for likes, following, and followers in my controller?
Those links are directing to these pages:
views/users/likes.haml
views/users/following.haml
views/users/followers.haml
Fix
I can't access it unless I'm the signed in user
The problem is you're calling before_action :authorize_user! on all the users_controller methods. This triggers the Devise user authentication check, which means that only logged-in users are able to view that page.
What you'll want is to limit the authentication to only the actions you want:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user, except: [:likes, :followers, :following]
end
This will only apply to the users controller -- interests should allow you, unless you're using authenticate_user! on there.
Misc
I find it odd that I don't even need to have a method for likes, following, and followers in my controller?
Rails 4+ has a built-in mechanism to load views regardless of whether the action is present or not.
--
Rails doesn't need index method in controller defined? (Docs):
By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your BooksController class:
class BooksController < ApplicationController
end
And the following in your routes file:
resources :books
And you have a view file app/views/books/index.html.erb:
<h1>Books are coming soon!</h1>
Rails will automatically render app/views/books/index.html.erb when you navigate to /books and you will see "Books are coming soon!" on your screen.
Notes
There are some fixes to your syntax:
Routes
Your routes can be DRYed up:
#config/routes.rb
resources :users, only: [:show] do
resources :interests, only: [:index, :create] #-> url.com/users/:user_id/interests
%i(likes followers following).each { |link| get link, on: :member #-> url.com/users/:id/likes }
end
Links
You should use the in-line style of link_to if you've only got a single string to output:
#app/views/users/show.haml
= link_to "User", user_path(user) #-> this should have a reference like user_path(user)
= link_to "Likes", likes_user_path(user)
= link_to "Followers", followers_user_path(user)
= link_to "Following", following_user_path(user)
This is because of the code in your user_controller
before_filter :authenticate_user!
This code will be executed for every controller actions and will be redirecting you to login page.Just add exceptions for the methods you want access directly without being login.
For more details on adding exceptions to methods in Rails please find the bellow SO threads.
1.before_filter with exception for current user
2.How to skip a before_filter for Devise's SessionsController?
I'm trying to set up something that allows users to go to certain urls only under certain circumstances. Right now I have a setEvent/:id url that sets a property on users to an event_id, then redirects the user to the event url. The user can access a url like .../whatever/event/1 where 1 needs to equal the event_id, and if it doesn't it redirects the user.
However, this doesn't stop someone from just typing .../whatever/setEvent/:id into their address bar to get access to the page.
The proper way to do this is with a before action in your controllers. Here is an example from one of my apps where a user who is not logged in will always be redirected to the new_session URL.
class ApplicationController < ActionController::Base
helper_method :current_user, :logged_in?, :herd_user
def herd_user
redirect_to new_session_url unless logged_in?
end
... other medthods...
end
and
class StaticPagesController < ApplicationController
before_action :herd_user
def index
end
end
without bringing in more gems you can just do a before_action
before_action :enforce_tenancy, except: [:index]
before_action :allow_only_admin, only: [:index]
private
def enforce_tenancy
render unauthorized unless event.user_id == current_user.id
end
def allow_only_admin
render no_way_sucka_path unless current_user.admin?
end
I had a similar problem and this might not be the best way to handle it but in the action for that page you can check the current url and check the property then redirect to the one they can access if they go to an incorrect url.
Something kind of like:
url_id = request.fullpath.sub('/whatever/event/', '')
redirect_to user_page_path(user.id) unless (current_user.event_id.to_s == url_id)
Sorry if the code isn't great I tried to write it based off of the info you gave.
Edit* Make sure to do this before getting any info for the page from your database or it will be less efficient.
i'd like to create settings page via activeadmin (edit/update).
https://github.com/huacnlee/rails-settings-cached.
But i faced that there is no way to register resource (not resources) in routes for particular page, eg have routes like /admin/settings, but not admin/settings/:id
inherit_resource has
defaults singleton: true
for this case, but this doesnt work for activeadmin.
Please help.
Otherwise, i can go with register_pagse way and create form myself and update action,but another problem appeared: how can i render errors messages on form from that update action.
The singleton way is way preferred.
You can always force the index action to redirect to the singleton resource that you want. While this is not a perfect solution, I have used it in the past. Something like this:
ActiveAdmin.register Setting, as: 'Setting' do
actions :all, only: [:show, :edit, :update, :index]
controller do
def index
redirect_to resource_path(Setting.first)
end
end
end
I'd like to write a custom method around Devise's edit profile page. I'd like it to be run before the edit page is loaded and after it is submitted. However, my code doesn't seem to be working:
class RegistrationsController < Devise::RegistrationsController
before_filter :check_tutor, only: :edit
private
def check_tutor
if current_user.is_tutor
current_user.build_tutor if current_user.tutor.nil?
else
current_user.tutor.destroy
end
end
end
Any ideas as to why this may be? Thanks!
Try adding edit action to this controller
def edit
super
end
For the filter to execute after the form is submitted, you will have to add
before_filter :check_tutor, only: [:edit, :update]
def update
super
end
For devise to pick up you controller you need to do following change in routes
devise_for :users, controllers: {registrations: "registrations"}
you might also want to consider an around_filter http://guides.rubyonrails.org/action_controller_overview.html#after-filters-and-around-filters. i'd show some sample code but i'm not sure if you're trying to build the tutor in the before and destroy it in the after [as needed] or are these actions supposed to run on both sides of the controller action.