0

I'm not 100% sure about why ActiveModel::Dirty has its name. I'm guessing it is because it is considered as dirty to use it.

But in some cases, it is not possible to avoid watching on specific fields.

Ex:

if self.name_changed?
  self.slug = self.name.parameterize
end

Without ActiveModel::Dirty, the code would look like:

if old_name != self.name
  self.slug = self.name.parameterize
end

which implies having stored old_name before, and it is not readable, so IMHO, it is dirtier than using ActiveModel::Dirty. It becomes even worse if old_number is a number and equals params[:user]['old_number'] as it needs to be correctly formated (parsed as int), whereas ActiveRecord does this automagically.

So I would find clean to define watchable fields at Model level:

class User < ActiveRecord::Base
  include ActiveModel::Dirty

  watchable_fields :name

  before_save :generate_slug, if: name_changed?

  def generate_slug
    self.slug = self.name.parameterize
  end

end 

Or (even better?) at controller level, before assigning new values:

def update
  @user = current_user
  @user.watch_fields(:name)

  @user.assign_attributes(params[:user])

  @user.generate_slug if @user.name_changed?
  @user.save # etc.
end

The good thing here is that it removes the memory overload produced by using ActiveModel::Dirty.

So my question is:

Can I do that using ActiveRecord pre-built tools, or should I write a custom library to this?

Thanks

Augustin Riedinger
  • 20,909
  • 29
  • 133
  • 206

2 Answers2

1

If ActiveModel::Dirty solves your problem, feel free to use it. The name comes from the term "dirty objects" and is not meant to imply that it's a dirty/hackish module. See this answer for more details on dirty objects: What is meant by the term "dirty object"?

Community
  • 1
  • 1
Arctodus
  • 5,743
  • 3
  • 32
  • 44
  • Interesting. Though it still generates the memory overload, doesn't it? I mean, it makes sense to track some fields, but others not. – Augustin Riedinger Jun 01 '15 at 13:10
  • Im sure there's some overhead but it's probably irrelevant unless you got very, very strict memory requirements. – Arctodus Jun 01 '15 at 15:44
0

Here's what I have ended up doing. I like it:

class User < ActiveRecord::Base

  attr_accessor :watched

  def field_watch(field_name)
    self.watched ||= {}
    self.watched[field_name] = self.send(field_name)
    return self
  end

  def field_changed?(field_name)
    self.send(field_name) != self.watched(field_name)
  end
end

And in the controller

def update
  @user = current_user.field_watch(:name)
  @user.assign_attributes(params[:user])
  @user.generate_slug if @user.field_changed?(:name)
  @user.save
end

I'll report here if I take the time to wrap this code in a gem or something.

Augustin Riedinger
  • 20,909
  • 29
  • 133
  • 206