We have recently upgraded our application to Rails3 and we are now using Mongoid, and we have a problem retrieving previous documents from mongo-db by _id.
Upon closer investigation, an old record (which I can't retrieve by _id) look as follows:
#<Audit::Log _id: 4d892bfe6bcaff4ffd000001,
failed: nil, request_id: "68ccb38e9e345bb7fc55331389a902a1",
session_id: "54940ff7e8c7336d813a872db7cb7bc0",
_id: "4d892bfe6bcaff4ffd000001", ... }>
and a good record has the following structure:
#<Audit::Log _id: 4d892bfe6bcaff4ffd000001,
failed: nil, request_id: "68ccb38e9e345bb7fc55331389a902a1",
session_id: "54940ff7e8c7336d813a872db7cb7bc0",
_id: BSON::ObjectId('4d892bfe6bcaff4ffd000001'), ... }>
As you can see, the _id field is different. For the old records it seems to be just a string, and for the new records it is a BSON::ObjectID.
I can't seem to be able to retrieve the records with the old format. Trying to find the records using
Audit::Log.where(:_id => BSON::ObjectId('4d892bfe6bcaff4ffd000001')).first
Audit::Log.where(:_id => '4d892bfe6bcaff4ffd000001').first
both return nil.
But for the good record, I can just do
Audit::Log.where(:'_id' => '4e14152d6bcaff26bb000039').first
I am guessing, but maybe Mongoid automatically converts the string to an ObjectId to find on _id? The only fix I see would be to convert
all the _id-fields to BSON::ObjectId if they are not already. But how do I do that?
Or do you have a better approach?
All of these will work, provided the record actually exists:
Account.where(:_id => "4e0a9c6142f5bc769f000008").first
Account.find(BSON::ObjectId("4e0a9c6142f5bc769f000008"))
Account.find("4e0a9c6142f5bc769f000008")
I'm interested in the JSON returned about a Audit::Log... Why are there two _id fields returned?
#<Audit::Log _id: 4d892bfe6bcaff4ffd000001,
failed: nil, request_id: "68ccb38e9e345bb7fc55331389a902a1",
session_id: "54940ff7e8c7336d813a872db7cb7bc0",
_id: "4d892bfe6bcaff4ffd000001", ... }>
You may want to drop to the mongo driver and see if this log truly exists in the database. Unless you are declaring another "_id" field in the audit_log.rb, I believe this record does not exist.
Ha, I should have looked further at the Mongoid documentation. They have a section describing how to upgrade. In the section to upgrade to 2.0.0.BETA.11 + they describe that the _id's now no longer are String and they point to this gist to convert all your ids from string to ObjectId.
Ex: Here is an id
1.9.3-p125 :096 > profile_id
=> “4fe969dd79216d0af9000002″
1.9.3-p125 :099 > BSON::ObjectId.from_string(profile_id)
=> BSON::ObjectId(’4fe969dd79216d0af9000002′)
Related
I am experiencing a head-scratcher in a non-Rails app using AR that I cannot figure out. I will simplify greatly, but here is the essence: I have a Download object that belongs to a Ledger. In one of my unit tests, I am experiencing this:
dl = create(:download, account: checking)
dl.ledger
=> <Byr::Ledger:0x00007fd176ce4740
id: 2,
name: "test_ledger_1",
org_name: "Test Ledger, Inc.",
street1: nil,
street2: nil,
city: nil,
state: nil,
zip: nil,
created_at: 2022-04-03 13:13:53.734003153 UTC,
updated_at: 2022-04-03 13:13:53.792451592 UTC,
default_account_id: 21,
short_name: "Test_ledger_1",
parent_percent: nil,
parent_id: nil,
accessed_at: 2022-04-03 13:13:53.791911547 UTC,
start_date: Mon, 01 Jan 2018,
cost_method: "fifo",
end_date: nil
> dl.ledger.peristed? => true
> Ledger.find(2) => nil with eval error: Couldn't find Byr::Ledger with 'id'=2
I use factory_bot to create the Download, dl, which in turn builds a ledger for it to go with, which purports to be persisted with id=2. But when I try to find the ledger with Ledger.find(2), it's not in the postgresql db.
Anybody have any idea what might be going on here?
I think you should use something like faker + factory_bot and mock resources to get access to params you need.
Here an example of use. Hope this helps
I finally got this to pass by explicitly passing the ledger into the Account factory on which the Download factory was created, like this:
let(:ldg) { create(:ledger, name: 'Willy') }
let(:checking) { create(:bank_account, ledger: ldg) }
let(:dl) { create(:download, account: checking) }
Suddenly, the disappearing ledgers abated. I believe the cuplrit may have been DatabaseCleaner wiping away the automatically-generated ledger from one example to the next. Using an explicit ledger just for the example in question kept it from being deleted underneath my feet.
Thanks, #Joe, for giving this some thought.
I'm studying DynamoDB using rails and I got a doubt.
I not be able to find a solution on web, so If you can solve it I'll thank.
The doubt is how can I find values into array saved on a table, for example:
I have a lot of data in my_table where there are fields called "numbers" that are arrays like:
[1,2,3,4]
[3,4,5,6]
[1,3,4,7]
[4,7,8,10]
[8,9,12,14]
[12,14,16,20]
So, I want select all entries that contains numbers 1,3,4. In this case four results.
So, my code is
result = dynamodb.scan({
table_name: "my_table",
select: "ALL_ATTRIBUTES",
attributes_to_get: ["numbers"],
scan_filter: {
"numbers" => {
attribute_value_list: [1,3,4],
comparison_operator: "CONTAINS"
}
}
})
But I get this error: One or more parameter values were invalid: Invalid number of argument(s) for the CONTAINS ComparisonOperator
How can I do this action using dynamo DB?
Thanks a lot
Try this and let me know if it works, I know from experience that DynamoDB is very painful to filter.
result = dynamodb.scan(
table_name: 'my_table',
expression_attribute_values: {
':one' => 1,
':two' => 2,
':three' => 3,
':four' => 4
},
filter_expression: 'contains(numbers, :one) OR contains(numbers, :two) OR contains(numbers, :three) OR contains(numbers, :four)'
)
I can't think of anything simpler currently, the method you linked is marked as deprecated, instead you should use expression_attribute_values and filter_expression.
I'm trying to read this array on RoR:
> importer_name = [#<RouteImporter id: 1, name: "aa", filename: "aa1", type: "RouteImporter">]
I just want to get the filename character "aa1", I tried with importer_name[2] but I didn't get nothing and I don't want 'filename: "aa1"' I just want "aa1", any idea? Thanks in advance!
you have a Ruby object stored in an array. You can access it like this(If I understand you correctly):
importer_name.first.filename
In my Rails app I have a model called Cycle with a "start" attribute that is a date. I'm running into a very strange problem where sometimes Cycle.find_by_start will return the expected record, but at other times it will return nil.
For example Cycle.find_by_start("2011-05-01") returns the following:
=> #<Cycle id: 45, created_at: "2011-05-15 22:38:35",
updated_at: "2011-05-15 22:38:35", user_id: 20,
start: "2011-05-01", ending: nil, startguess: false, endingguess: nil>
But running Cycle.find_by_start("2011-05-13") returns nil, even though there is a record with a matching start value. I've verified that the record exists and the start value matches by running the following at the Rails console.
irb(main):012:0> Cycle.find(47)
=> #<Cycle id: 47, created_at: "2011-05-23 01:28:59",
updated_at: "2011-06-21 00:38:34", user_id: 12,
start: "2011-05-13", ending: "2011-05-31", startguess: false, endingguess: false>
irb(main):011:0> Cycle.find(47).start == "2011-05-13".to_date
=> true
Possibly relevant info: Running Rails 3.0.7 in development mode with an SQLite database.
Any ideas or troubleshooting tips?
Edit 1
Log of the SQL queries used:
[94m19:10:11 active_record [37mCycle Load (1.0ms) SELECT "cycles".* FROM "cycles" WHERE "cycles"."start" = '2011-05-01' LIMIT 1
[94m19:10:19 active_record [37mCycle Load (0.0ms) SELECT "cycles".* FROM "cycles" WHERE "cycles"."start" = '2011-05-13' LIMIT 1
Dates.... you may have a parsing problem, with US/UK formats getting swapped around and confusing things. I often find it helps to make the date unambiguous (assuming English months):
Cycle.find_by_start("13 May 2011")
If :start is a date field, then it's best to pass find_by_start an actual Date object rather than a string. So:
Cycle.find_by_start(Date.parse("2011-05-13"))
(I'm using Date.parse to create the date object here, but you could also use Date.new or Date.today or some other method)
Passing a string to the finder method might work but, as you've discovered, might also not - depending on the database type and how the database interprets the string.
I am using Ruby on Rails 3 and I would like to solve a issue counting ActiveRecord instances in an array.
I have this code
data = Account.where({:name => "Test_name", :city => "Test_city"}).limit(10)
The data debug is
#<Account:0x000001029d2da0>#<Account:0x000001029d2c60>#<Account:0x000001029d2bc0>#<Account:0x000001029d2b20>
The data inspecting is
"[#<Account name: \"Test_name\", city: \"Test_city\">, #<Account … >, #<Account id… >, …]"
Doubt: The ##<...> should be something like #<Account...>,#<Account...>,<...> (note commas)?
If in my code I use the following
data_count = data.count
The data_count is
nil
Why is it nil? How should I count accounts?
If I use result = data.class the debug of result is nil, but if I use result = data.classthe debug is "{\"inheritable_attributes\":{}}".
If I use Account.find_by_name("Test_name") instead of Account.where(...) I get same results as above.
To get to the bottom of things, start the rails console with:
$ rails c
Given that Account is an ActiveRecord model, you should be able to do the following in the rails console:
> Account.all.count
=> 100
> Account.where(:status=>'active')
=> [ #<Account id: 1, name: "a1", ...>, #<Account id: 2, name: "a2", ...>, #<Account id: 3, name: "a3", ...>, ...]
I'm doing a lot of hand waving here with ... since I don't know your schema. Replace the where condition with whatever works for your situation. The returned value should look like an array with a list of all the rows in the database that match the condition. BTW, an array is a list of element, and inspect (as well as the default display in the console) show element separated by commas. I haven't used debug so I can't comment on what it should do.
You can verify that the returned value is an AREL, and should be able to do some other operations to verify things work as expected.
> Account.where(:status=>'active').class
=> ActiveRecord::Relation
> Account.where(:status=>'active').size
=> 99
> Account.where(:status=>'active').count
=> 99
> Account.where(:status=>'active').limit(10).count
=> 10
If these work as expected in the console, there may be something in the view that is obscuring the correct behavior. In that case you'll need to post the details of your view code. If the strange behavior still occurs in the console, I would suggest posting the minimal parts of the actual model code that still exhibit the problem, along with the migration so we can see the schema.
I think you are having some problem in where condition.
Can you show the attributes value used in where clause.
For me its working fine:
data = Account.where('id != 0').limit(10)
data_count = data.count
Use the following:
data = Account.where("id = 2 and email = 'test_email#test.com'")