2016-08-18 4 views
1

更新:数字をプリントアウトするときJavascriptとRailsの数の検証

、彼らは実際にはまったく同じであり、両方の2つだけ小数点以下の桁を示しています。また、私のデータベースでは、これらの値は、精度8と位取り2の小数点以下の型です。

私のレールアプリにはピースモデルがあります。このモデルには、artist_cutとtotal_priceの2つのフィールドがあります。作品の編集フォームには、artist_cutに基づいて作品のtotal_priceを計算するjavascriptがいくつかあります。私は、ユーザーがそのフィールドを編集できないように、artist_cutのreadonlyフィールドを使用しました。

しかし、readonlyフィールドは簡単に壊れている可能性があります。そのため、ピースのtotal_priceが自分が望む値であることを確認する検証を追加しました。そうでない場合は、エラーをスローします。

妥当性検査は、3892と3898の間を除くすべてのartist_cutsで動作します。これらのケースでは、javascriptによって生成された値とルビによって生成された値が等しくないと考えています。これをどうすれば解決できますか?

_form.html.erb

<div class="form-group"> 
    <%= f.label :artist_cut %><br> 
    <%= f.text_field :artist_cut, class: "form-control", id: "artist_cut" %> 
</div> 

<div class="form-group"> 
    <%= f.label :total_price %><br> 
    <%= f.text_field :total_price, class: "form-control", id: "total_price", readonly: true %> 
</div> 

<script> 
    $(document).on("change", "#artist_cut", function() { 
     var artist_cut = $("#artist_cut").val() || 0; 
     $("#total_price").val(Math.ceil((((artist_cut*2.19)+0.3)/(1-0.029))*100)/100); 
    }); 
</script> 

piece.rb

validates :artist_cut, presence: true, format: { with: /\A\d+(?:\.\d{0,2})?\z/ }, numericality: { greater_than: 0.5, less_than: 443378.86 } 
validates :total_price, presence: true, format: { with: /\A\d+(?:\.\d{0,2})?\z/ }, numericality: true 
validate :total_price_validation 


def total_price_validation 
    return if self.total_price == ((((self.artist_cut*2.19)+0.3)/(1-0.029))*100).ceil/100.0 
    errors.add(:total_price, "cannot be changed") 
end 

おかげ

+0

これは、浮動小数点比較を行っていることに注意してください。コンピュータは分母が2のべき乗である有理数のみを正確に表すことができるため、小さな丸め誤差が発生します。代わりに、期待値と真値の差の絶対値が正しいかどうかを確認する必要があります。 – csander

+0

@canderこの絶対値の違いをどのように確認できますか? –

+0

@ canderあなたが言っていることを理解しています。バリデーションでは、総価格からフォーミュラの値を差し引いた差の絶対値が0.0000000001以下であることを確認しました。これは美しく働いた。これを答えとして入力すると、正しいとマークすることができます:) –

答えて

0

浮動小数点比較を行っていることに注意してください。コンピュータは分母が2のべき乗である有理数のみを正確に表すことができるため、小さな丸め誤差が発生します。代わりに、期待値と真値の差の絶対値が非常に小さいかどうかを確認する必要があります。

+0

このコードの実装は\t \t 'return if(self(self-artist_cut * 2.19)+0.3)/(1-0.029))* 100).ceil/100.0).abs <= 0.0000000001 ' –

0

たぶん、あなたは、小数点以下2桁の両方を丸め試すことができますか?これはcsanderが述べたように、浮動小数点計算の小さな違いを修正するかもしれません。

Math.round(Math.ceil((((artist_cut*2.19)+0.3)/(1-0.029))*100)/100, 2) 


(((((self.artist_cut*2.19)+0.3)/(1-0.029))*100).ceil/100.0).round(2) 
+0

私はこれをやったが、うまくいかなかった。とにかく.ceilメソッドはそれらを丸める役目を果たしていないのですか? –

+0

また、これは最も近い整数にjavascriptを丸めるように思われる –

0

他で指摘されているように、浮動小数点比較はユーザーのニーズに適していないという問題があります。解決策は、artist_cut列をDecimal型に変更することです(使用しているデータベースのドキュメントを確認してください)。コード内のfloat値をBigDecimalに置き換えます。

def total_price_validation 
    return if self.total_price == ((((self.artist_cut * "2.19".to_d)+"0.3".to_d)/(1 - "0.029".to_d)) * 100).ceil/100 
+0

artist_cutは常に小数点型です。あなたが指定したto_dメソッドを試しましたが、同じエラーが発生しました。助言がありますか? –

+0

これは実際に動作していた他のケースでも実際には動作しません。 –