I'd like to keep all authentication specific code in the file that defines the Auth "model" like this:
class User
include Mongoid::Document
embeds_one :auth
field :username, type: String
end
class Auth
include Mongoid::Document
embedded_in :user, inverse_of: :auth
field :password
def self.login(user, pass)
User.first(conditions: { username: user, password: pass })
end
end
The problem? It's not possible to call class methods of embedded documents:
> Auth.login('user', 'pass')
Mongoid::Errors::InvalidCollection: Access to the collection for Auth is not allowed since it is an embedded document, please access a collection from the root document.
> User.auth.login('user', 'pass')
NoMethodError: undefined method `auth' for User:Class
Singleton methods in embedded Mongoid::Document models is not a good idea?
You can't access embedded documents directly like you tried first time Auth.loggin('user','pass'). You should be having only instance methods in embedded document models like this
def self.login(user, pass)
User.first(conditions: { username: user, password: pass })
end
and can access it by user object like this
#user.auth.login('user','pass')
Related
I am trying to store messages and I want to store to and from User reference as below:
class Message
include Mongoid::Document
include Mongoid::Timestamps
field :from, type: Moped::BSON::ObjectId
field :to, type: Moped::BSON::ObjectId
end
class User
include Mongoid::Document
field :username, type: String
end
Is the above the correct way of doing so? I can imagine one way is to create User as a custom type, but that seems a lengthy direction to take. Ideally I want to be able to reference the User directly as so: message.from.username or message.from['username'] and be able to validate the presence of the from and to fields.
Any help would be much appreciated.
class Message
belongs_to :from, class_name: 'User', inverse_of: nil
belongs_to :to, class_name: 'User', inverse_of: nil
...
Message.where(from: my_user)
I'm still getting my head around MongoDB and Mongoid in particlar.
Let's say I have a User and each User has one Thingamajig. When I create the User
I want the system to autmatically also create a blank Thingamajig for that User.
Each Thingamajig has a whatsit field that must be unique if it has a value, but is allowed to have no value when created.
So I define the following classes.
class Thingamajig
include Mongoid::Document
field :whatsit, type: String
index({whatsit: 1}, {unique: true, name: 'whatsit_index'})
end
class User
include Mongoid::Document
field :name, type: String
index({name: 1}, {unique: true, name: 'user_name_index'})
embeds_one :thingamajig, dependent: :nullify, autobuild: true
end
However what I find when I
User.create!(name: 'some name')
is that User.find(name: 'some name').thingamajig is nil.
Questions:
How can I ensure that each User gets an associated Thingamajig? and
How do I specify that the name field of a User is required?
FYI I am using Sintara not Rails (if that matters to anyone).
1 - The autobuild: true option normally should have done the trick. I think the problem is that you forgot to add the other side of the relation to the Thingamajig model:
class Thingamajig
include Mongoid::Document
embedded_in :user
...
end
2 - To specify required fields, use validations:
class User
include Mongoid::Document
field :name, type: String
validates_presence_of :name
...
end
Mongoid uses ActiveModel validations.
I want to impliment something which is similar to Twitter Repost System, therefore I will use this as an example. So let's say I have a Tweet Model and I want to allow other user to repost a certian tweet of another user, how do I impliment something like this?
I thought I would be a cool idea to put the retweet class into the tweet to be able to acess the repost too when I use Tweet.all to recive all tweets stored in the database, but somehow I didn't worked as expected...
The following Code is just an example which should show how to impliment this even if it is not working...
Any ideas how I could build a working repost model which also allows me to access both tweets and retweet by using Tweet.all?
class Tweet
class Retweet
include DataMapper::Resource
belongs_to :user, key => true
belongs_to :tweet, key => true
end
include DataMapper::Resource
property :text, String
property :timestamp, String
belongs_to :user
end
Important: I should be carrierwave compatible.
class Tweet
include DataMapper::Resource
property :id, Serial
has n, :retweets, 'Tweet', :child_key => :parent_id
belongs_to :parent, 'Tweet', :required => false
belongs_to :user
def is_retweet?
self.parent_id ? true : false
end
end
original = Tweet.create :user => user1
retweet = Tweet.create :parent => original, :user => user2
retweet.is_retweet? # => true
Post is accessible via
Blog.first.posts
How do I do this with a module name space? Such as Engine::Post
Blog.first.???
Thanks
Try explicitly giving Mongoid the class name
class Engine::Blog
include Mongoid::Document
embeds_many :posts, :class_name => "Engine::Post"
end
I want to implement before_validaton callback in a separate class so that it can be reused by multiple model classes.
Here in callback i want to strip field passed as parameter but i am not sure how to pass parameter to callback class. Also i want to pass this as reference rather than by value(not sure if this concept is in Ruby Rails). I am following the link http://guides.rubyonrails.org/active_record_validations_callbacks.html#callback-classes
Here is code which is not completely correct, please help for same
class StripFieldsCallback
def self.before_validation(field)
field = field.strip
end
end
class User < ActiveRecord::Base
validates_uniqueness_of :name, :case_sensitive => false
validates_length_of :name, :maximum => 50
before__validation StripFieldsCallback(name)
end
If i define method in model in itself rather than defining in separate callback class code is like this (which works fine)
class User < ActiveRecord::Base
validates_uniqueness_of :name, :case_sensitive => false
validates_length_of :name, :maximum => 50
before__validation :strip_blanks
protected
def strip_blanks
self.name = self.name.strip
end
end
Of course it is not good to replicate methods in all of models so i want to define method in callback classes.
You may do this or use normalize_attributes gem
module StripFieldsCallback
def before_validation_z(field)
write_attribute(field, read_attribute(field).strip) if read_attribute(field)
end
end
class User < ActiveRecord::Base
include StripFieldsCallback
before_validation lambda{|data| data.before_validation_z(:name)}
end