Update instead of delete - ruby-on-rails

I'm developing a webapp with Ruby 1.8.7 and Rails 2.3.5, which will manage some industrial process. One of the requirements is that, when someone wants to delete a registry, the delete task will have to make an update to one of the fields of the DB table. This field establishes if a record is active or not.
I have modified the default delete method generated by the scaffold:
def activar
#alarma = Alarma.find(params[:id])
respond_to do |format|
if #alarma.update_attribute(:estado_id => 1)
flash[:notice] = 'La alarma ha sido activada.'
format.html { redirect_to(#alarma) }
format.xml { head :ok }
else
format.html { render :action => "index" }
format.xml { render :xml => #alarmas }
end
end
end
def desactivar
#alarma = Alarma.find(params[:id])
respond_to do |format|
if #alarma.update_attribute(:estado_id => 2)
flash[:notice] = 'La alarma fue desactivada.'
format.html { redirect_to(#alarma) }
format.xml { head :ok }
else
format.html { render :action => "index" }
format.xml { render :xml => #alarmas }
end
end
end
where :estado_id => 1 is active, and :estado_id => 2 is deactive. However, when a I try to do the update, it doesn't change the attribute. Actually, it doesn't do anything.
Does anyone have a clue?

You should use update_attributes in your case
update_attributes(attributes) public
Updates all the attributes from the
passed-in Hash and saves the record.
If the object is invalid, the saving
will fail and false will be returned.
example:
#user.update_attributes(:status => 'active')
or #alarma.update_attribute(:estado_id, 2) if you want to use update_attribute
update_attribute(name, value) public
Updates a single attribute and saves
the record without going through the
normal validation procedure.

Related

When using the accept_nested_attributes_for method, what actually happens when I tell my controller to build the nested form?

What I'm trying to do is update a created item's attributes after it is created through the controller, like so:
def create
#check_out = CheckOut.new(params[:check_out])
#check_out.request_id = #request.id
#check_out.status = 'complete'
#check_out.date_taken = Time.now
etc.....
respond_to do |format|
if #check_out.save
format.html { redirect_to(#check_out, :notice => 'Check out was successfully created.') }
format.xml { render :xml => #check_out, :status => :created, :location => #check_out }
else
format.html { render :action => "new" }
format.xml { render :xml => #check_out.errors, :status => :unprocessable_entity }
end
end
end
The issue is that the item created, is created via a nested attribute. I've come to realize, through painful trial and error, that when nested items are created, it is not through their controller, but some other way. I need to figure out how this is done, so I can attempt to come up with a solution.
The good place to start http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for

Rails3 Conditional Statements in Controller Actions

I'm trying to write a conditional statement in my tasks controllers for a simple rails3 application.
Users have many tasks and tasks have one user.
When creating a task, we can chose who owns it:
<%= collection_select(:task, :user_id, User.all, :id, :name, {:prompt => true}) %>
I want the system to send an email to the owner of the task, only when it's created for someone else. I.e. I do not need to receive an email when I create a task for myself.
My mailer's working fine and in my tasks controller, I've tried this:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save and #task.user_id = current_user.id
format.html { redirect_to(tasks_path, :notice => 'Task was successfully created.') }
format.xml { render :xml => #task, :status => :created, :location => #task }
elsif #task.save
format.html { redirect_to(tasks_path, :notice => 'Task was successfully created.') }
format.xml { render :xml => #task, :status => :created, :location => #task }
TaskMailer.new_task(#task).deliver
else
format.html { render :action => "new" }
format.xml { render :xml => #task.errors, :status => :unprocessable_entity }
end
end
end
But it's not really working... Any chance of some assistance.
Replace #task.user_id = current_user.id with #task.user_id == current_user.id.
This is not the cause of your error, but you're saving your task two times if #task.user_id != current_user.id. You could do something like this instead:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to(tasks_path, :notice => 'Task was successfully created.') }
format.xml { render :xml => #task, :status => :created, :location => #task }
TaskMailer.new_task(#task).deliver if #task.user_id != current_user.id
else
format.html { render :action => "new" }
format.xml { render :xml => #task.errors, :status => :unprocessable_entity }
end
end
end
end
Are you not storing the id of the creator? If you do, all the data you need is in the model. Thus just implement an private instance method in Task model. Something like the following
# Task model
private
def notify_assignee
if new_record? || user_id_changed? && creator_id != user_id
TaskMailer.new_task(#task).deliver
end
end
Call the above method after_save
# Task model
after_save :notify_assignee
In case you are not storing the creator_id in the database, create an attribute accesor called :creator_id.
# Task model
attr_accessor :creator_id
In the controller, before saving, do
# Tasks controller
#task.creator_id = current_user.id
and the above method would still work.
You controller re directions would automatically be simplified to
if #task.save
format.html { redirect_to(tasks_path, :notice => 'Task was successfully created.') }
format.xml { render :xml => #task, :status => :created, :location => #task }
else
format.html { render :action => "new" }
format.xml { render :xml => #task.errors, :status => :unprocessable_entity }
end
And also this would be the right way to go as the "business logic" (which in your case is send assignee an email notifying that someone else has assigned a task to them) would reside in the model.
It's because of this line, you're using an assignment = instead of the comparision ==
Also the current_user should be #current_user instead because you didn't specify it in the method. (Or you have a method current_user() that you did not post. Then it's fine)
if #task.save and #task.user_id = current_user.id
It should be
if #task.save and #task.user_id == #current_user.id
also imho you should move the mailing-stuff to the Task-model and use an after_save-callback.
Maybe you need change this line: #task.user_id = current_user.id to #task.user_id == current_user.id

Shopping cart : handling no product error with rails / ajax

I am using ajax to change the displayed cart as the user add product to cart. To do so i call with :remote=>true the correct controller that send back the updated cart.
The controller method to do so is the following :
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to(magasin_url) }
format.js {#current_item = #line_item }
format.xml { render :xml => #line_item, :status => :created, :location => #line_item }
else
format.html { render :action => "new" }
format.xml { render :xml => #line_item.errors, :status => :unprocessable_entity }
end
end
end
I'd like to be able to handle an empty stock by sending a notice message instead of updating the cart.
I tried this :
if product.stock_to_display <=0
respond_to do |format|
format.html { }
format.js {}
end
end
But i do not know what to put in the format. and i have no idea how to do a condition in the rjs :
page.replace_html('panier', render(#cart))
page[:panier].visual_effect :blind_down if #cart.total_items == 1
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
page.select("#notice").each {|notice| notice.hide}
So i'd like to know how to handle the error with ajax/rjs. Thanks
Ok after a little bit of try i managed to do something that seems clean.
I created a #success boolean in the controller and affected him a value, after that i can use the boolean in RJS to either do my stuff or display the notice.
Here is my new RJS.
if #success
page.replace_html('panier', render(#cart))
page[:panier].visual_effect :blind_down if #cart.total_items == 1
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
page.select("#notice").each {|notice| notice.hide}
else
page.replace_html :notice, flash[:notice]
flash.discard
end
If you have a javascript error with the display, check the application layout as it may be restricted by a "if notice" condition

Rails doesn't populate dynamic generated fields on error on posting

In our rails application we have a page where upon submit we save data in db. On this page, we have some fields which are dynamically generated and I see that in case of a validation error when page reloads it doesn't populate these fields with the values present upon posting.
In controller we have the following method defined for populating it:
def build_my_registration_type_memberships
#memberships = []
ListCache.my_registration_types.each do |my_registration_type|
#memberships << MyRegistrationTypeMembership.find_or_initialize_by_my_id_and_my_registration_type_id( #my.id, my_registration_type.id )
end end
In above method when my registration is opened in edit/view mode, it shows the values using this #membership method. But on posting in case of error it doesn't reload this with correct information. So my question is how could I repopulate #membership in case of an error on posting?
Thanks for help.
As, I understand you want some values available to your new method or the page that is rendered after if the create fails.
I assume you must have have the respond_to block in your create method. And you're doing this:
def create
...
respond_to do |format|
if #patient.save
format.html { redirect_to #object, :notice => "Object was successfully saved." }
format.xml { render :xml => #object, :status => :created, :location => #object }
else
format.html { render :action => :new }
format.xml { render :xml => #patient.errors, :status => :unprocessable_entity }
end
end
end
As you can notice, in the else part the new action is just rendered. Using some template the view is just delivered. Now, you just have to do whatever you're doing in the new action to make those values available, in the else part.
def create
...
respond_to do |format|
if #patient.save
format.html { redirect_to #object, :notice => "Object was successfully saved." }
format.xml { render :xml => #object, :status => :created, :location => #object }
else
format.html {
#memberships = []
ListCache.my_registration_types.each do |my_registration_type|
#memberships << MyRegistrationTypeMembership.find_or_initialize_by_my_id_and_my_registration_type_id( #my.id, my_registration_type.id )
end
render :action => :new
}
format.xml { render :xml => #patient.errors, :status => :unprocessable_entity }
end
end
end
And, the values you wanted will be available in the rendered form.
Better, you move to that code to a before filter or something, which makes those values available to those two methods (new and create).

Rails, Is there any way in my view use link_to to grab the contents of a specific field and place it in a ruby variable?

Basically I am trying to capture the value of the form field before it is saved to the database. Then I intend to use that value in my controller to update a specific field in the database,
using
#taskforms.update_attribute('notes',
$notes)
I need to do this because I know of no other way to update that that does not require the full record to be validated.
The suggestion below to use #taskforms.save(false) is really not what I was looking for optimally. However it could work. However having and issue to get it to work.
What I am currently using (that works with validations)
def myupdate
#taskforms = Taskforms.find(params[:id])
respond_to do |format|
if #taskforms.update_attributes(params[:taskforms])
#taskforms.update_attribute('edited_at', Time.new )
flash[:notice] = 'Note was successfully updated.'
format.html { redirect_to(:controller => "taskforms", :action => "displayedit", :id => #taskforms.id) }
format.xml { head :ok }
else
format.html { render :action => "displayedit" }
format.xml { render :xml => #taskforms.errors, :status => :unprocessable_entity }
end
end
end
However when I try the save(false) it doesn't save and triggers validations anyway
def myupdate
#taskforms = Taskforms.find(params[:id])
if #taskforms.save(false)
#taskforms.update_attribute('edited_at', Time.new )
flash[:notice] = 'Note was successfully updated.'
format.html { redirect_to(:controller => "taskforms", :action => "displayedit", :id => #taskforms.id) }
format.xml { head :ok }
else
format.html { render :action => "displayedit" }
format.xml { render :xml => #taskforms.errors, :status => :unprocessable_entity }
end
end
I have never used Save in the past just the default respond_to do |format| so suspect my code is incorrect.
#taskforms.save(false) will save your model without any validations if that is your main goal.

Resources