I am creating some table data in a Rails-React application.
I had creating this piece of data here in console:
2.3.3 :024 > Crop.create date: Date.today, cropname: 'Radishes', ismetric: false, bagspackaged: '20', unitweight: '0.5', totalweight: '10'
Today I realized that Rails did not accept the 0.5 decimal for unitweight and no matter how I try to update it in console, it does not save.
This is my schema.rb file:
ActiveRecord::Schema.define(version: 20171004224716) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "crops", force: :cascade do |t|
t.date "date"
t.string "cropname"
t.boolean "ismetric"
t.integer "bagspackaged"
t.integer "unitweight"
t.integer "totalweight"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Two issues here
First you have given the data type integer to unitweight and totalweight, while you should have given it decimal or float in order to accept and store fractions. decimal data type with precision is better as it will give you more accurate result as stated below in the comments' section.
when you use decimal you can control it by The precision which is total number of digits in a number, whereas scale is number of digits following the decimal point.
here is an example
add_column :tickets, :price, :decimal, precision: 5, scale: 2
this will allow you to store decimal numbers like these 60.00, 80.99 and 100.00
Second you are passing string to integer, it is not a problem because rails will convert it to integer as long as it is a valid integer otherwise it will be 0. But generally it is not a good practice.
I would avoid rolling back your crops table, it would just be more work. It is up to you.
I would just do:
rails g migration ChangeUnitweightToFloat
Inside that file I would configure like so:
class ChangeUnitweightToFloat < ActiveRecord::Migration
def change
change_column :crops, :unitweight, :float
end
end
With these two steps, you should be go to go.
For future reference, please keep in mind that if you want to work with decimals, it will either be a t.decimal or t.float.
That isn't a decimal, it's a string. Don't put quotes around your numeric literals.
Crop.create(
date: Date.today,
cropname: 'Radishes',
ismetric: false,
bagspackaged: 20,
unitweight: 0.5,
totalweight: 10
)
You could use a decimal (or float) type field instead of an integer:
create_table "crops", force: :cascade do |t|
t.decimal "unitweight"
end
and then don't use quotes around the value:
2.3.3 :024 > Crop.create date: Date.today, cropname: 'Radishes', ismetric: false, bagspackaged: '20', unitweight: 0.5, totalweight: '10'
Related
I'm trying to seed some data using an external trivia API.
Here's what I have in my seeds.rb file where HTTParty is a gem that parses JSON into a ruby hash:
response = HTTParty.get("THE-API-SITE")
response.each do |trivia|
triviaHash = {
category: trivia["category"],
answer: trivia["correctAnswer"],
incorrect: trivia["incorrectAnswers"],
question: trivia["question"],
}
Trivia.find_or_create_by(triviaHash)
end
And here's my schema:
create_table "trivia", force: :cascade do |t|
t.string "category"
t.string "answer"
t.string "incorrect"
t.string "question"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "ids"
end
Everything works except for the "incorrect" key which should have a value of an array of strings of incorrect answers, but when I seed my data, I get a string of the array of incorrect answers.
What I want:
incorrect: ["Deep Purple", "Feeder", "Uriah Heep"],
What I'm getting:
incorrect: "["Deep Purple", "Feeder", "Uriah Heep"]",
I'm not sure how to get what I want or if it's even possible the way I'm going about it.
Since your column incorrect is of type string, so the data stored in DB will also be a string value.
If your DB supports array data type then you can use that or else I would suggest you to use this in your model.
serialize :incorrect, Array
Change your migration field for incorrect field, from:
t.string "incorrect"
to:
t.text :incorrect, array: true, default: []
Also I suggest you to use symbols instead of strings for column names and use t.timestamps that generates created_at and updated_at for you
I am trying to add a date of birth to each patient in my database and having issues adding a date to the dob attribute on each patient. When I add for ex. Patient.first(dob: "01/25/1990") I get an error reading no implicit conversion of Integer into Hash. Any ideas on how I would do so?
create_table "patients", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.integer "age"
t.date "dob"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
When I seeded my database, my dob field was nil
I have also tried Patient.first(dob: Date.parse('31-12-2010')) and still get the same error.
You have two problems:
first doesn't take query arguments.
Your date format is ambiguous.
The first finder method looks like:
first(limit = nil)
Find the first record (or first N records if a parameter is supplied). If no order is defined it will order by primary key.
You want to use find_by as your .where(...).first shortcut.
And to avoid ambiguity with your dates, you should use Date objects or ISO-8601 formatted strings (i.e. YYYY-MM-DD) inside the application and leave the supposedly "human friendly" formats for the very edges.
You want to say:
Patient.find_by(dob: '1990-01-25')
My Schedule model looks like this:
create_table "schedules", force: :cascade do |t|
t.integer "week_day"
t.time "opening_time"
t.time "closing_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "taco_place_id"
end
add_index "schedules", ["taco_place_id"], name: "index_schedules_on_taco_place_id"
As you can see, there are opening_time and closing_time properties and I have a realtionship Schedule belongs_to :taco_place and TacoPlace has_many :schedules, dependent: :destroy.
What I am trying to do from the Schedule model is to get the actual schedule for a TacoPlace for today (if it exists).
I have already implemented a scope for having today's schedules for a TacoPlace (depending on the week_day property) that looks like this:
scope :today_for_taco_place, ->(taco_place){where(taco_place_id: taco_place.id, week_day: Time.now.wday)}
and I'm using it in this method:
def self.actual_for_taco_place(taco_place)
today = self.today_for_taco_place(taco_place)
today.where("opening_time <= :now and closing_time >= :now", now: Time.now.utc).first
end
I have tested it and it "works". The thing is that if I run "Schedule.first.opening_time" on the console I get "2000-01-01 06:00:00 UTC". As you can see, it does not only include the time, but also the day (even if it was seeded as "opening_time: "15:00".to_time, closing_time: "24:00".to_time").
Finally, here is the question:
Is there a way that I can run something like this: (I know this won't work yet)
def self.actual_for_taco_place(taco_place)
today = self.today_for_taco_place(taco_place)
today.where("#{opening_time.strftime("%H%M")} <= :now and #{closing_time.strftime("%H%M") >= :now", now: Time.now.utc.strftime("%H%M")).first
end
So that the .where() method doesn't look for the property (opening_time or closing_time), but rather perform the strftime() method so I can compare the time only? Or should I save the opening_time and closing_time as integers (i.e. "1200") or manually convert them in a method?
Sorry if my question was long or hard to understand. Thank you in advance for your advise.
Opening_time and closing_time are now integers. I figured out that I don't gain anything from it being a "time" instead of an "integer" since it is only representing an hour.
I have a model that uses floating points to store geolocations. It stores the data in MySQL, using ActiveRecord, Rails 3.2.x.
c = Camping.new()
c.latitude=51.77802459999999
c.save
c.latitude
=> 51.77802459999999
c.reload
c.latitude
=> 51.778
When looking in the database, I confirm it is stored as 51.778. Other numbers are stored with more precision, I have the idea the 0 is what makes either ActiveRecord or MySQL decide to omit the rest.
What decides that the number could or should be chopped off after three digits? Is there anything to control this? Is float the correct type to store this in?
I want a precision of 6, never more, but could be less, or padded. So when 51.7780 is provided, it might be stored as 51.7780 or as 51.778000. When 51.77802459999999is provided, it could be stored as 51.778025 or as the number with full precision; I don't really care.
Relevant part from schema.rb:
create_table "campings", :force => true do |t|
#...
t.float "latitude"
t.float "longitude"
end
Apparently, MySQL is the problem, as float is described as an approximated value.
You can use decimal instead, and specify the precision and scale:
create_table "campings", :force => true do |t|
#...
t.decimal "latitude", :precision => 15, :scale => 10
t.decimal "longitude", :precision => 15, :scale => 10
end
I have an Rails application that defines a migration that contains a decimal with precision 8 and scale 2. The database I have set up is PostgreSQL 9.1 database.
class CreateMyModels < ActiveRecord::Migration
def change
create_table :my_models do |t|
t.decimal :multiplier, precison: 8, scale: 2
t.timestamps
end
end
end
When I run rake db:migrate, the migration happens successfully, but I noticed an error when I was trying to run a MyModel.find_or_create_by_multiplier. If I ran the following command twice, the object would get created twice:
MyModel.find_or_create_by_multiplier(multiplier: 0.07)
I am assuming this should create the object during the first call and then find the object during the second call. Unfortunately, this does not seem to be happening with the multiplier set to 0.07.
This DOES work as expected for every other number I have thrown at the above command. The following commands work as expected (creating the object during the first call and then finding the object during the second call).
MyModel.find_or_create_by_multiplier(multiplier: 1.0)
MyModel.find_or_create_by_multiplier(multiplier: 0.05)
MyModel.find_or_create_by_multiplier(multiplier: 0.071)
When I view the PostgreSQL database description of the MyModel table, I notice that the table does not have a restriction on the numeric column.
Column | Type | Modifiers
-------------+-----------------------------+-------------------------------------------------------
id | integer | not null default nextval('my_models_id_seq'::regclass)
multiplier | numeric |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
My db/schema.rb file also does not state the precision and scale:
ActiveRecord::Schema.define(:version => 20121206202800) do
...
create_table "my_models", :force => true do |t|
t.decimal "multiplier"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
...
So my first question is, why do I not see precision and scale pushed down to PostgreSQL when I migrate? Documentation states that it should be supported.
My second question is, why is 0.07 not correctly comparing using the MyModel.find_or_create_by_multiplier(multiplier: 0.07) command? (If I need to open another question for this, I will).
This is embarrassing...
I have precision misspelled.
Changing the migration to:
t.decimal :multiplier, precision: 8, scale: 2
fixed everything.
PostgreSQL 9.1 will let you declare a column in any of these ways.
column_name decimal
column_name numeric
column_name decimal(8, 2)
column_name numeric(8, 2)
If you look at that column using, say, pgAdminIII, it will show you exactly how it was created. If you (or Rails) created the column as numeric, it will say "numeric". If you (or Rails) created the column as decimal(8, 2), it will say "decimal(8, 2)".
So it looks to me like Rails is not passing precision and scale to PostgreSQL. Instead, it's simply telling PostgreSQL to create that column with type "numeric". Rails docs suggest it should not be doing that.
Example syntax in that link is different from yours.
td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
I was using :numeric at first. Although ActiveRecord changed it to :decimal for me, both :precision and :scale were ignored.
# 202001010000000_add_my_col_to_my_table.rb
add_column :my_table, :my_col :numeric, percision: 3, scale: 2, comment: 'Foobar'
# schema.rb
t.decimal "my_col", comment: 'Foobar'
Simply change to :decimal in migration file fixed it for me:
# 202001010000000_add_my_col_to_my_table.rb
add_column :my_table, :my_col :decimal, percision: 3, scale: 2, comment: 'Foobar'
# schema.rb
t.decimal "my_col", precision: 3, scale: 2, comment: 'Foobar'