Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I override an attr_accessor getter from a module?

module HasUrl
  extend ActiveSupport::Concern

  included do
    attr_accessor :bar
  end

  def bar
    0
  end
end

class Foo < ActiveRecord::Base
  include HasUrl
end

The bar attribute is not stored in the database, but it is used in a form (using SimpleForm's f.input). I'd like to override the getter for this method so I can set bar based on other attributes and have the form properly pre-fill the value.

The problem is that using attr_accessor in an included block like this will setup the getter on the Foo class. Because the module is included above Foo in the ancestor chain, the custom bar method that returns 0 is never touched.

One way to solve this is

class Foo < ActiveRecord::Base
  include HasUrl

  def bar
    super
  end
end

But I want to avoid this extra step. I just want to include the module and have it just "work". Another option is to use different helpers in my form (f.input_field etc) but then I cannot take advantage of SimpleForm's wrappers.

Module#prepend will not solve my problems either, since HasUrl also defines some other things (notably an ActiveRecord callback). If I prepend, these callbacks cause errors:

NoMethodError: undefined method `_run_...__find__...__callbacks`

Is there a way to get around this error so that prepend can work? Or another way to do this altogether?

like image 343
Logan Serman Avatar asked Feb 17 '23 00:02

Logan Serman


1 Answers

Are you sure you want the attr_accessor? Wouldn't an attr_writer suffice?

require 'active_support/all'

module HasUrl
  extend ActiveSupport::Concern

  included do
    attr_writer :bar
  end

  def bar
    0
  end
end

class Foo
  include HasUrl
end

p Foo.new.bar

Anyhow, if you really want to use attr_accessor, this should work:

require 'active_support/all'

module HasUrl
  extend ActiveSupport::Concern

  included do
    attr_accessor :bar
    define_method :bar do
      0
    end
  end
end

class Foo
  include HasUrl
end

p Foo.new.bar
like image 56
Ju Liu Avatar answered Feb 23 '23 20:02

Ju Liu