Mongoid and has_secure_password - authentication

I am trying to use rails 3.1 authentication using mongoid instead of active model
class User
include Mongoid::Document
include ActiveModel::SecurePassword
has_secure_password
validates_presence_of :password, :on => :create
attr_accessor :email, :password, :password_confirmation
field :email, :type => String
field :password_digest, :type => String
end
the problem is password_digest is not recognized by the bycrypt as in active model example http://railscasts.com/episodes/270-authentication-in-rails-3-1
Thanks

For anyone who is interested, the most minimal requirement for using has_secure_password with Mongoid is simply the inclusion of ActiveModel::SecurePassword in the model.
class User
include Mongoid::Document
include ActiveModel::SecurePassword
field :username
field :password_digest
has_secure_password
end
Article

Put
has_secure_password
After
field :password_digest, :type => String

Related

How to check emptiness on devise custom fields?

I've added two news fields to my users table :first_name and :last_name
In migration file I've specified these fields couldn't be null using the following code:
class Userscustomfields < ActiveRecord::Migration
def change
add_column :users, :first_name, :string, {:null => false, :limit => "128"}
add_column :users, :last_name, :string, {:null => false, :limit => "128"}
end
end
I've checked on my database and the table was configurated correctly. But when I'm going to do a new register, my rails app allows to me to add a new user with first and last names empty. The app saves the fields with "", which didn't worked as I expected.
How can I do prevent this, by making a check of emptiness on my field before save them on my database?
I put on model user.rb
validates :first_name, :last_name, presence: true

Rails nil value when saving to database

I am trying to implement a user authentication system inside rails, this is my model:
class User < ActiveRecord::Base
attr_accessible :id, :email, :name, :password, :created_at, :updated_at
has_secure_password
before_save { email.downcase! }
validates :email, presence: true, :uniqueness => { :case_senstive => false }
validates :name, presence: true
validates :password, presence: true, length: { minimum: 6 }
end
Running in the console i can read the User table successfully, then when i try to create a record:
User.new(:name => "A", :email => "a#a.a", :password => "password")
running valid on it retrurns true, but when saving the record, i get error:
users.password may not be NULL
Extracting the password out of the hash works fine.
What is the problem?
Thanks
Where are you setting :password_confirmation? The example in the docs suggests you need it.
http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html
Main problem is in has_secure_password. If you are using that you should have string field :password_digest (it's where your encrypted password will be saved). And you need delete field :password and your validator of presence for that too. After add gem 'bcrypt-ruby', '~> 3.0.0' .
And now that should work
user = User.new(:name => "A", :email => "a#a.a",
:password => "password", :password_confirmation => "password")
But better use great gem https://github.com/plataformatec/devise . It has everything you need.
NEW ADDED
you should have attr_accessible for :password_confirmation too and that field should be used in your form.
more info about has_secure_password

Rails 3: validates :presence => true vs validates_presence_of

What is the difference between validates :presence and validates_presence_of? Looking through ActiveModel it looks like they setup the validation the same way. However, given the following model definition:
class Account < ActiveRecord::Base
has_one :owner_permission, :class_name => 'AccountPermission', :conditions => { :owner => true, :admin => true }
has_one :owner, :class_name => 'User', :through => :owner_permission, :source => :user
validate :owner, :presence => true
validates_associated :owner
end
Calling save on an instance of Account does not validate the presence of owner. Though, if I use validates_presence_of it will.
All those validates_whatever_of :attr macros do is call validates :attr, :whatever => true.
The problem is you are using validate and not validates.
In Rails 3.x and 4.x - it is now encouraged to use the following syntax:
validates :email, presence: true
validates :password, presence: true
Instead of the 2.x way:
validates_presence_of :email
validates_presence_of :password
In fact validates and validates_presence_of is not entirely equal !
validates_presence_of is allowing you to also lazily check by example of the value in the field is included in another table.
Like that:
validates_presence_of :pay_type, :inclusion => PaymentType.names
Which is something you can't do as easily with something like that
validates :pay_type, presence, :inclusion => PaymentType.names
Cause the inclusion is only evaluated the first time (not in a lazy way)
I would have thought that it is appropriate to use validates :foo presence: true when you want to include other validations of :foo such as length or uniqueness. But if you know the only validation you'll need for an attribute is presence, then validates_presence_of appears to be more efficient.
So:
validates :foo, length: {maximum: 50}, uniqueness: true,
format: {with: /bar/},
presence: true # lots of validations needed
But:
validates_presence_of :foo # only presence validation needed

Embedded Document not being added

Having trouble adding an embedded document. I am trying to add a tag which is embedded in the user.
user.rb
class User
include Mongoid::Document
field :name
validates_presence_of :name
validates_uniqueness_of :name, :email, :case_sensitive => false
attr_accessible :name, :email, :password, :password_confirmation
embeds_many :tags
embeds_many :tasks
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
tag.rb
class Tag
include Mongoid::Document
field :name
embedded_in :user, :inverse_of => :tags
references_many :tasks
end
tags_controller.rb
def create
##user = User.find(:first, :conditions => {:_id => "4d3ae09bf5c4930b2b000004"} )
#user = current_user
#tag = Tag.new(params[:tag])
#user.tags << #tag
#tag.save
redirect_to #tag, :notice => "Tag created!"
end
This is the output to the server when I try to create a new tag.
Started POST "/tags" for 127.0.0.1 at 2011-02-18 13:46:03 -0500
Processing by TagsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"6p+Jova7Hol2v5LRReSp2fhNJ967EwkeIzAWyrChQRE=", "tag"=>{"name"=>"general"}, "commit"=>"Create Tag"}
db['users'].find({:_id=>BSON::ObjectId('4d39cd63f5c4930708000001')}, {}).limit(-1) MONGODB
db['users'].update({"_id"=>BSON::ObjectId('4d39cd63f5c4930708000001')}, {"$push"=>{"tags"=>{"name"=>"general", "_id"=>BSON::ObjectId('4d5ebe6bf5c493554d000002')}}}) Redirected to
http://localhost:3000/tags/4d5ebe6bf5c493554d000002 Completed 302 Found in 5ms
Not really sure what the issue is or where to start. It actually looks like the user is found then an update is being made to tags but it is not successful.
Thanks
The Tags class in your model is embedded inside of user (via the embeds_many association), rather than a table on its own. So following the updates in your controller, you should have something like this:
> db.users.find()
{
_id: ObjectId('4d39cd63f5c4930708000001'),
tags: [
{
_id: ObjectId('4d5ebe6bf5c493554d000002'),
name: "General"
}
]
}
Using MongoID, you can also have Tags appear in their own collection by replacing "embeds_many" with "references_many".
In the comments above, you'll see that the issue berek-bryan was having had to do with where the tag was being added. He expected the tag to be added in its own collection, hence the question. Actually, the tags were being added right into his users collection.

Trying to view a referenced document: illegal ObjectId format

Trying to view an attribute to a referenced document. The issue is in the task's index file. When I try to display the tag associated with the task I get the following error:
BSON::InvalidObjectId in Tasks#index
The error is on '<%= task.tag.title %>' line in the index.html.erb file.
user.rb
class User
include Mongoid::Document
field :name
validates_presence_of :name
validates_uniqueness_of :name, :email, :case_sensitive => false
attr_accessible :name, :email, :password, :password_confirmation
embeds_many :tags
embeds_many :tasks
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
tag.rb
class Tag
include Mongoid::Document
field :title
embedded_in :user, :inverse_of => :tags
references_many :tasks
end
task.rb
class Tag
include Mongoid::Document
field :title
embedded_in :user, :inverse_of => :tags
references_many :tasks
end
index.html.erb
<% #tasks.each do |task| %>
<tr>
<td><%= task.name %></td>
<td><%= task.tag.title %></td>
</tr>
<% end %>
Thanks,
I ran into a similar problem myself recently (2.0.0.rc.7). In my case a Rails collection_select was ending up writing an empty string value into a reference field (e.g. tag_id). When mongoid attempted to reload the document and my code referenced the association it failed to convert empty string to a valid BSON object ID.
It looks like it is a known issue and has been fixed but hasn't made it into a new build just yet.
https://github.com/mongoid/mongoid/issues/closed#issue/651
https://github.com/mongoid/mongoid/issues/closed#issue/690
In the meantime I ended up working around the problem by writing a before_save event handler to convert the empty string values to nil. e.g.
before_save :before_save
def before_save
self.tag_id = nil if self.tag_id == ''
end
Its just a workaround and should be unecessary with 2.0.0.rc.8. It will only stop invalid object references being saved, it won't clean up any data that is already in the database.