I have belongs_to :provider in my model, and provider_id is set, but association is still blank:
irb(main):095:0> o2.provider_id
=> BSON::ObjectId('4e0472f36d40ec0004000001')
irb(main):096:0> o2.provider
=> nil
Also, model has provider_id= method with "write_attribute(:provider_id, provider_id)" inside.
What could be wrong here?
Mongoid version is 2.4.0
Thank you!
I believe you need a has_one or has_many association in your other model.
class Foo
include Mongoid::Document
belongs_to :bar
end
class Bar
include Mongoid::Document
has_one :foo
end
Related
I'm building a web API with Ruby and Grape. I have two classes that requires each other which leads to a situation where I get uninitialized constant class errors. The place where I get the error is in the Entity class for Connector, see the example code below, which requires Card::Entity before it has been inintialized. Is there any way to solve this probelm without moving the Entity definitions to another file?
#card.rb
require_relative 'connector'
require_relative 'caption'
class Card < ActiveRecord::Base
belongs_to :medium
belongs_to :storyline
has_many :connectors, autosave: true
has_many :connected_cards, class_name: "Connector", foreign_key: "connected_card_id"
has_many :captions
accepts_nested_attributes_for :connectors, :captions
class Entity < Grape::Entity
expose :id, documentation: { readonly: true }
expose :cardtype
expose :connectors, using: Connector::Entity
expose :captions, using: Caption::Entity
end
end
#connector.rb
require_relative 'card'
class Connector < ActiveRecord::Base
has_one :card
has_one :connected_card, :class_name => "Card", :foreign_key => "connected_card_id"
class Entity < Grape::Entity
expose :id, documentation: { readonly: true }
expose :title
expose :card, using: Card::Entity
expose :connected_card, using: Card::Entity
end
end
I don't know a lot about grape, but this could be solved by "pre declaring" the class:
#card.rb
require_relative 'caption'
class Connector < ActiveRecord::Base
# empty declaration just to make the import works
end
class Card < ActiveRecord::Base
belongs_to :medium
belongs_to :storyline
has_many :connectors, autosave: true
has_many :connected_cards, class_name: "Connector", foreign_key: "connected_card_id"
has_many :captions
accepts_nested_attributes_for :connectors, :captions
...
end
Still, I think that QPaysTaxes may have a valid point about design here.
I would like to override a Lib Model in my Models and add a relation.
What is the best way to do it ?
Example of a model in rpush lib:
https://github.com/rpush/rpush/blob/f82cc6a25861612ce118b2661f5a47bceb7ebd86/lib/rpush/client/active_record/app.rb
module Rpush
module Client
module ActiveRecord
class App < ::ActiveRecord::Base
self.table_name = 'rpush_apps'
if Rpush.attr_accessible_available?
attr_accessible :name, :environment, :certificate, :password, :connections, :auth_key, :client_id, :client_secret
end
has_many :notifications, class_name: 'Rpush::Client::ActiveRecord::Notification', dependent: :destroy
validates :name, presence: true, uniqueness: { scope: [:type, :environment] }
end
end
end
end
I would like to add a has_many relation without editing the gem
So I thought creating a models/app.rb with this would be a start:
class Rpush::Client::ActiveRecord::App
has_many :rel_group_apps
has_many :groups, :through => :rel_group_apps
end
I tried this but nothing changed. Maybe my models/app.rb is not called ?:
module Rpush
module Client
module ActiveRecord
module App
def self.included(includer)
includer.class_eval do
has_many :rel_group_apps
has_many :groups, :through => :rel_group_apps
end
end
end
end
end
end
How should I do it ? Is there a way to extend a lib model without removing the original behavior ?
Thanks !
EDIT
I Made it work but only by putting this code directly in config/initializers/rpush.rb
It wasn't working in models/app.rb
class Rpush::Client::ActiveRecord::App
has_many :rel_group_apps
has_many :groups, :through => :rel_group_apps
end
If someone has a nicer idea, I'll take it !
Extend the class with class << self
class Rpush::Client::ActiveRecord::App
class << self
[your methods here]
end
end
Foo, Bar and Baz are all Mongoid collection models. There are the only collections in the DB.
Is there a more efficient way to get all the data in the DB?
Foo.all + Bar.all + Baz.all
I don't know a way of querying several collections at the time, and I believe that if one try to do that will defeat the purpose of using a NONSQL DB like MongoDB.
However, there is one way of archiving this behaviour in MongoDB. Using embedded documents. For example:
class Everything
include Mongoid::Document
include Mongoid::Timestamps
embeds_many :foos, class_name: 'Foo', inverse_of: :everything
embeds_many :bars, class_name: 'Bar', inverse_of: :everything
embeds_many :bazs, class_name: 'Bazs', inverse_of: :everything
end
class Foo
include Mongoid::Document
field :foo, type: String
embedded_in :everything, class_name: 'Everything', inverse_of: :foos
end
class Bar
include Mongoid::Document
field :bar, type: String
embedded_in :everything, class_name: 'Everything', inverse_of: :bars
end
class Bazs
include Mongoid::Document
field :baz, type: String
embedded_in :everything, class_name: 'Everything', inverse_of: :bazs
end
Doing Everything.all will retrieve all documents in Everything along with all the embedded documents in one call.
How do I go about validating the presence of an item defined as belongs_to? In other words:
class Temp
include Mongoid::Document
include Mongoid::Timestamps
belongs_to :user
end
and I wish to make sure a user was input.
Thanks in advance!
From the fine manual:
The parent document of the relation should use the has_many macro to indicate is has n number of referenced children, where the document that is referenced uses belongs_to.
class Band
include Mongoid::Document
has_many :members
end
class Member
include Mongoid::Document
field :name, type: String
belongs_to :band
end
[...]
# The parent band document.
{ "_id" : ObjectId("4d3ed089fb60ab534684b7e9") }
# The child member document.
{
"_id" : ObjectId("4d3ed089fb60ab534684b7f1"),
"band_id" : ObjectId("4d3ed089fb60ab534684b7e9")
}
Take note of the band_id that represents the belongs_to :band relationship. So saying:
belongs_to :user
implicitly adds a field :user_id to your Temp. That means that you can simply:
validates_presence_of :user_id
to make sure that a :user_id has been given. If you want to ensure that the :user_id is valid then you could:
validates_presence_of :user
and the validation will make sure that temp.user (i.e. User.find(temp.user_id)) finds something.
In my code I have a user class:
class User
include Mongoid::Document
has_and_belongs_to_many :person_record_bookmarks, inverse_of: nil, :class_name => "PersonRecord"
end
now it will generate person_record_bookmarks_ids in my document. This name is too long, is there any way to store it as shorter name in the database? In embed documents we can use store_as:, but seems it doesn't work for references.
foreign_key is what you are looking for
class User
include Mongoid::Document
has_and_belongs_to_many :person_record_bookmarks, inverse_of: nil, :class_name => "PersonRecord", foreign_key :shorter_name
end
then your user will be:
{...shorter_name:[ObjectId("..."),ObjectId("...")]...}
You can user user.shorter_name to retrieve the list of ids or user.person_record_bookmarks to retrieve all PersonRecordBookmarks.where({_id: {$in: shorter_name})