Deleting group of elements in rails - ruby-on-rails

I have an Event model and every event has user_id, and i want to delete all of them by one click.
def destroy
#events.destroy
respond_to do |format|
format.html { redirect_to events_url, notice: 'Event was successfully destroyed.' }
format.json { head :no_content }
end
end
I know that i need firstly to find all of them by user_id, but don't know how to delete than. Can someone help?

I hope your user model have has_many :events Association if this is the case then you can try following.
def destroy
user = User.find(1) # Or User.find(params[:user_id])
#events = user.events.where(title: "FIRST")
# Or If you just wanted to delete all Events except deleting user events then #events = Event.where(title: "FIRST")
#events.destroy_all
respond_to do |format|
format.html { redirect_to events_url, notice: 'Event was successfully destroyed.' }
format.json { head :no_content }
end
end

You can use destroy_all(conditions = nil). Code would look something like this:
def destroy
respond_to do |format|
if Event.destroy_all(:user_id => params[:user_id])
format.html { redirect_to events_url, notice: 'Events were successfully destroyed.' }
else
format.html { redirect_to events_url, notice: 'Events could not be deleted. Try again' }
end
end
end
Or instead of: Event.destroy_all(:user_id => params[:user_id]), if you have User object then you can do:
#user.events.destroy_all

destroy(single object)/:destroy_all(for collection) The associated objects are destroyed alongside this object by calling their destroy method
delete(single object)/:delete_all(for collection) All associated objects are destroyed immediately without calling their :destroy method
You can use any one of them according to your conditions
Event.destroy_all(conditions)
To destroy all methods with specific conditions.

Event.destroy_all(:user_id => params['user_id'])
or
Event.where(:user_id => id).destroy_all
This will destroy all events which belongs to that user_id

Related

Rails redirect to the post after a comment is made

I have a comment form on my tickets show page. I can fill it out, but when submitting the comment, it goes to the comments show page. I need this to just go back to the ticket it was showing.
I have this code at the moment:
comment_controller.rb
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
and a similar thing with the destroy method
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_path, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
I'm not sure how to get it to remember which ticket it was on, for it to redirect to.
I have entered the associations with the models with ticket.rb and comments.rb
You can just replace the
redirect_to comments_path
with
redirect_to :back
# or
redirect_to(:back)
which after the comment is made, it returns to the previous page
If you're using rails 5, use
redirect_back(fallback_location: root_path)
instead

Rails 4 - Delete rows from another table before updating

I have the following code in my members controller:
def update
#member.phone_numbers.destroy_all
respond_to do |format|
if #member.update(member_params)
format.html { redirect_to #member, notice: 'Member was successfully updated' }
else
format.html { render action: 'edit' }
end
end
end
I have to delete existing records from phone_numbers before updating members, because the phone numbers must be inserted again (because of possible ordering changes and other reasons, but it does not matter).
The question is: It works, but if members fail to update, all the phone numbers will be already deleted.
What could be done to avoid the problem if the #member.update fails?
You may consider marking the phone numbers for destruction instead of actually deleting them.
#member.phone_numbers.map(&:mark_for_destruction)
Then, when you do #member.update, it should do the update and the destruction of the associated phone numbers all at once. Here's the API for #mark_for_destruction: http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html#method-i-mark_for_destruction
Otherwise, you can look into setting up a transaction block. The API explains this well enough: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
Wrap this into a helper method that wraps the statements into a transaction and call from the controller:
# Member Model
def delete_phone_numbers_and_update(params)
Member.transaction do
phone_numbers.destroy_all
update(params)
end
end
# Controller
def update
respond_to do |format|
if #member.delete_phone_numbers_and_update(member_params)
format.html { redirect_to #member, notice: 'Member was successfully updated' }
else
format.html { render action: 'edit' }
end
end
end

Rails Device and has_many association with promotions privilege

I have two models User and Promotion, an user can create has_many promotion and an promotion belong to user,
for the users i used devise so:
when I delete a promotion, I would like that the users can't delete also the promotions of other users but only their own
I have to change the controller but how? i hope in a help
this is controller for the destroy of a promotion
def destroy
#promotion = Promotion.find(params[:id])
#promotion.destroy
##promotion = current_user.promotions.destroy
respond_to do |format|
format.html { redirect_to promotions_url, notice:'Promotion was successfully delete.' }
format.json { head :ok }
end
end
end
sorry for my english please!
Crosscheck if the current_user is also the creator of the #promotion:
def destroy
#promotion = Promotion.find(params[:id])
if #promotion.user == current_user #if user is the owner of that promotion
#promotion.destroy
respond_to do |format|
format.html { redirect_to promotions_url, notice:'Promotion was successfully delete.' }
format.json { head :ok }
end
else
redirect_to root_path
end
end

How to handle update of a single user model data separately: user info, password, extra information

I want to present users with separate pages/dialogs for editing their own information. However, the information is held in a single model (called User). Now I'm trying to find the best approach for handling the update calls from partials. My code currently:
def edit
render :layout=>!request.xhr?
end
def edit_password
render :layout=>!request.xhr?
end
def edit_extra
unless #user.extra
#user.build_extra
#user.extra.value = 2047
end
render :layout=>!request.xhr?
end
def update
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit", :layout=>!request.xhr? }
end
end
end
The thing is, all forms in methods (edit, edit_password and edit_extra) call the update method. However, there are two problems:
If the data parsing isn't validated, user is presented with the "edit" form, which is incorrect.
I want to have a password confirmation on extra data. User shouldn't be able to edit that information unless they supply a correct password.
I would like to make more generalized solution than just duplicating the update -code. The largest problem is rendering correct layout (edit, edit_password) based on the current action.
For now, I solved the problem by creating separate edit_section parameter that will be handled in update.
def update
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => (t :actionsuccesful) }
format.json { head :no_content }
else
action = if params[:edit_section] then "edit_" + params[:edit_section] else "edit" end
format.html { render :action => action, :layout=>!request.xhr? }
end
end
end
And in forms (edit_password, etc)
=form_for(#user, :remote => true) do |f|
= hidden_field_tag :edit_section, "password"

Ruby on Rails - updating multiple models from the one controller

I'm trying to get my head around saving to multiple models from the one controller and it's probably really simple but I can't figure it out.
I have a User Model that has many loanitems and the loanitems belong to the user associations set up.
In my loanitems controller I want each loanitem create action to update a the user.points
So at the moment I have the following code that doesn't throw any errors but doesn't update the user model either.
def create
#loanitem = current_user.loanitems.build(params[:loanitem])
respond_to do |format|
if #loanitem.save
#loanitem.user.points = #loanitem.user.points + 50
#loanitem.user.save
format.html {redirect_to root_path, :flash => {:success => "Loan Item created" } }
format.xml{render xml: root_path}
else
format.html {render 'pages/home' }
format.xml {render xml: 'pages/home'}
end
end
end
I'm also trying the following variation on a theme
def create
#loanitem = current_user.loanitems.build(params[:loanitem])
respond_to do |format|
if #loanitem.save
current_user.points = current_user.points + 50
current_user.save
format.html {redirect_to root_path, :flash => {:success => "Loan Item created" } }
format.xml{render xml: root_path}
else
format.html {render 'pages/home' }
format.xml {render xml: 'pages/home'}
end
end
end
But should I be sending some message instead to the userupdate controller instead? That currently looks like this ...
def update
#user = User.find(params[:id])
if
#user.update_attributes(params[:user])
redirect_to #user, :flash => { :success => "Profile has been updated!"}
else
#title = "Edit Profile"
render 'edit'
end
end
Or I have heard that the business logic really should all be contained in the model so maybe the method should be written in User.rb and then called by the Loanitems controllers create method?
I know it's a real rookie question but any advice would be really welcome.
It sounds like you need to use a Transaction, so you can modify multiple items as a single atomic unit:
def create
respond_to do |format|
User.transaction do
begin
#loanitem = current_user.loanitems.create!(params[:loanitem]) # raises exception if it can't create
#loanitem.user.update_attributes!(:points => #loanitem.user.points + 50) # raises exception if it can't update
format.html {redirect_to root_path, :flash => {:success => "Loan Item created" } }
format.xml{render xml: root_path}
rescue ActiveRecord::RecordInvalid
format.html {render 'pages/home' }
format.xml {render xml: 'pages/home'}
raise ActiveRecord::Rollback
end
end
end
end
This allows you to have a simple happy-path where multiple objects are updated/created and roll-back all changes so far if anything goes wrong and render your error handling logic. The objects will have the validation messages you can display to the user.

Resources