So I discovered a weird issue while trying to use mass assignment on a model that also had an attr_accessor for an attribute that was being updated through a mass assigned strong params hash. I was curious as to why this happens - and is it supposed to happen?
Here is my controller methods for update and the strong params -
def update
@device = Device.find(params[:id])
if @device.update(device_params)
redirect_to device_path(@device)
else
render :edit
end
end
private
def device_params
params.require(:device).permit(:department_id, :entity_id, :description, :device_model_id)
end
And when I do this in the corresponding device model being updated, it will not throw any errors, but the fields - department, and entity will remain unchanged after the update method.
class Device < ActiveRecord::Base
attr_accessor :device_event, :sensor_event, :department_id
delegate :name, to: :department, prefix: true, allow_nil: true
delegate :name, to: :entity, prefix: true, allow_nil: true
delegate :id, to: :department, prefix: true, allow_nil: true
delegate :id, to: :entity, prefix: true, allow_nil: true
delegate :firmware, to: :device_configuration, prefix: true, allow_nil: true
delegate :sleeptime, to: :device_configuration, prefix: true, allow_nil: true
has_many :sensors
has_many :events
has_many :sensor_data, through: :events
has_many :device_data, through: :events
belongs_to :device_type
belongs_to :entity
belongs_to :department
has_one :device_configuration
paginates_per 10
def self.filter(params_hash)
filter_params = ActiveSupport::HashWithIndifferentAccess.new(params_hash)
devices = Device.where(filter_params)
end
def recent_sensor_event
self.events.where(event_type_id: 1).last
end
def recent_device_event
self.events.where(event_type_id: 0).last
end
end
Now when I remove the attr_accessor on department_id, the mass_assigned strong params hash will save properly when @device.update is called in the controller and all is well. It took me a while to figure out that the attr_accessors were what was tripping up the mass assignment.
Your device model already has an implicit department_id
by virtue of this line:
belongs_to :department
By additionally declaring attr_accessor :department_id
you are overwriting this implicit attribute (and its ActiveRecord persistence magic) with a concrete getter and setter based on a @department_id
instance variable (which has no persistence magic at all). That's probably not what you had in mind.
So when you perform the mass assignment, the @department_id
value will get changed, but the underlying belongs_to
association will not. Hence your observation that the department association is not updated in the database.
To summarize: you don't need attr_accessor :department_id
because ActiveRecord generates something similar to it automatically when you declare belongs_to :department
.