Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord::Base.store automatic typecasting

Is there a way to automatically typecast values that are stored using ActiveRecord::Base.store?

Take this totally impractical example:

class User < ActiveRecord::Base
  store :settings, accessors: [ :age ]
end

user = User.new(age: '10')
user.age # => '10'

I know I can just override the reader method for age to convert it to an integer, but I was curious if there was an undocumented way of doing it.

Trying to avoid this:

class User < ActiveRecord::Base
  store :settings, accessors: [ :age ]

  def age
    settings[:age].to_i
  end
end

user = User.new(age: '10')
user.age # => 10

Update

Looking for something like:

class User < ActiveRecord::Base
  store :settings, accessors: {:age => :to_i}
end

Or:

class User < ActiveRecord::Base
  store :settings, accessors: {:age => Integer}
end
like image 745
Peter Brown Avatar asked Oct 08 '22 04:10

Peter Brown


3 Answers

As of Rails 3.2.7 there is not a way to automatically typecast values. I'll update this question if I ever come across a way to do it :/

like image 52
Peter Brown Avatar answered Oct 12 '22 02:10

Peter Brown


I know of two ways to do it. One of them you convert it every time it is set. The other you convert it only when you save it to the database.

Option one: custom setter

class User < ActiveRecord::Base

  ...

  # public method
  def age=(age)
    self.settings[:age] = age.to_i
  end

  ...

end

In console:

$ user.age = '12'     # => "12"
$ user.age            # => 12
$ user.age.class      # => Fixnum
$ user = User.new age: '5'
$ user.age.class      # => Fixnum

Option two: before_save call (or different before call)

class User < ActiveRecord::Base
  before_save :age_to_int

  ...

  private

    def age_to_int
      # uncomment the if statement to avoid age being set to 0
      # if you create a user without an age
      self.age = self.age.to_i # if self.age 
    end

end

In console

$ user = User.new(age: '10')
$ user.save
$ user.age            # => 10
$ user.age.class      # => Fixnum

Shortcoming of option two:

$ user.age = '12'
$ user.age            # => "12"

I'd use the custom setter if I were you. If you want a default value independent of the database column (which is a string), use a before_save in addition to the setter.

like image 40
AJcodez Avatar answered Oct 12 '22 02:10

AJcodez


Storext adds type-casting and other features on top of ActiveRecord::Store.store_accessor.

like image 1
Ramon Tayag Avatar answered Oct 12 '22 02:10

Ramon Tayag