I am working on a rails method where I need to create copies of a resource. I am using dup for that.
Right now I am using save method in saving new copies and saving it in the iteration:
(User.leads2deals.emails - [#old_inquiry.to_email]).each do |dealer|
#inquiry = #old_inquiry.dup
#inquiry.to_email = dealer
#inquiry.senttoall = true
if !#inquiry.save
all_saved = false
end
end
Depending upon the all_saved boolean flag, I am sending the right message to the user as shown:
if all_saved
#old_inquiry.senttoall = true
#old_inquiry.save
respond_to do |format|
format.html {redirect_to #parent, notice: 'All Leads were successfuly sent!'}
end
else
respond_to do |format|
format.html {redirect_to #parent, notice: 'There was some problems sending all the leads! Try sending one by one'}
end
end
My question is I want to use bulk create. Use an array, build objects and finally call create on that array of the object for efficiency.
But I want to check if create fails for any of the objects, in that case, I will change my boolean flag to false and give the user notifications that not all inquiries were saved.
I checked that create or create! does not return true/false. In this case, how can I check if all the objects were successfully created or not?
You can do:
result = Model.create(array)
Then to check if everything was created successfully,
if result.all?(&:persisted?)
# successful action
else
# failed action
end
Try using activerecord-import. It supports validations. All you need to do is to check what it returns when a validation fails and build your response based on that.
Related
I have a controller that looks like the following:
def update
#expense_report = ExpenseReport.find(params[:id])
#expense_report.status = "Submitted"
respond_to do |format|
if #expense_report.update(expense_report_params)
...
...
else
format.html { render :edit }
...
end
end
end
I am attempting to set the status before the update, so I can reduce the number of saves performed. I'd prefer only one save to occur. However, when the form is re-rendered on a failed save, it is re-rendered with the original parameters AND the status set to Submitted, even though 'Submitted' was not one of the original params. Is there a way to render with only the original parameters?
#artur.prado is on the right track with his answer, but is missing re-assigning the user provided parameters. I've made this into a separate answer, because changing his answer would completely overhaul what he has written and might go against his intent.
You can restore the database version with restore_attributes, then re-apply the submitted changes with assign_attributes.
def update
#expense_report = ExpenseReport.find(params[:id])
#expense_report.status = "Submitted"
respond_to do |format|
if #expense_report.update(expense_report_params)
# ...
else
#expense_report.restore_attributes
#expense_report.assign_attributes(expense_report_params)
format.html { render :edit }
# ...
end
end
end
Rails 4.2 introduced exactly what you need. On the else block, just call
#expense_report.restore_attributes
before rendering the view. It will do the trick.
I don't quite understand the logic for the code below. A new instance is created with the data entry by a user and the code goes on to say if #item.save. Don't you have to save the new instance BEFORE checking whether the instance was saved or not in if #item.save?
def create
#item = Item.new(params.require(:item).permit(:title, :description))
if #item.save
redirect_to root_path
else
render :new
end
end
I don't get why the code isn't something like
def create
#item = Item.new(params.require(:item).permit(:title, :description))
#item.save
if #item.save
redirect_to root_path
else
render :new
end
end
#item.save run validations and save the record if the validations passed successfully. Furthermore save returns true if the record was saved and false if the validations failed.
So it does both saving and returning the status of the saving operation. Therefore there is no need to do it yourself.
By default, save always runs validations. If any of them fail the action is canceled and save returns false, and the record won't be saved.
Quote from the documentation of the save method.
#save returns true or false. true if the object is saved successfully, false otherwise. This allows #item.save to be used as conditional expression in the if structure.
PS.: There is this other method #save! too. It returns true if the object gets saved or raises an error otherwise.
I realized something quite strange when attempting to upload an image via the paperclip gem for my user model (under the avatar attribute). For some reason there User.update and #user.update_attributes behaves differently. Does anyone know why this is so?
#using #user.update_attributes(user_avatar_params)
def update_profile_pic
#user = User.find(params[:id])
#user.update_attributes(user_avatar_params)
puts #user.avatar_file_name.nil? # prints false as expected
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
#using User.update(#user.id, user_avatar_params)
def update_profile_pic
#user = User.find(params[:id])
User.update(#user.id, user_avatar_params)
puts #user.avatar_file_name.nil? # prints true although successfully saves
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
And here is my strong params in the user_controller.rb
def user_avatar_params
params.require(:user).permit(:avatar)
end
For what it's worth, as of Rails 4.0.2, #update returns false if the update failed, not simply the object which the update failed for. Of further note, #update_attributes is simply an alias of #update now.
ActiveRecord.update has a behavior that may be throwing you off:
Updates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.
http://apidock.com/rails/ActiveRecord/Base/update/class
However the update_attributes will just return false.
Both of these use Model-level validations and so both should save or not save equally. However, the return values will be different.
As #RoaringStones pointed out, the solution is to use
user = User.update(user.id, user_avatar_params)
By the way, #update_attributes gonna be deprecated from Rails 6 (though this is not released yet)
please have a look at
https://github.com/rails/rails/pull/31998
https://github.com/rails/rails/commit/5645149d3a27054450bd1130ff5715504638a5f5
for more details.
I'm implementing a multistep form - as shown in #217 Multistep Forms - Railscasts - and came across an error:
can't dump File
Here are new and create actions:
def new
session[:batch_params] ||= {}
#batch = current_user.batches.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #batch }
end
end
def create
session[:batch_params].deep_merge!(params[:batch]) if params[:batch]
#batch = current_user.batches.build(session[:batch_params])
if #uploaded
#batch.file = #uploaded
end
#batch.current_step = session[:batch_step]
if params[:back_button]
#batch.previous_step
elsif #batch.last_step?
#batch.file = session[:file]
#batch.save
else
#batch.next_step
end
session[:batch_step] = #batch.current_step
if #batch.new_record?
render 'new'
else
session[:batch_step] = session[:batch_params] = nil
flash[:notice] = "Batch was successfully created"
redirect_to #batch
end
end
The problem is: the file needs to be updated in the first step, since I need to read it and get the number of rows, to be used on the second step. So I'm trying to store a file in the session, and since it's not possible to serialize it, I'm getting this error.
How can avoid doing this? I believe I should upload the file on the first step, and then just provide it's url to the following steps; is it correct?
How can I do this?
I suggest you create the record on the first form, and use a state machine to track the steps of the object until you fully build it on the last form. Gems like state_machine will allow you to do validations per step. The only problem with that is that you might (will) end with submissions that weren't completed. You might clean up this periodically.
I have a create action in one of my controllers which responds to ajax and html requests. Inside the create action I set an instance variable (#location) using a find_or_initialize_by_such_and_such. I then test to see if the location already exists or not using this:
if #location.id.nil?
#location.save
respond_with(#location, :location => root_path) do |format|
format.html { redirect_to root_path }
end
end
This works fine since basically the partial (create.js.erb) appends the newly saved location object to a list.
The problem occurs when the user inputs a location which already exists (i.e. has an id). In such a case I do not want the found location to be appended to the list, as it would cause duplication (all the locations are already there). Since #location.id.nil? is false in that scenario the code within the above block is obviously not executed, but I am having a hard time figuring out how to handle that situation. I tried doing something like:
respond_with(nil, :location => root_path) do |format|
format.html { redirect_to root_path }
end
but the js.erb file still grabs the #location instance variable and executes the javascript that adds the object to the list.
What would be the best way to therefore to work around this, so that in cases where the find_or_initialize_by returns an already created object, the response will not execute the javascript to append this object to a list?
remove
respond_with(nil, :location => root_path) do |format|
format.html { redirect_to root_path }
end
and leave only this
redirect_to root_path
if you don't any extra respond