3

If I override a getter and setter in my model, what's the best way to create default initial values for that attribute in my controller?

For instance, when I create a new instance of the model in the controller to include some initial values, the pre-populated values in the form show the output from the setter rather than the getter.

How should this be done?

Example

class Something < ActiveModel:Base
  # override getter
  def attr_a
    self[:attr_a] * 5 
  end
  # override setter
  def attr_a=
    self[:attr_a] = attr_a / 5 # i.e. 10 / 5 = 2
  end
end

class SomethingController < ActiveController
  def new
    @something = Something.new({attr_a: 10})
  end
end

# index.html.erb
<% form_for @something do |f| %>
  <% f.text_field :attr_a %>
  <% f.submit 'Save' %>
<% end %>

In this example, the text_field in the form is populated with 2 rather than 10.

I can see why it makes sense to by showing 2 as the setting's being called as part of the object instantiation, but am I going about things the wrong way to get the result I want?

Essentially, data needs to be stored in the database in a different way to how it's used in application logic and what the user should see. I want to make that as seamless as possible.

Turgs
  • 1,729
  • 1
  • 20
  • 49

3 Answers3

2

I would not use the same attribute name. If the value in the DB is different than what your object returns then this is confusing and error prone. Somebody who is unaware of the conversion that takes place will build buggy code like:

Something.where('attr_a < 10')

If you reallyreally have to, then you can read/write the attribute value with read_attribute(:attr_a) and write_attribute(:attr_a, value) from inside the object.

But I'd do something like this: Assuming that you want to store the price of a Product in cents as integer. (Ignoring special cases like nil or form submits with strings and floating point division problems, rounding and so on) :

class Product < ActiveRecord::Base
  def price
    price_in_cents / 100.0
  end 
  def price=(value)
    self.price_in_cents = value * 100
  end
end
Pascal
  • 8,464
  • 1
  • 20
  • 31
  • @dft why would this lead to said exception? i'm not accessing the same method from within `price` or `price=` Though you should check for nil value of `price_in_cents` when dividing. – Pascal Apr 16 '17 at 07:30
  • Facepalm, my bad, will remove – dft Apr 18 '17 at 18:51
1
class Something < ActiveModel:Base
  # override getter
  def attr_a
    self[:attr_a] * 5 
  end
  # override setter
  def attr_a=(value)
    self[:attr_a] = value || attr_a / 5 # i.e. 10 / 5 = 2
  end
end

may be this will work

self[:attr_a] = value || attr_a / 5 # i.e. 10 / 5 = 2

it explain that if value is given then self[:attr_a] = value, otherwise self[:attr_a] = attr_a / 5

setter just a function, you need to give it value def attr_a=(value).

alxibra
  • 727
  • 1
  • 7
  • 12
0
Something.new({attr_a: 10}) will set the value of attr_a to 10, 

so it will call its setter method.

If you want to set default value for the text field you can do,

<%= f.text_field :attr_a, :value => 10 %>
shweta
  • 8,019
  • 1
  • 40
  • 43