I want to add a field to an Ecto changeset provided the field is not nil. Besides, I do not want to update the value which is already in the database if this new value is nil.
I have tried various options but still not getting the desired result.
I would be very grateful for any help in this regard.
def update_device_data(params) do
uniq_device_code=params[:uniq_device_code]
manufacturerId=if !is_nil(params[:manufacturerId]) do
params[:manufacturerId]
end
manufacturerCompanyName=if !is_nil(params[:manufacturerCompanyName]) do
params[:manufacturerCompanyName]
end
deviceAliasName=if !is_nil(params[:deviceAliasName]) do
params[:deviceAliasName]
end
deviceType=if is_nil(params[:deviceType]) do
params[:deviceType]
end
modelTypeNumber=if !is_nil(params[:modelTypeNumber]) do
params[:modelTypeNumber]
end
serialNumber=if !is_nil(params[:serialNumber]) do
params[:serialNumber]
end
record = App.Repo.get_by(App.Schema.DeviceData, [device_id: uniq_device_code])
changeset = App.Schema.DeviceData.changeset(record, %{device_serial_no: serialNumber, model_type_id: modelTypeNumber, device_type_code: deviceType, manufacturer_id: manufacturerId, manufacturer_company_name: manufacturerCompanyName, device_alias: deviceAliasName, updated_at: DateTime.truncate(Timex.now(), :second)})
App.Repo.update(changeset)
end
This function is made far more complicated by accepting parameters with keys that don’t match your requirements. I would change your implementation to accept a map of params that match the keys of the DeviceData schema. If the function is being called by a dependency or something else that you can’t control then adding a separate function that transforms the keys to the expected format before passing the params to updated_device_data would work as well.
Then you can just filter any of the params that have a nil value like this:
def update_device_data(params) do
alias App.Schema.DeviceData
device_id = params[:device_id]
params =
params
|> Enum.reject(fn {_, v} -> is_nil(v) end)
|> Map.new()
App.Repo.get_by(DeviceData, [device_id: device_id])
|> DeviceData.changeset(params)
|> App.Repo.update()
end
As @LostKobrakai mentioned if params is unvalidated user input you should cast it first. Checking for nil won’t prevent an empty string being set, if you cast it first then Ecto will transform empty strings to nil for you.