Rails doesn’t persist flash message key after destroy action - ruby-on-rails

I use Rails 4, and have four methods at my application_controller.rb for setting flash messages in Rails
def exclusion_info_for model_name
flash[:notice] = "#{model_name.to_s.capitalize} has been deleted."
end
def creation_notice_for model_name
flash[:notice] = "#{model_name.to_s.capitalize} has been created."
end
def update_notice_for model_name
flash[:notice] = "#{model_name.to_s.capitalize} has been updated."
end
def error_notice
flash[:error] = "An unexpected error has it occurred"
end
But the flash setting at exclusion_notice_for is lost after redirection of the action destroy. The others methods works normally.
The Controller
class CustomersController < ApplicationController
respond_to :html
def new
respond_with #customer = customer
end
def create
if #customer = Customer.create(customer_attrs)
creation_notice_for :customer
else
error_notice
end
respond_with #customer, location: "/"
end
def show
respond_with #customer = customer
end
def index
respond_with #customers = Customer.all
end
def edit
respond_with #customer = customer
end
def update
if #customer = customer.update(customer_attrs)
update_notice_for :customer
else
error_notice
end
respond_with #customer, location: "/"
end
def destroy
if #customer = customer.destroy()
exclusion_info_for :customer
else
error_notice
end
respond_with #customer, location: "/"
end
private
def customer
id ? Customer.find(id) : Customer.new
end
def customer_attrs
params.require(:customer).permit(:name)
end
end
This is the application destroy button currently genereted
This is the application.rb file
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: :null_session
# protect_from_forgery with: :exception
include FormattedTime
def form_parent
ObjectSpace._id2ref(params[:form_parent_object_id].to_i) if params[:form_parent_object_id]
end
helper_method :form_parent
def root
render "layouts/application", layout: false
end
protected
def id
params[:id]
end
# refactored
def info_flashed model_name, action
flash[:notice] = "#{model_name.to_s.capitalize} has been #{action}."
end
def error_notice
flash[:error] = "An unexpected error has it occurred"
end
end

Flashing Method will work all of your actions simply add 'created' or 'updated' string like in destroy method.
You had error Can't verify CSRF token authenticity
You can put this method in application.rb file to fix it all.
protect_from_forgery with: :exception, if: Proc.new { |c| c.request.format != 'application/json' }
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
protected
def info_flashed (model_name, action)
flash[:notice] = "#{model_name.to_s.capitalize} has been #{action}."
end
In Controller
def destroy
if #customer = customer.destroy
info_flashed (#customer, 'deleted')
else
error_notice
end
respond_with #customer, location: "/" # you need to redirect correct path.
end

Related

the AbstractController::DoubleRenderError cannot be fixed with "redirect_to and return"

I got this error today when I tried to use some helper methods for the users controller:
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and
at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need
to do something like "redirect_to(...) and return".)
I put this following helpers in application_controller.rb :
class ApplicationController < ActionController::Base
def current_user
User.find_by :id=>session[:user_id]
end
def log_in?
!!session[:user_id]
end
def log_in_first
if !log_in?
session[:error]="You have to log in first to continue your operation"
redirect_to("/login") and return
end
end
def correct_user?
if !(current_user.id.to_s==params[:id])
session[:error]="You have no right to do this operation."
redirect_to "/"
return
end
end
end
and here is the user_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id]=#user.id
redirect_to user_path(#user)
else
render 'new'
end
end
def show
log_in_first
#user = User.find_by id: params[:id]
correct_user?
if #user
render 'show'
else
redirect_to '/login'
end
end
private
def user_params
params.require(:user).permit(:name,:password,:email,:email_confirmation)
end
end
As you can see I tried to use both return and and return in log_in_first and correct_user?to fix the problem but it still doesn't work. Does anyone have any ideas?
The problem is in the show action, log_in_first redirects then the show action does whatever it wants, which is redirect or render. This is causing the error.
A better solution is to use before_action for your authentication and authorization and just let the user controller actions do their thing. Something like the below.
class ApplicationController < ActionController::Base
def current_user
User.find_by :id=>session[:user_id]
end
def log_in?
!!session[:user_id]
end
def authenticate_user!
if !log_in?
session[:error]="You have to log in first to continue your operation"
redirect_to("/login")
end
end
def authorize_user!
unless current_user&.id.to_s==params[:id]
session[:error]="You have no right to do this operation."
redirect_to "/"
end
end
end
class UsersController < ApplicationController
before_action :authenticate_user!, only: [:show]
before_action :authorize_user!, only: [:show]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id]=#user.id
redirect_to user_path(#user)
else
render 'new'
end
end
def show
#user = User.find_by id: params[:id]
render 'show'
end
private
def user_params
params.require(:user).permit(:name,:password,:email,:email_confirmation)
end
end

pundit rails 5 can't enforce create method restrictions

everytime I submit a form here (that I scaffolded) localhost:3000/syllabus_requests/new
The rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
from my ApplicationController.rb file gets raised and I'm not sure why because in the policy class I have a create? method and it returns true
i'm using
ruby '2.3.1'
gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
gem 'pundit', '~> 1.1'
I have a policy
class SyllabusRequestPolicy < ApplicationPolicy
attr_reader :current_user, :model
def initialize(current_user, model)
#current_user = current_user || User.new
#model = model #this is the syllabus_request record from the syllabus_requests table as a rails model object
end
def index?
#current_user.role == "admin"
end
def show?
#current_user.role == "admin"
end
def create?
true
end
def edit?
#current_user.role == "admin"
end
def update?
#current_user.role == "admin"
end
def destroy?
#current_user.role == "admin"
end
end
I have a controller
class SyllabusRequestsController < ApplicationController
before_action :set_syllabus_request, only: [:show, :edit, :update, :destroy]
# GET /syllabus_requests
# GET /syllabus_requests.json
def index
#syllabus_requests = SyllabusRequest.all
authorize #syllabus_requests
end
# GET /syllabus_requests/1
# GET /syllabus_requests/1.json
def show
authorize #syllabus_request
end
# GET /syllabus_requests/new
def new
#syllabus_request = SyllabusRequest.new
authorize #syllabus_request
end
# GET /syllabus_requests/1/edit
def edit
authorize #syllabus_request
end
# POST /syllabus_requests
# POST /syllabus_requests.json
def create
#syllabus_request = SyllabusRequest.new(syllabus_request_params)
authorize #syllabus_request
respond_to do |format|
if #syllabus_request.save
format.html { redirect_to #syllabus_request, notice: 'Syllabus request was successfully created.' }
format.json { render :show, status: :created, location: #syllabus_request }
else
format.html { render :new }
format.json { render json: #syllabus_request.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /syllabus_requests/1
# PATCH/PUT /syllabus_requests/1.json
def update
authorize #syllabus_request
respond_to do |format|
if #syllabus_request.update(syllabus_request_params)
format.html { redirect_to #syllabus_request, notice: 'Syllabus request was successfully updated.' }
format.json { render :show, status: :ok, location: #syllabus_request }
else
format.html { render :edit }
format.json { render json: #syllabus_request.errors, status: :unprocessable_entity }
end
end
end
# DELETE /syllabus_requests/1
# DELETE /syllabus_requests/1.json
def destroy
authorize #syllabus_request
#syllabus_request.destroy
respond_to do |format|
format.html { redirect_to syllabus_requests_url, notice: 'Syllabus request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_syllabus_request
#syllabus_request = SyllabusRequest.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def syllabus_request_params
params.require(:syllabus_request).permit(:full_name, :email)
end
end
my ApplicationPolicy.rb file looks like this
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
binding.pry # this should not hit if I'm overriding it
false
end
def new?
binding.pry
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
My ApplicationController.rb looks like this
include Pundit
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
private
def user_not_authorized
# binding.pry
flash[:alert] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path)
end
end
Did you try to add a new? method in your SyllabusRequestPolicy ?

Multi user in devise + Rails

I want to create multi user application. Admin user can create new users. how can i do this using devise. Because when after login as admin user i want add new user devise show error that "you are already signed in". How i do this using devise.
I was able to create the Admin User and logged in
User-Controller
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Successfully created User."
redirect_to root_path
else
render :action => 'new'
end
end
def user_params
params.require(:user).permit(:email, :username, :password, :password_confirmation,:propic)
end
end
Admin Controller
class ClientsController < ApplicationController
skip_before_filter :authenticate_user!, only: [:index, :new, :create]
def new
#client = Client.new
#client.build_owner
render layout: 'sign'
end
def index
#clients = Client.all
render layout: 'welcome'
end
def create
#client = Client.new(client_params)
if #client.valid? then
Apartment::Tenant.create(#client.subdomain)
Apartment::Tenant.switch(#client.subdomain)
#client.save
redirect_to new_user_session_url(subdomain: #client.subdomain)
else
render action: 'new'
end
end
private
def client_params
params.require(:client).permit(:name, :subdomain, owner_attributes: [:email, :username, :password, :password_confirmation,:propic])
end
end
Application Controller
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_filter :load_tenant
before_filter :authenticate_user!
#rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
private
def record_not_found
render 'record_not_found'
end
def load_tenant
Apartment::Tenant.switch(nil)
return unless request.subdomain.present?
client = Client.find_by(subdomain: request.subdomain)
if client then
Apartment::Tenant.switch(request.subdomain)
else
redirect_to root_url(subdomain: false)
end
end
def after_signout_path_for(resource_or_scope)
new_user_session_path
end
end
Anyone? I am super new to Ruby on Rails. All the code is the result of hefty trial and errors.

Trouble Creating and showing Users in Rails blog

I keep getting a variety of error while trying to create and show errors in a simple Rails blog I'm trying to create.Let me know if you see anything obvious or if you need me to post more code as I've tried a number of things but to no avail. Thanks
The browser is giving me this error
Couldn't find User without an ID
in my "logged_in?" method which shows
def logged_in?
#current_user ||= User.find(session[:user_id])
end
Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
flash[:success] = "You are logged in"
redirect_to root_path
else
render action: 'new'
flash[:error] = "There was a problem logging in. Please check your email and password"
end
end
end
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def edit
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
flash[:notice] = "You have registered, please login"
redirect_to login_path
else
render :new
end
end
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
Articles Controller
class ArticlesController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
def new
#article = Article.new
end
def index
#article = Article.all
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def show
#article = Article.find(params[:id])
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text, :image)
end
end
Application Helper
module ApplicationHelper
def logged_in?
#current_user ||= User.find(session[:user_id])
end
end
The problem you're facing is that session[:user_id] is nil. Usually a method which sets current user is called current_user. The logged_in? is not a good name for a method setting an user instance, because one would expect that a method ending with a question mark would return a true or false. And not an user instance.
Also, setting the current user is usually done with a before_filter. Additionally, you want to skip such before filter for action where you're setting the current user (i.e the current_user doesn't exist yet)
Finally, I would rather fail gracefully, if user is not found. You can achieve this by changing your code to User.find_by_id(session[:user_id])
While the user is not loggued, session[:user_id] is nil, and so User.find(session[:user_id]) generates the error. The method should be like this:
def logged_in?
#current_user ||= User.find(session[:user_id]) if session[:user_id].present?
end
Why would the logged_in? helper method try to assign a value to #current_user? I think that is a bad logic, it should just return a boolean result without modifying such a central instance. This is a proper way to do that:
def logged_in?
#current_user.nil? ? false : true
end
The responsibility of setting the #current_user falls to a method that you should place in application_controller.rb and make it a before_action so that it's executed before any controller action is triggered, that is:
# app/controllers/applicaton_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_action :authenticate_user
# Your actions here
..
..
#
private
def authenticate_user
#current_user ||= User.find(session[:user_id]) if session[:user_id].present?
end
end

Syntax error for permission.rb

I am not able to solve this syntax error I have on permission.rb. It says it needs a extra "end" but when I do add it Safari is unable to load the page. I have tried several different methods on both files, none seem to work. Any ideas?
Error:
SyntaxError in UsersController#new
/Users/lexi87/dating/app/controllers/application_controller.rb:20: syntax error, unexpected keyword_end, expecting end-of-input
Rails.root: /Users/lexi87/dating
Application Trace | Framework Trace | Full Trace
app/controllers/users_controller.rb:1:in `<top (required)>'
permission.rb (without the extra 'end'):
class Permission < Struct.new(:user)
def allow?(controller, action)
if user.nil?
controller == "galleries" && action.in?(%w[index show])
elsif user.admin?
true
else
controller == "galleries" && action != "destroy"
end
end
application_controller:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def current_permission
#current_permission || ::Permission.new(current_user)
end
end
def authorize
if !current_permission.allow?(params[:controller], params[:action])
redirect_to root_url, alert: "Not authorized."
end
end
end
UPDATE
Here's my users_controller:
class UsersController < ApplicationController
before_filter :authorize
def new
#user = User.new
end
def profile
#profile = User.profile
end
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def index
#users = User.all
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted."
redirect_to users_url
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Account updated"
redirect_to #user
authorize! :update, #user
else
render 'edit'
end
end
end
It looks like you need another end in permission.rb and you need to move one in application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def current_permission
#current_permission || ::Permission.new(current_user)
end
end # this shouldn't be here
def authorize
if !current_permission.allow?(params[:controller], params[:action])
redirect_to root_url, alert: "Not authorized."
end
end
# it should be here
corrections
1.
You definetely need the end at the end of the permission.rb
2.
you do not need and end to end the private section of ApplicationController. Everything below the private keyword is considered 'private'. So you need to move the "authorize" method.
solution
So the complete code is (with moving one method into "public"):
permission.rb:
class Permission < Struct.new(:user)
def allow?(controller, action)
if user.nil?
controller == "galleries" && action.in?(%w[index show])
elsif user.admin?
true
else
controller == "galleries" && action != "destroy"
end
end
end
application_controller:
class ApplicationController < ActionController::Base
protect_from_forgery
def authorize
if !current_permission.allow?(params[:controller], params[:action])
redirect_to root_url, alert: "Not authorized."
end
end
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def current_permission
#current_permission || ::Permission.new(current_user)
end
end
You don't have to close the private keyword.
The end after
def current_permission
is not necessary !

Resources