Reputation: 512
I'm using something like this in my Controller
class:
before_action :do_something, only: [:new, :create]
def new
@myModel = MyModel.new
end
def create
@myModel = MyModel.create_with_data(params)
respond_to do |format|
if @myModel.errors.empty?
format.html { redirect_to @myModel, notice: 'MyModel was successfully created.' }
format.json { render :show, status: :created, location: @myModel }
else
logger.error 'MyModelController: Creating mymodel failed!'
format.html { render :new }
format.json { render json: @myModel.errors, status: :unprocessable_entity }
end
end
def do_something
# Very long method
end
Now, the problem is, that my do_something
method takes very long to execute. If user will make mistake while creating new myModel
field, he will need to wait for this method to execute, just to display him some error.
Let's say, that I don't want front-end validation and I can't reduce the time of do_something
method. How can I pass somehow data from do_something
that executed before new
method is called, so it won't be needed to execute again before create
method?
Upvotes: 1
Views: 401
Reputation: 102046
I would consider using an optimistic saving approach instead. Much like how unconfirmed users are usually treated.
You insert the record in the database but set a state which denotes that it's not a full fledged record. You then update the record when it is confirmed.
It gives the user quick feedback and you can free your web process from waiting for do_something
.
class MyModel < ActiveRecord::Base
# create an Int column named status
# make sure it has an index and defaults to 0.
enum status: [:unverified, :verified]
end
So, you would do something like this in your controller:
def create
# Don't do params assignment / whitelisting in your models.
# models should not be aware of parameters.
@my_model = MyModel.new(my_model_params) do |m|
# This should be handled by the DB default but
# this is a belt and suspenders approach to be 200% sure
# that a record does not slip through.
m.unverified!
end
if @my_model.save
MyModelVerificationJob.perform_later(@my_model)
respond_to do |format|
format.html do
flash[:notice] = "We are currently verifying..."
redirect_to :edit, @my_model
end
# ...
end
else
# we already know something is fishy so just render the
# form again.
respond_to do |format|
# ...
end
end
end
private
def my_model_params
params.require(:my_model).permit(...)
end
This example is with Rails 5 Active Jobs but you can look into Resque or Sidekiq as well.
How exactly to handle the callback from your do_something
method depends on what kind of user interaction is required. If the user needs to correct a form for example you would cache the results from the background job and prompt the user to visit a page where they correct the form.
Upvotes: 3