Rails decimal returned as string in API












0














I have a field called price in my db which is a decimal field and in my JSON API response it is returned as a String.



I wanted to apply some validations to the field that would allow max 2 digits after period and found out that if I use decimal field I can then apply the precision on DB level.



t.decimal "price", precision: 10, scale: 2



Then I want to calculate total price in a service object:



services/statistics/monthly_rides_generator.rb



class CurrentMonthRidesGenerator
def initialize(current_user)
@current_user = current_user
end

def call
user_current_month_rides_by_day.map do |date, rides_on_day|
{
day: formatted_date(date),
total_distance: total_distance(rides_on_day),
avg_ride: avg_ride(rides_on_day),
avg_price: avg_price(rides_on_day),
total_price: total_price(rides_on_day)
}
end
end

...

def total_price(rides)
rides.map(&:price).sum
end
end


app/api/statistics/stats_api.rb



get '/current_month' do
Statistics::CurrentMonthRidesGenerator.new(current_user).call
end


but in API response this field is a String.



{
"day": "November, 8th",
"total_distance": "9km",
"avg_ride": "9km",
"avg_price": "100.0PLN",
"total_price": "100.0"
}


I want this field to be returned as it was saved because I need a float/decimal number in the front end to then do other calculations.



Why is it returning a String when it is a decimal field? How can I fix it?










share|improve this question
























  • Should I use Money gem to convert it to Float?
    – jedi
    Nov 18 '18 at 1:22
















0














I have a field called price in my db which is a decimal field and in my JSON API response it is returned as a String.



I wanted to apply some validations to the field that would allow max 2 digits after period and found out that if I use decimal field I can then apply the precision on DB level.



t.decimal "price", precision: 10, scale: 2



Then I want to calculate total price in a service object:



services/statistics/monthly_rides_generator.rb



class CurrentMonthRidesGenerator
def initialize(current_user)
@current_user = current_user
end

def call
user_current_month_rides_by_day.map do |date, rides_on_day|
{
day: formatted_date(date),
total_distance: total_distance(rides_on_day),
avg_ride: avg_ride(rides_on_day),
avg_price: avg_price(rides_on_day),
total_price: total_price(rides_on_day)
}
end
end

...

def total_price(rides)
rides.map(&:price).sum
end
end


app/api/statistics/stats_api.rb



get '/current_month' do
Statistics::CurrentMonthRidesGenerator.new(current_user).call
end


but in API response this field is a String.



{
"day": "November, 8th",
"total_distance": "9km",
"avg_ride": "9km",
"avg_price": "100.0PLN",
"total_price": "100.0"
}


I want this field to be returned as it was saved because I need a float/decimal number in the front end to then do other calculations.



Why is it returning a String when it is a decimal field? How can I fix it?










share|improve this question
























  • Should I use Money gem to convert it to Float?
    – jedi
    Nov 18 '18 at 1:22














0












0








0







I have a field called price in my db which is a decimal field and in my JSON API response it is returned as a String.



I wanted to apply some validations to the field that would allow max 2 digits after period and found out that if I use decimal field I can then apply the precision on DB level.



t.decimal "price", precision: 10, scale: 2



Then I want to calculate total price in a service object:



services/statistics/monthly_rides_generator.rb



class CurrentMonthRidesGenerator
def initialize(current_user)
@current_user = current_user
end

def call
user_current_month_rides_by_day.map do |date, rides_on_day|
{
day: formatted_date(date),
total_distance: total_distance(rides_on_day),
avg_ride: avg_ride(rides_on_day),
avg_price: avg_price(rides_on_day),
total_price: total_price(rides_on_day)
}
end
end

...

def total_price(rides)
rides.map(&:price).sum
end
end


app/api/statistics/stats_api.rb



get '/current_month' do
Statistics::CurrentMonthRidesGenerator.new(current_user).call
end


but in API response this field is a String.



{
"day": "November, 8th",
"total_distance": "9km",
"avg_ride": "9km",
"avg_price": "100.0PLN",
"total_price": "100.0"
}


I want this field to be returned as it was saved because I need a float/decimal number in the front end to then do other calculations.



Why is it returning a String when it is a decimal field? How can I fix it?










share|improve this question















I have a field called price in my db which is a decimal field and in my JSON API response it is returned as a String.



I wanted to apply some validations to the field that would allow max 2 digits after period and found out that if I use decimal field I can then apply the precision on DB level.



t.decimal "price", precision: 10, scale: 2



Then I want to calculate total price in a service object:



services/statistics/monthly_rides_generator.rb



class CurrentMonthRidesGenerator
def initialize(current_user)
@current_user = current_user
end

def call
user_current_month_rides_by_day.map do |date, rides_on_day|
{
day: formatted_date(date),
total_distance: total_distance(rides_on_day),
avg_ride: avg_ride(rides_on_day),
avg_price: avg_price(rides_on_day),
total_price: total_price(rides_on_day)
}
end
end

...

def total_price(rides)
rides.map(&:price).sum
end
end


app/api/statistics/stats_api.rb



get '/current_month' do
Statistics::CurrentMonthRidesGenerator.new(current_user).call
end


but in API response this field is a String.



{
"day": "November, 8th",
"total_distance": "9km",
"avg_ride": "9km",
"avg_price": "100.0PLN",
"total_price": "100.0"
}


I want this field to be returned as it was saved because I need a float/decimal number in the front end to then do other calculations.



Why is it returning a String when it is a decimal field? How can I fix it?







ruby-on-rails






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 18 '18 at 2:00

























asked Nov 18 '18 at 1:08









jedi

487416




487416












  • Should I use Money gem to convert it to Float?
    – jedi
    Nov 18 '18 at 1:22


















  • Should I use Money gem to convert it to Float?
    – jedi
    Nov 18 '18 at 1:22
















Should I use Money gem to convert it to Float?
– jedi
Nov 18 '18 at 1:22




Should I use Money gem to convert it to Float?
– jedi
Nov 18 '18 at 1:22












3 Answers
3






active

oldest

votes


















2














It's returning as a string because Decimal/BigDecimal in ruby is a very precise number. Javascript/JSON doesn't have a data type that is as precise as ruby's BigDecimal.



You can easily see this in your browser if you open up the console:
enter image description here



If you convert the value to a float in your serializer then it will be a float in the JSON object that is returned by your API, but you'll want to be careful of how your clients use this data. If they don't use a library that can handle precision then you're going to get rounding errors and often be off on your calculations by a penny.



I've been using the decimal.js library for things like this and it works out great. https://github.com/MikeMcl/decimal.js/






share|improve this answer





















  • Thanx for the rationale. I have some precision validations in db that rounds the number to 2 places after period and my clients will only get numbers with max 2 digits after period so that's not a problem
    – jedi
    Nov 18 '18 at 1:55



















0














One way to solve this is to cast it to the desired type in a serializer:



# app/serializers/your_model_serializer.rb

class YourModelSerializer < ActiveModel::Serializer
attributes :day,
:total_distance,
:avg_ride,
:avg_price,
:total_price

def total_price
object.total_price.to_f
end
end





share|improve this answer





















  • What if this method is not defined on a Model? I have this method defined in a service object. Will that still work?
    – jedi
    Nov 18 '18 at 1:34










  • Sure, you could call the service object from the serializer instead of object.total_price.to_f. EDIT: That is assuming you are calling an action on the controller associated with the serializer (e.g. YourModelController and YourModelSerializer).
    – Troy Carlson
    Nov 18 '18 at 1:45








  • 1




    If you update the question with more details about where the total_price method is defined, what the controller looks like, etc. I can provide a more definitive answer.
    – Troy Carlson
    Nov 18 '18 at 1:49










  • Can I not simply call to_f on it?
    – jedi
    Nov 18 '18 at 2:24










  • Well I'm not sure how Rails behaves when you call a service object directly within a route like you are doing...my solution works when you are using a more traditional controller + serializer convention, where subclasses of ActiveModel::Serializer give you more control over how Rails serializes the response.
    – Troy Carlson
    Nov 19 '18 at 3:11



















0














I decided to solve this problem by changing the column type to Float, renaming it to price_cents, adding money-rails and monetizing the column. Then I just call to_f or round the value right before displaying it or sending it to front-end in API response.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53357032%2frails-decimal-returned-as-string-in-api%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    It's returning as a string because Decimal/BigDecimal in ruby is a very precise number. Javascript/JSON doesn't have a data type that is as precise as ruby's BigDecimal.



    You can easily see this in your browser if you open up the console:
    enter image description here



    If you convert the value to a float in your serializer then it will be a float in the JSON object that is returned by your API, but you'll want to be careful of how your clients use this data. If they don't use a library that can handle precision then you're going to get rounding errors and often be off on your calculations by a penny.



    I've been using the decimal.js library for things like this and it works out great. https://github.com/MikeMcl/decimal.js/






    share|improve this answer





















    • Thanx for the rationale. I have some precision validations in db that rounds the number to 2 places after period and my clients will only get numbers with max 2 digits after period so that's not a problem
      – jedi
      Nov 18 '18 at 1:55
















    2














    It's returning as a string because Decimal/BigDecimal in ruby is a very precise number. Javascript/JSON doesn't have a data type that is as precise as ruby's BigDecimal.



    You can easily see this in your browser if you open up the console:
    enter image description here



    If you convert the value to a float in your serializer then it will be a float in the JSON object that is returned by your API, but you'll want to be careful of how your clients use this data. If they don't use a library that can handle precision then you're going to get rounding errors and often be off on your calculations by a penny.



    I've been using the decimal.js library for things like this and it works out great. https://github.com/MikeMcl/decimal.js/






    share|improve this answer





















    • Thanx for the rationale. I have some precision validations in db that rounds the number to 2 places after period and my clients will only get numbers with max 2 digits after period so that's not a problem
      – jedi
      Nov 18 '18 at 1:55














    2












    2








    2






    It's returning as a string because Decimal/BigDecimal in ruby is a very precise number. Javascript/JSON doesn't have a data type that is as precise as ruby's BigDecimal.



    You can easily see this in your browser if you open up the console:
    enter image description here



    If you convert the value to a float in your serializer then it will be a float in the JSON object that is returned by your API, but you'll want to be careful of how your clients use this data. If they don't use a library that can handle precision then you're going to get rounding errors and often be off on your calculations by a penny.



    I've been using the decimal.js library for things like this and it works out great. https://github.com/MikeMcl/decimal.js/






    share|improve this answer












    It's returning as a string because Decimal/BigDecimal in ruby is a very precise number. Javascript/JSON doesn't have a data type that is as precise as ruby's BigDecimal.



    You can easily see this in your browser if you open up the console:
    enter image description here



    If you convert the value to a float in your serializer then it will be a float in the JSON object that is returned by your API, but you'll want to be careful of how your clients use this data. If they don't use a library that can handle precision then you're going to get rounding errors and often be off on your calculations by a penny.



    I've been using the decimal.js library for things like this and it works out great. https://github.com/MikeMcl/decimal.js/







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 18 '18 at 1:51









    Jimmy Baker

    2,2871520




    2,2871520












    • Thanx for the rationale. I have some precision validations in db that rounds the number to 2 places after period and my clients will only get numbers with max 2 digits after period so that's not a problem
      – jedi
      Nov 18 '18 at 1:55


















    • Thanx for the rationale. I have some precision validations in db that rounds the number to 2 places after period and my clients will only get numbers with max 2 digits after period so that's not a problem
      – jedi
      Nov 18 '18 at 1:55
















    Thanx for the rationale. I have some precision validations in db that rounds the number to 2 places after period and my clients will only get numbers with max 2 digits after period so that's not a problem
    – jedi
    Nov 18 '18 at 1:55




    Thanx for the rationale. I have some precision validations in db that rounds the number to 2 places after period and my clients will only get numbers with max 2 digits after period so that's not a problem
    – jedi
    Nov 18 '18 at 1:55













    0














    One way to solve this is to cast it to the desired type in a serializer:



    # app/serializers/your_model_serializer.rb

    class YourModelSerializer < ActiveModel::Serializer
    attributes :day,
    :total_distance,
    :avg_ride,
    :avg_price,
    :total_price

    def total_price
    object.total_price.to_f
    end
    end





    share|improve this answer





















    • What if this method is not defined on a Model? I have this method defined in a service object. Will that still work?
      – jedi
      Nov 18 '18 at 1:34










    • Sure, you could call the service object from the serializer instead of object.total_price.to_f. EDIT: That is assuming you are calling an action on the controller associated with the serializer (e.g. YourModelController and YourModelSerializer).
      – Troy Carlson
      Nov 18 '18 at 1:45








    • 1




      If you update the question with more details about where the total_price method is defined, what the controller looks like, etc. I can provide a more definitive answer.
      – Troy Carlson
      Nov 18 '18 at 1:49










    • Can I not simply call to_f on it?
      – jedi
      Nov 18 '18 at 2:24










    • Well I'm not sure how Rails behaves when you call a service object directly within a route like you are doing...my solution works when you are using a more traditional controller + serializer convention, where subclasses of ActiveModel::Serializer give you more control over how Rails serializes the response.
      – Troy Carlson
      Nov 19 '18 at 3:11
















    0














    One way to solve this is to cast it to the desired type in a serializer:



    # app/serializers/your_model_serializer.rb

    class YourModelSerializer < ActiveModel::Serializer
    attributes :day,
    :total_distance,
    :avg_ride,
    :avg_price,
    :total_price

    def total_price
    object.total_price.to_f
    end
    end





    share|improve this answer





















    • What if this method is not defined on a Model? I have this method defined in a service object. Will that still work?
      – jedi
      Nov 18 '18 at 1:34










    • Sure, you could call the service object from the serializer instead of object.total_price.to_f. EDIT: That is assuming you are calling an action on the controller associated with the serializer (e.g. YourModelController and YourModelSerializer).
      – Troy Carlson
      Nov 18 '18 at 1:45








    • 1




      If you update the question with more details about where the total_price method is defined, what the controller looks like, etc. I can provide a more definitive answer.
      – Troy Carlson
      Nov 18 '18 at 1:49










    • Can I not simply call to_f on it?
      – jedi
      Nov 18 '18 at 2:24










    • Well I'm not sure how Rails behaves when you call a service object directly within a route like you are doing...my solution works when you are using a more traditional controller + serializer convention, where subclasses of ActiveModel::Serializer give you more control over how Rails serializes the response.
      – Troy Carlson
      Nov 19 '18 at 3:11














    0












    0








    0






    One way to solve this is to cast it to the desired type in a serializer:



    # app/serializers/your_model_serializer.rb

    class YourModelSerializer < ActiveModel::Serializer
    attributes :day,
    :total_distance,
    :avg_ride,
    :avg_price,
    :total_price

    def total_price
    object.total_price.to_f
    end
    end





    share|improve this answer












    One way to solve this is to cast it to the desired type in a serializer:



    # app/serializers/your_model_serializer.rb

    class YourModelSerializer < ActiveModel::Serializer
    attributes :day,
    :total_distance,
    :avg_ride,
    :avg_price,
    :total_price

    def total_price
    object.total_price.to_f
    end
    end






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 18 '18 at 1:24









    Troy Carlson

    2,0071022




    2,0071022












    • What if this method is not defined on a Model? I have this method defined in a service object. Will that still work?
      – jedi
      Nov 18 '18 at 1:34










    • Sure, you could call the service object from the serializer instead of object.total_price.to_f. EDIT: That is assuming you are calling an action on the controller associated with the serializer (e.g. YourModelController and YourModelSerializer).
      – Troy Carlson
      Nov 18 '18 at 1:45








    • 1




      If you update the question with more details about where the total_price method is defined, what the controller looks like, etc. I can provide a more definitive answer.
      – Troy Carlson
      Nov 18 '18 at 1:49










    • Can I not simply call to_f on it?
      – jedi
      Nov 18 '18 at 2:24










    • Well I'm not sure how Rails behaves when you call a service object directly within a route like you are doing...my solution works when you are using a more traditional controller + serializer convention, where subclasses of ActiveModel::Serializer give you more control over how Rails serializes the response.
      – Troy Carlson
      Nov 19 '18 at 3:11


















    • What if this method is not defined on a Model? I have this method defined in a service object. Will that still work?
      – jedi
      Nov 18 '18 at 1:34










    • Sure, you could call the service object from the serializer instead of object.total_price.to_f. EDIT: That is assuming you are calling an action on the controller associated with the serializer (e.g. YourModelController and YourModelSerializer).
      – Troy Carlson
      Nov 18 '18 at 1:45








    • 1




      If you update the question with more details about where the total_price method is defined, what the controller looks like, etc. I can provide a more definitive answer.
      – Troy Carlson
      Nov 18 '18 at 1:49










    • Can I not simply call to_f on it?
      – jedi
      Nov 18 '18 at 2:24










    • Well I'm not sure how Rails behaves when you call a service object directly within a route like you are doing...my solution works when you are using a more traditional controller + serializer convention, where subclasses of ActiveModel::Serializer give you more control over how Rails serializes the response.
      – Troy Carlson
      Nov 19 '18 at 3:11
















    What if this method is not defined on a Model? I have this method defined in a service object. Will that still work?
    – jedi
    Nov 18 '18 at 1:34




    What if this method is not defined on a Model? I have this method defined in a service object. Will that still work?
    – jedi
    Nov 18 '18 at 1:34












    Sure, you could call the service object from the serializer instead of object.total_price.to_f. EDIT: That is assuming you are calling an action on the controller associated with the serializer (e.g. YourModelController and YourModelSerializer).
    – Troy Carlson
    Nov 18 '18 at 1:45






    Sure, you could call the service object from the serializer instead of object.total_price.to_f. EDIT: That is assuming you are calling an action on the controller associated with the serializer (e.g. YourModelController and YourModelSerializer).
    – Troy Carlson
    Nov 18 '18 at 1:45






    1




    1




    If you update the question with more details about where the total_price method is defined, what the controller looks like, etc. I can provide a more definitive answer.
    – Troy Carlson
    Nov 18 '18 at 1:49




    If you update the question with more details about where the total_price method is defined, what the controller looks like, etc. I can provide a more definitive answer.
    – Troy Carlson
    Nov 18 '18 at 1:49












    Can I not simply call to_f on it?
    – jedi
    Nov 18 '18 at 2:24




    Can I not simply call to_f on it?
    – jedi
    Nov 18 '18 at 2:24












    Well I'm not sure how Rails behaves when you call a service object directly within a route like you are doing...my solution works when you are using a more traditional controller + serializer convention, where subclasses of ActiveModel::Serializer give you more control over how Rails serializes the response.
    – Troy Carlson
    Nov 19 '18 at 3:11




    Well I'm not sure how Rails behaves when you call a service object directly within a route like you are doing...my solution works when you are using a more traditional controller + serializer convention, where subclasses of ActiveModel::Serializer give you more control over how Rails serializes the response.
    – Troy Carlson
    Nov 19 '18 at 3:11











    0














    I decided to solve this problem by changing the column type to Float, renaming it to price_cents, adding money-rails and monetizing the column. Then I just call to_f or round the value right before displaying it or sending it to front-end in API response.






    share|improve this answer


























      0














      I decided to solve this problem by changing the column type to Float, renaming it to price_cents, adding money-rails and monetizing the column. Then I just call to_f or round the value right before displaying it or sending it to front-end in API response.






      share|improve this answer
























        0












        0








        0






        I decided to solve this problem by changing the column type to Float, renaming it to price_cents, adding money-rails and monetizing the column. Then I just call to_f or round the value right before displaying it or sending it to front-end in API response.






        share|improve this answer












        I decided to solve this problem by changing the column type to Float, renaming it to price_cents, adding money-rails and monetizing the column. Then I just call to_f or round the value right before displaying it or sending it to front-end in API response.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 18 '18 at 22:04









        jedi

        487416




        487416






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53357032%2frails-decimal-returned-as-string-in-api%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to send String Array data to Server using php in android

            Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

            Is anime1.com a legal site for watching anime?