Parameters not getting saved in Rails 3 app -
i rails 3 beginner working on application allows user enter monetary values. using jquery plugin (http://github.com/plentz/jquery-maskmoney) display decimal values monetary values on edit page. decimal attributes manipulated currency when editing. when saving the, purchase_price , capital_reserves saved correctly. property before_save function called , currency values ($123.45) converted decimal values (123.45).
the problem associated rent values never saved if edit rent prices. can see correct values being sent in parameters before_save code in rent model never triggered. if edit apartment number value , rent price, rent price saved correctly. also, after can edit price apartment number modified. however, other rent price not updated.
i using mysql , rails 3.0.9
steps reproduce: non-issue
- edit property
- modify property's purchase price and/or capital reserves value
- click update
- these values converted currency values ($1,234.56) decimal (1234.56) before_save code in property
issue
- edit property
- modify property's rent current price and/or market price values
- click update
- these values not saved. before_save code not called in rent model.
issue
- edit property
- modify property's purchase price and/or capital reserves value, edit apartment number
- click update
- these values saved correctly.
- now can edit price values row saved , prices saved. why?
i made small project showcase if interested (https://github.com/michaelklem/money-test).
here data models.
property class
class property < activerecord::base before_save :handle_before_save has_many :rents, :dependent => :destroy accepts_nested_attributes_for :rents, :allow_destroy => true def handle_before_save if new_record? generate_default_rent_data end remove_currency_formatting end def generate_default_rent_data 10.times |i| self.rents.build(:apartment_number => i+1) end end def remove_currency_formatting if self.capital_reserves.to_s != self.capital_reserves_before_type_cast.to_s self.capital_reserves = property.remove_currency_format(self.capital_reserves_before_type_cast) end if self.purchase_price.to_s != self.purchase_price_before_type_cast.to_s self.purchase_price = property.remove_currency_format(self.purchase_price_before_type_cast) end end # # handles removing characters currency objects # except 0-9 , . # def self.remove_currency_format(currency_attribute) currency_attribute.gsub(/[^0-9.]/, "") end end
rent class:
class rent < activerecord::base belongs_to :property before_save :handle_before_save def handle_before_save remove_currency_formatting end def remove_currency_formatting if self.current_price.to_s != self.current_price_before_type_cast.to_s self.current_price = property.remove_currency_format(self.current_price_before_type_cast) end if self.market_price.to_s != self.market_price_before_type_cast.to_s self.market_price = property.remove_currency_format(self.market_price_before_type_cast) end end end
not sure if seeing bug or missing obvious. looking this.
update
after posted found question stripping first character of string helped me figure out. still seems me original issue bug.
i able simplify code following , works.
class property < activerecord::base before_save :handle_before_save has_many :rents, :dependent => :destroy accepts_nested_attributes_for :rents, :allow_destroy => true def handle_before_save if new_record? generate_default_rent_data end end def purchase_price=(data) if data.is_a?(string) data = property.remove_currency_format(data) write_attribute(:purchase_price, data) end end def capital_reserves=(data) if data.is_a?(string) data = property.remove_currency_format(data) write_attribute(:capital_reserves, data) end end # # generate default data # def generate_default_rent_data 10.times |i| self.rents.build(:apartment_number => i+1) # provide default value apartment numbers end end def self.remove_currency_formatting(data) if data.is_a?(string) data = property.remove_currency_format(data) end return data end # # handles removing characters currency objects # except 0-9 , . # def self.remove_currency_format(currency_attribute) currency_attribute.gsub(/[^0-9.]/, "") end def purchase_price=(data) _write_attribute(:purchase_price, data) end def capital_reserves=(data) _write_attribute(:capital_reserves, data) end private def _write_attribute(attribute, data) write_attribute(attribute, property.remove_currency_formatting(data)) end end class rent < activerecord::base belongs_to :property def current_price=(data) _write_attribute(:current_price, data) end def market_price=(data) _write_attribute(:market_price, data) end private def _write_attribute(attribute, data) write_attribute(attribute, property.remove_currency_formatting(data)) end end
this may helpful, , might clean lot of write_attribute code if chose use it.
in our app, run issue frequently, have tons of amount fields , hellish add logic each model (almost every table has decimal fields amounts). in initializer, added following:
activerecord::connectionadapters::column.class_eval def type_cast_with_commas_removed(value) if type == :decimal && value.is_a?(string) value = value.delete(',') end type_cast_without_commas_removed(value) end alias_method_chain :type_cast, :commas_removed end class bigdecimal alias :old_to_s :to_s def to_s(s=nil) if s.nil? parts = ("%.2f" % self).split('.') parts[0].gsub!(/(\d)(?=(\d{3})+(?!\d))/, "\\1,") parts.join('.') else old_to_s(s) end end end
this achieves 2 things: first, on insertion database, commas stripped decimal field entries if value string (you change use regex of grabbing numbers , period). second, when bigdecimal converted string commas re-inserted (this business requirement in our case wanted display proper formatting @ times, may not need).
anyway, know solved problem, wanted give approach. :)
cheers!
Comments
Post a Comment