Allowing commas in a numerical field

醉酒当歌 提交于 2019-12-06 05:52:59

问题


This is such a dumb question that I feel like I must be missing something simple. I have a form with a quantity field. People keep typing commas when they enter the quantity (for example, they type 12,000 to indicate twelve thousand) so I would like to strip out the commas before saving the quantity (12000 in the example) into an integer column in the database.

So far I have tried two methods. Overriding the setter method as suggested in this SO question

  def quantity=(num)
    num.gsub!(',', '') if num.is_a?(String)
    self[:quantity] = num.to_i
  end

This works in a sense. If I type 12,000 in the quantity field and submit the form, I get 12000 in the database. The problem is that it also bypasses all quantity validations. No longer can I validate the presence of a value for quantity for example. This is not good.

I have also tried to use a before validation callback (instead of overriding the setter):

  before_validation :sanitize_quantity

  def sanitize_quantity
    # Doesn't wok because quantity.to_i already called by this point.
  end

This doesn't work because by the time the quantity has reached the callback method, Rails has already called to_i on it. This means that 12,000 will be truncated to 12 by the time it reaches the callback. Once again, not good.

What else can I try aside from stripping the commas on the client-side?

As a final note, I am aware that this is essentially a dumb thing to do because certain countries use periods and commas in different ways. I still need to do it anyway.


回答1:


Use Type Coercions

If I understand your question correctly, you're trying to coerce strings into numbers. If so, you can just use an explicit cast like so:

validates :quantity, presence: true, numericality: true

def quantity=(num)
  self[:quantity] = num.to_s.scan(/\b-?[\d.]+/).join.to_f
end

Tests and Examples

See see how this works, you can try the following at the console.

# String as input.
number = '12,956.05'
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05

# Float as input.
number = 12956.05
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05

# Using an ActiveRecord object.
q = Quantity.new quantity: '12,956.05'
=> #<Quantity id: nil, quantity: 12956.05, created_at: nil, updated_at: nil>
q.save
=> true



回答2:


I actually figured this out just as I was reading over my question.

The key is to use a virtual attribute.

class Job < ActiveRecord::Base
  def flexible_quantity
    quantity
  end

  def flexible_quantity=(quantity)
    self.quantity = quantity.gsub(',', '') unless quantity.blank?
  end
 end

Then in the form, use the virtual attribute.

<%= f.text_field :flexible_quantity %>

Now validate the presence of the flexible_quantity value instead.

class Job < ActiveRecord::Base
  validates :flexible_quantity, presence: true

  # The cool this is that we can leave the numericality validation on the quantity field.
  validates :quantity, presence: true, numericality: { only_integer: true }
end



回答3:


You'll get the quantity in params[:quanity]. You can just call a helper method (defined in your controller, for instance) to fix the String, and then pass that along to your model.

# YourController.rb
def create # or whatever
    quantity = sanitize_quantity(params[:quantity])
    YourModel.create!(:quantity => quantity)
end

private

    def sanitize_quantity(num)
        num.gsub!(',', '') if num.is_a?(String)
        return num.to_i
    end

So you sanitize it before it goes to your model, so it can still have validations done on it.



来源:https://stackoverflow.com/questions/11585062/allowing-commas-in-a-numerical-field

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!