I am working with the following piece;
def index
#user = User.find(params[:id])
rescue
flash[:notice] = "ERROR"
redirect_to(:action => 'index')
else
flash[:notice] = "OK"
redirect_to(:action => 'index')
end
Now I either case whether I have a correct ID or not, I am always getting "OK" in my view, what am I doing wrong?
I need that when I have no ID in the DB to show "ERROR". I have also tried to use rescue ActiveRecord::RecordNotFound but same happens.
All help is appreciated.
All code after the end of the rescue block is interpreted only if there are no returns in the rescue block. So you can call return at the end of your rescue block.
def index
begin
#user = User.find(params[:id])
rescue
flash[:notice] = "ERROR"
redirect_to(:action => 'index')
return
end
flash[:notice] = "OK"
redirect_to(:action => 'index')
end
or
def index
#user = User.find(params[:id])
# after is interpret only if no exception before
flash[:notice] = "OK"
redirect_to(:action => 'index')
rescue
flash[:notice] = "ERROR"
redirect_to(:action => 'index')
end
But in your case the better is to use rescue_from or rescue_in_public
like
class UserController < ApplicationController
def rescue_in_public(exception)
flash[:notice] = "ERROR"
redirect_to(:action => 'index')
end
def index
#user = User.find(params[:id])
flash[:notice] = "OK"
redirect_to(:action => 'index')
end
end
But the using of rescue_in_public is not really good advice
Just an overall Rails Rescue answer:
I found this to be very cool:
#user = User.find(params[:id]) rescue ""
If there is no user with that id, then User.find will return nil. Returning nil is not an error case and will not trigger a rescue.
Related
In my rails app I have this bit of logic in my SessionsController's create method that I want to refactor out by extracting it into a method:
if login_form.validate(params[:user])
begin
#user = User.find_by!(email: params[:user][:email])
rescue ActiveRecord::RecordNotFound => e
flash.now.alert = 'invalid user credentials'
render :new and return
end
else
flash.now.alert = login_form.errors.full_messages
render :new and return
end
All this does is check if user exists in the system. I want to refactor this into
if login_form.validate(params[:user])
find_user
else
flash.now.alert = login_form.errors.full_messages
render :new and return
end
And then the private find_user method:
private
def find_user
begin
#user = User.find_by!(email: params[:user][:email])
rescue ActiveRecord::RecordNotFound => e
flash.now.alert = 'invalid user credentials'
render :new and return
end
end
But now after I do this, the ActiveRecord::RecordNotFound exception is ignored! The method does not stop at the return command. Why is that? What am I doing wrong?
UPDATE:
I understand what I am doing wrong. But how do I do this in the right way?
The return statement just returns from the function where it is called, that is the find_user method.
Ok so I can use a block like so:
if login_form.validate(params[:user])
find_user do
flash.now.alert = 'invalid user credentials'
render :new and return
end
else
flash.now.alert = login_form.errors.full_messages
render :new and return
end
And then refactor the private method like so:
def find_user(&block)
begin
#user = User.find_by!(email: params[:user][:email])
rescue ActiveRecord::RecordNotFound => e
yield
end
end
can you help my to fix my problem. I can save data if the user is managing partner but when I choose other roles, (like secretary), I can't save data to the database.
I think, there's a problem here. This is my codes:
def profile
#office = Office.last
#partial = (params[:type].present?) ? params[:type] : "work_data"
#user = User.find(params[:id])
#user.is_managing_partner = true if current_user.role == 'managing partner'
end
def update_profile
#office = Office.last
#user = User.find(params[:id])
#user.is_managing_partner = true
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
case params[:type]
when 'work_data'
redirect_to profile_user_path(type: "personal_data")
when 'personal_data'
redirect_to root_path
end
else
#partial = (params[:type].present?) ? params[:type] : "work_data"
render json: #user.errors, status: :unprocessable_entity
end
end
and this is my application_controller.rb
rescue_from CanCan::AccessDenied do |exception|
#office = Office.last
#user = User.find(params[:id])
if #user == current_user
#partial = (params[:type].present?) ? params[:type] : "work_data"
authorize! :read, #user
render 'profile'
else
flash[:warning] = "Access Denied."
redirect_to root_url
end
end
and this is my ability.rb
if user.role == 'managing partner'
can :manage, :all
else
if user.role == "secretary"
can :update, :user_id => user.id
end
can :read, :all
end
In your ability.rb the 'can :update, :user_id => user.id' row is wrong. You have to specify WHAT he can update:
can :update, WHAT, :user_id => user.id
How can I refactor the following controller fetch action, also how to use local variable(website not #website, local because it doesn't have a view) in fetch action and start_fetching method
def fetch
#website = Website.find(params[:website_id])
retun redirect_to :back, :alert => t('crawl_counter_error') if #website.fetch_counter < 1
authorize! :update, #website, :message => t("website_authorize_error")
#website.confirmed? || #website.confirmed_key? ? start_fetching : flash[:error] = t('key_error')
redirect_to :back
end
private
def start_fetching
if #website.working_status
flash[:error] = t('crawling_in_progress_error')
else
#website.start_fetch
flash[:notice] = t('crawler_success_notice')
end
end
This might be a bit cleaner
# controller
def fetch
website.find(params[:website_id])
authorize! :update, website, :message => t("website_authorize_error")
status = website.fetch
flash[status[:type]] = t(status[:message])
redirect_to :back
end
# move to model/website.rb
def fetch
status = nil
if (fetch_counter < 1)
status = {:error, 'crawl_counter_error'}
elsif confirmed? || confirmed_key?
status = {:error, 'key_error'}
elsif working_status
status = {:error, 'crawling_in_progress_error'}
else
start_fetch
status = {:notice, 'crawler_success_notice'}
end
status
end
I want to redirect_to slider_path after a user submits their email. Currently, only the success message is displayed without a redirect. Here's the code:
class Splash::SubscribersController < ApplicationController
def create
#subscriber = Subscriber.new(params[:subscriber])
if #subscriber.save
success = true
message = "Success! We'll let you know when we launch."
else
success = false
message = "Fail."
end
respond_to do |format|
format.html {
if success
flash[:success] = message
redirect_to slider_path
else
flash[:error] = message
end
redirect_to root_path
}
format.json { render :json => { :success => success, :message => message }.to_json }
end
end
end
Just replace this part of your code:
if success
flash[:success] = message
redirect_to slider_path
else
flash[:error] = message
end
redirect_to root_path
with this:
if success
flash[:success] = message
redirect_to slider_path
else
flash[:error] = message
redirect_to root_path
end
Rails API states:
An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:
def do_something
redirect_to :action => "elsewhere"
render :action => "overthere" # raises DoubleRenderError
end
If you need to redirect on the condition of something, then be sure to add “and return” to halt execution.
def do_something
redirect_to(:action => "elsewhere") and return if monkeys.nil?
render :action => "overthere" # won't be called if monkeys is nil
end
Note the use of and return
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".
Add a return statement after your redirect. If the action also renders a template by default, any redirects need to be followed by a return statement.
if success
flash[:success] = message
redirect_to slider_path
return # <= Add a return.
else
flash[:error] = message
end
redirect_to root_path
I have ambethia's reCAPTCHA plugin on Rails 3 working. Does anyone know how to override it's flash message markup? I'd like to reuse my own flash_error div id instead of using the plugin's flash_recaptcha_error div id:
<div id="flash_recaptcha_error">incorrect-captcha-sol</div>
Also, how would you clean up this controller#create?
def create
#post = Post.new(params[:post])
respond_to do |format|
if verify_recaptcha(:model => #post, :error => "reCAPTCHA incorrect. Try again.") && #post.save
flash.now[:notice] = "Created \"#{#post.title}\""
format.html { redirect_to(#post, :notice => 'Post was successfully created.') }
else
flash.now[:error] = "Incorrect word verification. Are you sure you\'re human?"
format.html { redirect_to(:back, :error => 'reCAPTCHA incorrect. Try again.') }
end
end
end
Thanks for reading my question.
Because flash[] is an array you could delete element inside it. When we use recaptcha gem, the flash array contain recaptcha_error element, so you just only delete this element with :
flash.delete(:recaptcha_error) inside your controller.
For example :
if verify_recaptcha(:model=>#object,:message=>"Verification code is wrong", :attribute=>"verification code") && #object.save
#your code if succes
else
flash.delete(:recaptcha_error)
#your code if its fail
end
Maybe it could help you. Thanks
If you're making a User Authentication System from scratch, you may have to do something like this:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
respond_to do |format|
if verify_recaptcha(:model => #user )
if #user.save
format.html { redirect_to root_url, :notice => "You have Signed up!" }
else
format.html { render :new }
end
else
flash.delete(:recaptcha_error)
format.html { redirect_to( root_path , :flash => { :error => 'Please retry the two words of the reCaptcha' } ) }
end
end
end
end