Rails controllers: halt action execution after render - ruby-on-rails

I have a Rails 4.0.2 controller action which is called by a method submission. Inside this method I check for a particular field to match a criteria and in case it is not matched, I want to present an error to the user and call render new again, without going any further within the method. So I wrote:
discount_coupon = DiscountCoupon.where(code: discount_code).first
if discount_coupon.nil? || (discount_coupon.present? && !discount_coupon.currently_active?)
flash[:alert] = t("flash.entries.create.invalid_coupon_code")
render :new
return
end
#entry.save
So, in my app when the discount_coupon variable is wrong and the program enters the conditional, it should halt its execution on return but somehow it does not and the #entry.save method is called and screws up the whole thing.
What am I doing wrong? I appreciate any help!

why don't you just enclose #entry.save with an else condition and remove return? so that if the discount coupon condition fails it renders the action :new else it just saves the entry.

As it's been suggested, try if/else conditional:
discount_coupon = DiscountCoupon.where(code: discount_code).first
if discount_coupon.nil? || (discount_coupon.present? && !discount_coupon.currently_active?)
flash[:alert] = t("flash.entries.create.invalid_coupon_code")
render :new
else
#entry.save
end
you can refactor this code once you are sure it is working.

Related

Checking record before update

Goal: To check if a record has already been updated and either allow or not allow the record to be updated if it already has been.
This is in case a buyer is on a page that doesn't have updated information and attempts to cancel an order once it's already been completed.
I have the following code, which works but also doesn't work correctly:
private
def prevent_order_update
#order = Order.find(params[:id])
if ( #order.order_status[2] || #order.order_status[3] )
redirect_to #order, notice: "Your request status for Order:#{#order.id} has already been updated."
end
end
with:
before_action :prevent_order_update, :only => [:update]
This works, but also "works" if the :order_status is 1, which is shouldn't.
I only want a block in the update IF the order status is anything but 1.
The order status is from a model enum of 1,2,3.
I have also tried using:
if ( #order.order_status[2] || #order.order_status[3] ) && #order.order_status_previously_changed?
which completely blocks the prevent_order_update from working all together.
And:
( #order.order_status[2] || #order.order_status[3] ) != #order.order_status[1]
Which then blocks my update method all together and still gives me the prevent_order_update method notice when the order status is 1
#order.order_status is corresponding to string when it comes to rails enums.
In your case, say #order.order_status is charged. When you execute #order.order_status[2] it actually produces a which is the third item of charged string. In this case the comparison always returns true.
So try the following code:
def prevent_order_update
#order = Order.find(params[:id])
if ( #order.charged? || #order.canceled? )
redirect_to #order, notice: "Your request status for Order:#{#order.id} has already been updated."
end
end
You can use aasm gem, so that you no need any before_action. You can solve it in model level using aasm transitions
https://github.com/aasm/aasm

Could not find record error while deleting record in Rails

I'm trying to delete a record by passing id of that record. The code looks like this:
def destroy_catalogue_entry
#catalogue_entry = CatalogueEntry.find(params[:catalogue_entry_id])
if #catalogue_entry.destroy
flash[:success] = 'Catalogue entry deleted successfully.'
else
flash[:error] = 'Failed...'
end
end
I'm getting an interesting error. When my function destroy_catalogue_entry is called it shows:
Couldn't find CatalogueEntry with 'id'=16
but as I comment If condition section and render #catalogue_entry as json, the output is printed successfully. So how is it possible? Am I making some silly mistake or is there logical reason. Please enlighten me.
Solved! All I did is this:
def destroy_catalogue_entry
#catalogue_entry = CatalogueEntry.find(params[:catalogue_entry_id])
if #catalogue_entry.destroy
flash[:success] = 'Catalogue entry deleted Successfully'
redirect_to action: :view_catalogue_entries, dc_id: #catalogue_entry.dc_id
else
flash[:success] = 'Failed...'
end
end
When I notice the console, the record was getting deleted successfully but after that there was a SELECT query for the same record, that is why it was throwing the error Couldn't find CatalogueEntry with 'id'=16. As I redirected it, the problem was solved.
I think destroy method is returning an object. In ruby anything other than false or null will be taken to true in if statement. You can do puts on destroy method and see what its returning.
i presume your,
#catalogue_entry = CatalogueEntry.find(params[:catalogue_entry_id])
is returning that error because it cant find CatalogueEntry with id 6, make sure you have CatalogueEntry with that id.

Add information to DB from the controller on rails

I'm trying to add the user id to 2 columns in the db after a user successfully submits a form. The commands run fine in the console but wont work in the controller. I haven't added info to the db straight from the controller before so I'm thinking that I'm doing something wrong.
Here is the create method
def create
#game = Game.friendly.find(params[:game_id])
#game_category = Game.friendly.find(#game.id).game_categories.new(game_category_params)
if current_user.mod_of_game? params[:game_id] && #game_category.save
Game.find(#game.id).game_categories.find(game_category.id).update(submitted_by: current_user.id)
Game.find(#game.id).game_categories.find(game_category.id).update(approved_by: current_user.id)
flash[:info] = "Game category added succesfully!"
redirect_to #game
else
render 'new'
end
end
These 2 lines are supposed to add the user id to the submitted_by and approved_by columns but they don't. I don't get any error messages, they simply just don't add anything to those columns
Game.find(#game.id).game_categories.find(game_category.id).update(submitted_by: current_user.id)
Game.find(#game.id).game_categories.find(game_category.id).update(approved_by: current_user.id)
If I replace the lines with coding that works in the console to see if its a variable or something thats not right it still doesn't work
Game.find(12).game_categories.find(55).update(submitted_by: 1)
Game.find(12).game_categories.find(55).update(approved_by: 1)
I'm building an app to learn rails and I guess this is something I just don't know.
Can anyone enlighten me on what I'm doing wrong?
Update:
Ok it is now giving me an error - Couldn't find GameCategory without an ID
So the #game_category.id isn't working?
It is a small typo in your query you missed #.
Game.find(#game.id).game_categories.find(#game_category.id).update(submitted_by: current_user.id)
After playing around tweaking it here and there it turns out to be this line
if current_user.mod_of_game? params[:game_id] && #game_category.save
when changed to this it works
if #game_category.save && current_user.mod_of_game? #game

Rails Activerecord: Update where conditions... else create

I need to check multiple columns of a table to see if I find a match. If I find a match I need to "updateattributes" of the matching record with all of my form params... Else I need to add a new record with all of my form params.
if #somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2])
if #somethingtoupdate = Model.update_attributes(params[:something])
redirect_to somewhere_path, :notice => "The existing record was updated"
else
render "myformlocation"
end
else
#added = Model.new(params[:something])
if #added.save
redirect_to somewhere_path, :notice => "The new record was created"
else
render "myformlocation"
end
end
Update
#somethingtoupdate = Model.where("this_id = ? and that_id = ?", params[:something][:this_id], params[:something][:that_id])
if ! #somethingtoupdate.empty?
if #somethingtoupdate.update_attributes(params[:something])
redirect_to some_path, :notice => "The existing record was updated"
else
render "myformlocation"
end
else
#added = Model.new(params[:something])
if #added.save
redirect_to some_path, :notice => "The new record was created"
else
render "myformlocation"
end
end
This is where I stand now thanks to #micahbf.
But, I am still getting an error on my "update_attributes" when there is a matching record.
Seems like this should work.... What am I missing or doing wrong?
This is because where does not return nil if it doesn't find anything, it returns an empty array, which is still truthy, so the block gets executed.
You can use empty? to check whether to run the block or not.
Note also that if it finds a match, the match will still be returned inside of an array (even if there was only one match). So you will have to do something like call first on the result to take the first returned model and update it.
So, the top might look like:
#somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2])
if ! #somethingtoupdate.empty?
if #somethingtoupdate.first.update_attributes(params[:something])
redirect_to some_path, :notice => "The existing record was updated"
else
render "myformlocation"
end
else
// do stuff if the query found no matches
end
I think here is short method to find record and if found then update record and if record not found then create it.
#somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2]).first_or_initialize
#somethingtoupdate.update_attributes(params[:something])
First of all, Model.update_attributes(params[:something]) is not working (at least in Rails 3.2.12). It should be #somethingtoupdate.update_attributes(params[:something]).
Also, there is an existing method for this kind of purpose: first_or_create.
#somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2]).first_or_create

Rails redirect_to not working

I have a filter_before filter that checks to see if a param is true. If it is my app does this. However, the && return seems to be causing some problems. When I take it out, it'll redirect form every page to the desired countdown page--but then it loops or double renders.
redirect_to :countdown && return if #online == 1
Is there a way to wrap this in an if statement?
Something like:
if current_page(:countdown)
redirect_to :countdown if #online == 1
end
You'd better exclude the countdown action from your before_filter to avoid infinite loop.
something like:
before_filter :check_countdown, :except => :countdown
That said, what you did is valid:
redirect_to :countdown and return if #online == 1
You need to use and instead of &&.
From the Rails Guide:
Make sure you use and return and not && return because while the
former will work, the latter will not due to operator precedence in
the Ruby Language.
http://guides.rubyonrails.org/layouts_and_rendering.html
It might be work for you
return redirect_to :countdown if #online == 1

Resources