Virtual attributes
I recently face an issue in my job where I was suppose to create a resource, N times. A first approach is to use the default params
object used in controller to send a variable containing the number of time the object should be created. However, since the creation of the object should be done through another model, a second approach could be to use virtual attributes. The idea behind a virtual attributes is that this is an accessor / attributes of the model which is not persistant in the database. We could then fill it with a form.
Just before going in the code here is the scenario: we are going to create an object EpcOrder
, which should create N times another object GtinEpcOrder
.
Step 1, the form.
form.html.erb
<%= f.input :gtins_count, as: :integer %>
<%= f.input :description, as: :text %>
<%= f.submit %>
The first thing to do is create a form to fill the model. Here the description is a persistant attributes of the model, while gtins_count
is the virtual attributes, we call it that way but really there’s no convention, what matter is that the name has to match with the vitual attributes defined in the model. (See just below)
Step 2, the model.
epc_order.rb
class EpcOrder < ApplicationRecord
validates :gtins_count, numericality: { only_integer: true, greater_than: 0, less_than_or_equal_to: 10.000 }
attribute :gtins_count, :integer, default: 0
end
gtins_count
is the virtual attribute. I was using at first the attr_accessor
ruby keyword to defined the getter / setter of the attributes, but I discovered the attributes keyword which is introduced in rails 5. Both options are the same and work, simply make sure you specify in your HTML form the type if this is not a string, in our case gtins_count is an integer.
Step 3, the controller.
epc_orders_controller.rb
class Admin::EpcOrdersController < Admin::AdminController
def create
@epc_order = EpcOrder.new(epc_params)
if @epc_order.save
# success steps
end
end
private
def epc_params
params.require(:epc_orders).permit(:description, :gtins_count)
end
end
This is the controller of the resource, the important thing to see here is we add the gtins_count
variable in the permitted params of the model.
Once the three steps has be done, you can simply use the attributes like if it is part of the model :
Step 4, the model, again.
epc_order.rb
class EpcOrder < ApplicationRecord
after_create :create_gtins
def create_gtins
gtins_count.times do
GtinEpcOrder.create
end
end
end