Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding the setter throws an error #507

Closed
amingilani opened this issue Oct 13, 2017 · 5 comments
Closed

Overriding the setter throws an error #507

amingilani opened this issue Oct 13, 2017 · 5 comments

Comments

@amingilani
Copy link

My values come with a lot of weird whitespace and padding so, as recommended by the docs I tried to override the accessors

  def price=(value)
    price = value.strip
    super(price)
  end
  
  def quantity=(quantity)
    quantity = quantity.strip
    super(quantity)
  end

This resulted in the following error:

     NoMethodError:
       super: no superclass method `price=' for #<Item:0x007faf30f2f620>
       Did you mean?  price

Is there a workaround for this? For the moment, i'm going to strip it in the controller, but this definitely feels like something the model should be doing.

@samstickland
Copy link

samstickland commented Apr 16, 2018

I think this will work if you prepend a module instead:

class MyRecord < ApplicationRecord
  module StripValues
    def price=(value)
      price = value.strip
      super(price)
    end
  
    def quantity=(quantity)
      quantity = quantity.strip
      super(quantity)
    end
  end

  prepend StripValues

The problem is that the setter methods are defined (via define_method) in your active record class itself, so there is no setter method in ActiveRecord::Base to call. Prepending a module however will prepend the method in your active record class, so when it calls super it will should call the right method.

That is, in the example above when MyRecord#price= is called, it will first invoke MyRecord::StripValues#price= and then when that calls super it will invoke MyRecord#price=

@amingilani
Copy link
Author

Thank you!

@achernik
Copy link

achernik commented Jul 6, 2018

There is also another way to handle this problem:

  alias price_from_monetize= price=

  def price=(value)
    price = value.strip
    self.price_from_monetize = price
  end

@rockwellll
Copy link

rockwellll commented Nov 2, 2022

There is also another way to handle this problem:

  alias price_from_monetize= price=

  def price=(value)
    price = value.strip
    self.price_from_monetize = price
  end

I'm sorry but im dumbfounded and cant seem to understand how this works. Could you clarify? Thanks. @achernik

@dorianmariecom
Copy link

@rockwellll A common idiom is to do alias old_price= price= so you have an alias of the current price= method named old_price= that will be used later.

Then we override price=, do our custom code (the strip) and call the aliased method (the old_price= method, here named price_from_monetize=)

hope this helps

jbennett added a commit to jbennett/money-rails that referenced this issue Jul 3, 2024
Currently you cannot override the generated methods and access super ie:

```ruby
monetize :price_cents

def price=(value)
   # stuff
   super # NoMethodError
end
```

This happens because the method is defined on the class directly so their is no super method to call. A solution today is to create an alias (`alias :old_price= :price=`) before overriding the method as is recommending in issue RubyMoney#507.

Instead, a new module can be created, included into the class, and the methods defined on it allowing `super` to work as expected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants