I am using the Mongoid gem according to this https://docs.mongodb.com/mongoid/current/tutorials/getting-started-rails/
But now i want to make a usermodel with few attributes
How do i update these attributes in rails controller
puts"saving data"
Mongo::Logger.logger.level = :: Logger:: FATAL
client - Mongo::Client.new(['127.0.0.1:27017' ], :database => 'mydb')
doc ={:_id=>1,:token=> oauth_token, token_secret-> oauth_token_secret}
client[:UserTable].insert_one doc
client.close
puts"saved data"
The above code directly works with mongodb I want to do this same job via model
First you should create the class for mongoid
class User
include Mongoid::Document
store_in collection: 'UserTable'
field :token, type: String
field :token_auth, type: String
end
and later you can use in your controller sentences like:
user = User.find(params[:id])
user.update_attributes(update_params)
Related
I've been looking for some days without finding the exact answer to my problem which is as simple as that : I have a simple model, with books and authors. A book embeds many authors, and an author is embedded in book. But whenever I'm saving a new book, the author array is not persisted.
What I have is an angular 7 application, calling a ROR API. My Rails versions is 5.2.2. I am using mongoid 7.0 for persistence.
My API was generated with rails g scaffold, and with the --api and --skip-active-record flags.
I first had a problem with the mapping of my properties. My Angular APP sends JSON in lowerCamelCase, when Rails awaits form lower_snake_case vars. I managed to bypass this problem by adding a middleware (correct me if I'm wrong on this one) in my initializers which converts camelCase to snake_case.
# Transform JSON request param keys from JSON-conventional camelCase to
# Rails-conventional snake_case:
ActionDispatch::Request.parameter_parsers[:json] = -> (raw_post) {
# Modified from action_dispatch/http/parameters.rb
data = ActiveSupport::JSON.decode(raw_post)
data = {:_json => data} unless data.is_a?(Hash)
# Transform camelCase param keys to snake_case:
data.deep_transform_keys!(&:underscore)
}
From what I found looking for my problem, it could have been a problem with strong params, so I tried to get awat with this in my book_params
def book_params
#params.fetch(:book, {})
params.require(:book).permit(:title, :release_date, authors_attributes: [:name, :last_name, :birth_date])
end
These are my model :
class Person
include Mongoid::Document
field :last_name, type: String
field :first_name, type: String
field :birth_date, type: Date
end
class Author < Person
include Mongoid::Document
embedded_in :book
end
class Book
include Mongoid::Document
field :title, type: String
field :release_date, type: Date
embeds_many :authors
accepts_nested_attributes_for :authors
end
And this is POST in my book controller (generated with Rails)
# POST /books
def create
#book = Book.new(book_params)
if #book.save
render json: #book, status: :created, location: #book
else
render json: #book.errors, status: :unprocessable_entity
end
end
And here are exemple of a body sent, received and how it is processed by Rails :
Request sent by angular app
Request received and processed by Rails
We can see in the book object
"book"=>{"title"=>"azerty", "release_date"=>"2019-01-21T16:10:19.515Z"}}
That the authors have disappeared, though they were present in the request received by the server.
My question is then : what is the solution to this, or at least what am I missing ? Doesn't Mongoid automatically save children when using embedded documents and accepts_nested_attributes_for ? Should I manually save the children each time a parent is saved in my controller ?
Thanks in advance for helping me
You have to use nested attributes to save children records
Add following line in book model
accepts_nested_attributes_for :authors
And pass authors parameters in author_attributes, for exa:
{title: 'test', release_date: '', author_attributes: [{first_name: '', other_attributes of author}, {first_name: '', , other_attributes of author}]}
for more details please check Mongoid: Nested attributes
Pass perameters in this format
{"title"=>"test", "release_date"=>"2019-01-22", "book"=>{"title"=>"test", "release_date"=>"2019-01-22", "authors_attributes"=>[{"first_name"=>"test name", "last_name"=>"test", "birth_date"=>"2019-01-22T09:43:39.698Z"}]}}
Permit book params
def book_params
params.require(:book).premit(:first_name, :last_name, authors_attributes: %i[first_name last_name birth_date])
end
I'm trying to create some relations on Mongoid but when I try to save the inner object or add it to the user.personal_accounts collection I get the following error
NoMethodError: undefined method `bson_type' for #<Bank:0x71c01a8>
My Object in rails console is correct
#<PersonalAccount _id: 56e87f669c27691be0d3041b, number: "55", active: true, bank: #<Bank _id: 56d74cdb9c27692fb4bd4c6d, code: 123, name: "Bradesco", country: "USA">>
My mappings
class PersonalAccount
include Mongoid::Document
field :number, type: String
field :active, type: Boolean
field :bank, type: Bank
embedded_in :user
end
class User
include Mongoid::Document
field :first_name, type: String
field :last_name, type: String
embeds_many :personal_accounts
end
class Bank
include Mongoid::Document
field :code, type: Integer
field :name, type: String
field :country, type: String
end
The mapping that I was expecting is:
User
PersonalAccounts
Bank
Bank
As I have read that I need to copy the outer bank to each PersonalAccount.
I have already tried the following Link
Versions installed:
bson (4.0.2)
bson_ext (1.5.1)
mongoid (5.0.2)
mongo (2.2.4)
The root of your problem is right here:
field :bank, type: Bank
MongoDB doesn't know how to store a Bank so Mongoid will try to convert it to something that MongoDB will understand while Mongoid is preparing the data for the database, hence the NoMethodError.
Presumably you want Bank to exist as its own collection and then each PersonalAccount would refer to a Bank. That would be a standard belongs_to setup:
class PersonalAccount
#... but no `field :bank`
belongs_to :bank
end
That will add a field :bank_id, :type => BSON::ObjectId to PersonalAccount behind the scenes and hook up accessor (bank) and mutator (bank=) methods for you.
Normally you'd want the other half of the relation in Bank:
class Bank
#...
has_many :personal_accounts
end
but that won't work (as you found out) because PersonalAccount is embedded inside User so Bank can't get at it directly. Keep in mind that embeds_one is just a fancy of wrapping the Mongoid machinery around a Hash field in a document and embeds_many is just a fancy way of wrapping the Mongoid machinery around an array of hashes inside another document; embedded documents don't have an independent existence, they're just a part of their parent.
Simply trying to work out how to copy attributes from one Active Model to another without having to do it one by one.
I have two models one is RFM (ruby to filemaker) one is mongoid both mixin active model.
gem "ginjo-rfm"
the model
require 'rfm'
class StudentAdmin < Rfm::Base
config :layout => 'STUDENT_ADMIN_LAYOUT'
attr_accessor :name_first,:name_last
end
Mongoid model
class Student
include Mongoid::Document
field :first_name, type: String
field :last_name, type: String
end
Is there a quicky copy I can do? I found a sample between active record objects e.g.
student_admin = ... #load StudentAdmin
Student.new(student_admin.attributes.slice(Student.attribute_names))
but RFM doesn't provide a attributes method.
EDIT
Sorry what I am trying to achive is a better way than this
student_admins = #get student admins from external service
students = []
student_admins.each() do |sa|
students.push(Student.create!(first_name: sa.name_first, last_name: sa.name_last))
end
This example only shows 2 attributes, but in practice there is over 50 and was wondering if there is a way to do it without having to specify every attribute e.g. if the attribute names are the same on two objects copy them automatically.
Try this:
students = student_admins.map do |sa|
attrs = sa.methods.inject({}) do |hash, m|
next unless Student.column_names.include? m.to_s
hash[m] = sa.send m
end
Student.create(attrs)
end
Student would have to be a class that inherits from ActiveRecord::Base:
class Student < ActiveRecord::Base
...
end
My application model allows Patients to have CustomFields. All patients have the same customs fields. Customs fields are embedded in the Patient document. I should be able to add, update and remove custom fields and such actions are extended to all patients.
class Patient
include Mongoid::Document
embeds_many :custom_fields, as: :customizable_field
def self.add_custom_field_to_all_patients(custom_field)
Patient.all.add_to_set(:custom_fields, custom_field.as_document)
end
def self.update_custom_field_on_all_patients(custom_field)
Patient.all.each { |patient| patient.update_custom_field(custom_field) }
end
def update_custom_field(custom_field)
self.custom_fields.find(custom_field).update_attributes({ name: custom_field.name, show_on_table: custom_field.show_on_table } )
end
def self.destroy_custom_field_on_all_patients(custom_field)
Patient.all.each { |patient| patient.remove_custom_field(custom_field) }
end
def remove_custom_field(custom_field)
self.custom_fields.find(custom_field).destroy
end
end
class CustomField
include Mongoid::Document
field :name, type: String
field :model, type: Symbol
field :value, type: String
field :show_on_table, type: Boolean, default: false
embedded_in :customizable_field, polymorphic: true
end
All pacients have the same customs fields embedded in. Adding a custom field works very well. My doubt is about updating and destroying.
This works, but it is slow. It makes a query for each pacient. Ideally I would just be able to say to MongoDB 'update the document with id: that is embedded in the array *custom_fields* for all documents in the Patient collection'. Idem for destroy.
How can I do this in Mongoid?
I am using Mongoid 3.1.0 & Rails 3.2.12
I don't think there is a way you can do that with a good efficiency with embedded documents.
Maybe you should consider having a referenced relationship between your models, so that you can use the delete_all and update_all methods on the collection.
I have a requirement to convert an ActiveRecord model class into a MongoDB Document class automatically. I am able to do so using a rails generator which will read the attributes of a model and generate the new document.rb.
If a ActiveRecord model class looks like below:
class Project < ActiveRecord::Base
attr_accessible :completed, :end_date, :name, :start_date
end
Then, a generated class confirming to Mongoid's structure will be as below:
class ProjectDocument
field :name, type: String
field :start_date, type: Date
field :end_date, type: Date
field :completed, type: Boolean
field :created_at, type: Time
field :updated_at, type: Time
end
But I don't want to store a different document files, one for each model. I want to be able to generate this document class on the fly, whenever the rails application is started.
Is this possible? Is this approach of generating and using classes from memory advised? I don't have constraints on changes to AR model structure; the document is flexible w.r.t data structure and changed columns will get added automatically.
My first attempt would look something like this:
klass = Project
new_class = Object.const_set(klass.name + "Document", Class.new)
klass.columns.each do |c|
new_class.class_eval do
field c.name.to_sym, type: c.type
end
end
You'll almost certainly have to do something more complicated to set the field type correctly, but this should give you a good starting point.