I'm trying to create a basic Rails CRUD app against a CouchDB database hosted on Cloudant.
I'm using couch_potato as my persistence layer and have it connecting properly to my Cloudant database.
The issues I'm having is my first model won't see the existing documents in my CouchDB database, unless I add a ruby_class field that equals the name of my model.
My simple User model:
class User
include CouchPotato::Persistence
property :id, :type => Fixnum
property :FullName, :type => String
view :all, :key => :FullName
end
Sample CouchDB document:
{
"_id": 123456,
"_rev": "4-b96f36763934ce7c469abbc6fa05aaf3",
"ORGID": 400638,
"MyOrgToken": "19fc342d50f9d8df1ecd5e5404f5e5f7",
"FullName": "Jane Doe",
"Phone": "555-555-5555",
"MemberNumber": 123456,
"Email": "jane#example.com",
"LoginPWHash": "14a3ccc0e6a50135ef391608e786f4e8"
}
Now, when I use my all view from the rails console, I don't get any results back:
1.9.2-p290 :002 > CouchPotato.database.view User.all
=> []
If I add the field and value "ruby_class: User" to the above CouchDB document, then I get results back in the console:
1.9.2-p290 :003 > CouchPotato.database.view User.all
=> [#<User _id: "123456", _rev: "4-b96f36763934ce7c469abbc6fa05aaf3", created_at: nil,
updated_at: nil, id: "123456", FullName: "Jane Doe">]
I'm working with a large set of customer data, and I don't want to write any scripts to add the ruby_class field to every document (and I may not be permitted to).
How can I get my app to recognize these existing CouchDB documents without adding the ruby_class field?
I couldn't find much documentation for couch_potato and couchrest that shows how to work with existing CouchDB databases. Most of the examples assume you're starting your project and database(s) from scratch.
Thanks,
/floatnspace
when you are looking at the all view of your User you will see something like ruby_class == 'User' so unless you add this property to your documents you will need to work around what couch_potato provides. you could i.e. use couch_rest directly to retrieve your documents, but i don't think that this what you want.
if you start persisting or updating your own documents, couch_potato will add the ruby_class field anyways. so i think the simples solution would be to just add them there.
another thing you can do is create a view that emits the documents also when they DON'T have the property set. this approach will only work if you have just one kind of document in your couchdb:
if(!doc.ruby_class || doc.ruby_class == 'User') {
emit(doc);
}
Related
I'm trying to save file to a Google Storage bucket, I followed the official guide for rails.
So I've this code for updating my file
after_create :upload_document, if: :path
def upload_document
file = Document.storage_bucket.create_file \
path.tempfile,
"cover_images/#{id}/#{path.original_filename}",
content_type: path.content_type,
acl: "public"
# Update the url to my path field on my database
update_columns(path: file.public_url)
end
I can store my file on my bucket, I can retrieve the public_url and update the path field on my table but when I try to fetch the path string I have a nil. Exemple on my rails console
Document.find(14)
=> #<Document id: 14, name: "Test", path: "https://storage.googleapis.com/xxxxxxxx-xxxx.x...", created_at: "2018-10-05 07:17:59", updated_at: "2018-10-05 07:17:59">
Document.find(14).path
=> nil
Document.find(14).name
=> "Test"
So I don't understand why I can access to my path field on my SQL database after an update using the update_columns of Rails.
Thanks a lot for your help
You have some method defined on Document class (or included module) that is overriding the default attribute accessor.
To find out which, write this in console:
Document.find(14).method(:path).source_location
In any case you can access directly the attribute with
Document.find(14)['path']
I am referencing the following url http://api.mongodb.org/ruby/current/ which to me is of no help in my quesiton. I wanted to know if I used the following code
coll.update({ :count => 5 }, { :count => "foobar" }, { :upsert => true })
is is possible to get the upserted document without making another database call? Links to better documentation would be greatly appreciated.
The Ruby MongoDB Driver requires a separate database call to retrieve data. Although it can perform an upsert there is no way to get the upserted document with a single database call. So you have to do something like this
coll.find({ :count => "foobar" })
I am developing a Ruby on Rails (3.2.6) application and is using MongoId (3.0.0) to interact with the MongoDB database. I am just wondering how do save embeded JSON objects that contains multiple levels and not just one level.
I got an old MongoDB database with this and simular structure so I need to save new documents using the same structure.
This is from the documentation and is used to add a one level document:
Person.create(
first_name: "Heinrich",
last_name: "Heine"
)
How can I add an object with this structure:
{
"basic": {
"file_id": {
"file": "cf1952761a806c56c9bee60665418f02c"
},
"share": false,
"status": "created"
},
"data": {
"id": "4fd942dder5f5e88837300026e",
"name": "roberta",
"comment": "This is a comment"
}
}
The easiest way to do this is to create classes for basic and data and embed them in your top level document.
Embedded document classes are defined in Mongoid the same way as other documents with an embedded_in call and a matching embeds_one or embeds_many in the top level document.
The other option is to simply define a Hash field, but this obviously may have any structure.
Class Person
include Mongoid::Document
field :data, :type => Hash
...
end
:data will accept any hash, even with nested hashes.
Mostly my entries in seeds.rb are simple, like this:
User.create!(
name: "Peter"
admin: false;
# etc.
)
If I get the "Can't mass-assign protected attributes" error, I make a small change in the model, in this case user.rb:
attr_accessible: name, admin
So far so good. But how am I supposed to seed entries into tables generated by a rails gem which adds another engine to my app? Forem, for example. And I'm sure there are others.
I have added these entries to my seeds.rb file:
Forem::Category.create!(
name: "cat1"
)
Forem::Forum.create!(
title: "forum1",
description: "forum1 description",
category_id: 1
)
Forem::Topic.create!(
forum_id: 1,
user_id: 1,
subject: 'topic1',
locked: false,
pinned: false,
hidden: false,
)
Category and Forum are generated, Topic is not:
Can't mass-assign protected attributes: forum_id, user_id, locked, pinned, hidden
If I had a topic.rb model, I would know what to do. But I don't have it. Forem is an engine and I don't know of a way to make some attributes of model topic.rb visible.
I know that this line in application.rb:
config.active_record.whitelist_attributes = true
enables the protection against mass assignment. Disabling it leaves a huge security hole, so it's not an option. And disabling it didn't allow me to seed into topics table anyway.
I've also tried to use fixtures. I added this to my seeds.rb file:
require 'active_record/fixtures'
Fixtures.create_fixtures("#{Rails.root}/test/fixtures", "topics.yml")
test/topics.yml:
one:
id: 1
forum_id: 1
user_id: 1
subject: "topic1"
created_at: 2012-05-19 19:54:19
updated_at: 2012-05-19 19:54:20
locked: false
pinned: false
hidden: false
last_post_at: 2012-05-19 19:54:21
state: "open"
views_count: 3
Error I get is - uninitialized constant Fixtures
What's wrong with my seeds.rb and fixture? Or should I use a migration?
Disabling it leaves a huge security hole, so it's not an option`
Nope, it's not a huge security hole. This is a controversial debate, but attr_accessible (and variants) are (in my and a lot of others opinion) not a good solution to the problem that is preventing users to create/update objects/attributes they should not. Put another way, attr_accessible is a model solution to a controller issue. Because that is the job of the controller to make sure that the data is cleaned and usable, to check wether the current user is allowed to do such things, etc.
So what I'd do would be to remove all references to attr_accessible and set whitelist_attributes to false.
Then it's up to you to filter your params in your controllers. You could do as done in this gist or use rails/strong_parameters, or any other way that might please you.
After that you would no longer have these issues while seeding
Seeds.rb is just ruby code. You don't have to create the whole resource in one line. Try something like this
topic = Forem::Topic.create(
:subject => "topic 1",
:locked => false
# etc
)
topic.user_id = 1
topic.save
I have 1000 users that i will be retrieving from Twitter, and I would like to save them at one shot, as opposed to doing 1000 insertions individually.
How can I do this on Mongoid? Something like this would rock:
TwitterUser.createMany([{:name=>u1}, {:name=>u2},{:name=>u3}] )
You should use the Mongo ruby driver to do this. You can pass an array of hashes to the insert method to create multiple documents at once (more info on this google groups discussion). Mongoid makes it easy to access the ruby driver.
The code would look something like this:
user_list = twitter_accounts.map do |account|
# create a hash of all the fields to be stored in each document
{ 'name' => account.name,
'username' => account.username
# some other fields...
}
end
Mongoid.master['twitter_users'].insert(user_list)
You almost got it, it's create, not createMany. You can use it like this:
TwitterUser.create([
{ username: "u1", display_name: "Display Name 1" },
{ username: "u2", display_name: "Display Name 2" },
{ username: "u3", display_name: "Display Name 3" }
])
Also, as #bowsersenior points out, it's a good idea to use it with Array#Map:
TwitterUser.create(
#users_array.map do |u|
{ username: u.username, display_name: u.name }
end
)
From the Mongoid#Persistence Docs:
Model.create
Insert a document or multiple documents into the database
Model.create!
Insert a document or multiple documents into the database, raising an error if a validation error occurs.
Just use MongoidModel.create directly.