Rails 4 - Delete rows from another table before updating - ruby-on-rails

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

Related

rails How to update user attribute with Model.object from different controller on :create

I want to update(add or substract) to User.points_balance the value of Point.point_moving
I need to get the user from Point.user_id (user is not logged in)
I do not get error messages, the points are created but User.points_balance is not updated.
my points.controller
def create
#point = Point.new(point_params)
#point.save
#user = User.find(params[#point.user_id])
if user && user.increment(:points_balance, by = #point.points_moving)
respond_to do |format|
format.html { redirect_to :back, notice: 'Saved.' }
format.json { render :show, status: :created, location: #user }
end
end
Question update:
Having so much trouble to do this and cant figure out why., how about this?
I have Points controller with :user_id and :points_moving
I have Users controller with :points_balance that needs to be updated(add/substract) Point.points_moving value.
How should i do to create a separate method that updates User.points_balance (adding or substracting the value of Point.point_moving) and then call the method from the Points controller on :create ?
Hoping this makes sense...
I was going to suggest using #user.increment!(:update_count, by = #point.point_moving). Note the !, which causes it to update the database. Unlike your version which just updates the instance variable.
However, this can be very racy if you have multiple requests coming in at the same time incrementing the same user. So I would avoid this 'read and then write' approach, and do it directly in the database like so:
User.where(id: #user.id).
update_all("update_count = update_count + #{#point.point_moving}")
Notice you're using user.increment. When you should increment #user
def create
#point = Point.new(point_params)
#point.save
#user = User.find(params[#point.user_id])
if #user && #user.increment(:points_balance, by = #point.points_moving)
respond_to do |format|
format.html { redirect_to :back, notice: 'Saved.' }
format.json { render :show, status: :created, location: #user }
end
end
Let me know if that solves your issue.
You want User's point_balance to increase, but you're incrementing update_count.

Deleting group of elements in 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

find results from table after update, where (attribute integer) is equal to the (primary id integer)

I am updating an object in a table with attributes : :primary_id, :zucode_number, :zucode_email
The updated row object does NOT have the attributes :zucode_number and :zucode_email .
Other different rows in the same table do have the attributes i need, :zucode_number and :zucode_email.
:zucode_number(integer) can be equal to, is sometimes equal to the :primary_key(integer)
How to get the rows where :zucode_number is equal to :primary_key and send email to :zucode_email on those rows.
Hope this makes sense...
Ive been, and i am, struggling with this, and can't get it to work. Thanks in advance for your help.
Asked another question similar yesterday but think it wasn't clearly explained.
I am updating (successfully) the object(zucode), sending it through a link to:
def changezu
zucode = Zucode.where( id: params[:id], secret2: params[:secret2] ).first
if zucode
respond_to do |format|
format.html { redirect_to edit_zucode_path, notice: 'Make changes!.' } #edit_zucode_path
format.json { head :no_content }
end
end
end
my update method is :
def update
respond_to do |format|
if #zucode.update(zucode_params)
format.html { redirect_to #zucode, notice: 'Zu was successfully updated.' }
format.json { render :show, status: :ok, location: #zucode }
else
format.html { render :edit }
format.json { render json: #zucode.errors, status: :unprocessable_entity }
end
end
end
UPDATE::
added to controller :.
after_action :trynew, only: [:update]
and
def trynew
#zucode = Zucode.where("zucode_number=id")
#ZuMailer.mymail.(zucode).deliver
end
with the mailer commented out, it does not give error but nothing happens. Looking into log the correct rows are not being selected or mentioned. I only see reference to the updated row. If i run with the mailer i get error for "wrong arguments 0 of 1"
As I can see, that you need to use callbacks of object lifecycyle.
I am assuming that you have a model called Zucode .
Inside that model add after_update method.
class Zucode
after_update :method_to_call
def method_to_call
zucodes = Zucode.where('zucode_number=id')
#perform action on zucodes
end
end
The method method_to_call will get called each time a Zucode is updated.

Rails redirect_to in controller to correct page

I have several models with has_many :attachments.
I'm trying to redirect back to the Note view after the Note is created.
This is the attachments controller code I'm trying. The #note tells me that this attachment is related to that Note.
# GET /attachments/new
# GET /attachments/new.json
def new
#attachment = Attachment.new
#comment = params[:comment_id]
#note = params[:note_id]
respond_to do |format|
format.html # new.html.erb
format.json { render json: #attachment }
end
end
# POST /attachments
# POST /attachments.json
def create
#attachment = Attachment.new(params[:attachment])
respond_to do |format|
if #attachment.save
if #note != nil
format.html { redirect_to note_path(#note), notice: 'Attachment was successfully created.' }
else
format.html { redirect_to attachments_path, notice: 'Attachment was successfully created.' }
end
But, #note is nil by the time the create code happens.
Thanks for the help!
As a rule, you probably won't see "new" and "create" blocks executed in the same context. That's a bit of a mouthful, so lets be a bit more specific: the variables you declare in "new" won't still exist when "create" is called. So, any variables you want to use in "create" must be declared there as well.
One thing you can do (depending on the code) is share a block between different controller methods that initialized these variables for you. For example:
before_filter :initialize_vars, only: [:new, :create]
...
def initialize_vars
#note = params[:note_id]
end
The "before_filter" will execute the "initialize_vars" method before any new request is sent to the "new" or "create" methods.
More generally, this relates to a pretty important Rails concept (and server-side web engineering in general) - that there is very little "state" within the server. The server takes a request, processes it, and forgets about it. Everything that's needs to be remembered must be stored in the server, or somehow communicated by the request the user sends.

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"

Resources