How would I store passwords in CouchDB using CouchRest & BCrypt? - ruby

Although, this isn't CouchDB specific, the library I'm using is. I'm using couchrest_model in Ruby to create a User model like this below:
class User < CouchRest::Model::Base
use_database 'sample'
property :_id, String
property :email, String
# property :password
timestamps!
end
I'm confused with password storing here. I'd like to use BCrypt but when I do something like this:
class User < CouchRest::Model::Base
include BCrypt
use_database 'sample'
property :_id, String
property :email, String
property :password, BCryptHash
timestamps!
end
I get told that User::BCryptHash is an uninitialised constant. I of course require the bcrypt library beforehand. Could you help me resolve that BCrypt issue or suggest a different way of storing passwords in CouchDB? I've looked at hashing passwords however I'm not sure how to implement this.

require 'couchrest_model'
class User < CouchRest::Model::Base
include ActiveModel::SecurePassword
use_database 'sample'
has_secure_password
property :username, String
property :email, String
property :password_digest, String
timestamps!
design { view :by_email }
end
User.create(:username => 'rafalchmiel', :email => 'hi#rafalchmiel.com', :password => 'password', :password_confirmation => 'password')
User.create(:username => 'bar', :email => 'hi#bar.com', :password => 'password213', :password_confirmation => 'password213')
User.create(:username => 'foo', :email => 'hi#foo.com', :password => 'password12111', :password_confirmation => 'password12111')
More info as to why this works in this GitHub Issue.

Related

Active admin nested form not working Error: too many arguments for format string

Following is my code block of state Model, SatatImage Model and Active Admin Code. In active admin when I try to create a new record or Edit a --record that time I show an error on production server. but works on my localhost in development mode,
---------Error---------------------------
too many arguments for format string
app/admin/state.rb:49:in `block (2 levels) in '
I am using Ruby 1.9, Rails 3,2, activeadmin (0.6.0)
======State Model===============
class State < ActiveRecord::Base
attr_accessible :name, :code
validates :code, :uniqueness => true
has_one :state_image, :dependent => :destroy
accepts_nested_attributes_for :state_image, :allow_destroy => true
.......
end
==============StatImage Model=============
class StateImage < ActiveRecord::Base
attr_accessible :state_id, :stateimage, :image_name
belongs_to :state
mount_uploader :stateimage, StateUploader
end
=======Active Admin part=================
ActiveAdmin.register State do
.....
form(html:{multipart:true}) do |f|
f.inputs "State Form" do
f.input :name, required:true
f.input :code, required:true
end
#line-49#
f.inputs "StateImage", for:[:state_image, f.object.state_image || StateImage.new] do |p|
p.input :stateimage, :as => :file, :label => "Image"
end
f.buttons :submit
end
end
I am using
f.semantic_fields_for
And Formtastic requires you to wrap ALL inputs in an "inputs" block. So this should be:
f.inputs 'State Image' do
f.semantic_fields_for :state_image, (f.object.state_image || StateImage.new) do |p|
p.inputs do
p.input :stateimage, :as => :file, :label => "Image"
p.input :_destroy, :as => :boolean, :required => false, :label => 'Remove image'
end
end
end
Please try this:
form :html => { :enctype => "multipart/form-data" } do |f|
Also upgrade you activeadmin version to 0.6.6

How do I reference the same Carrierwave uploaded file in multiple Ruby model instances without reprocessing

I have a model that is using Carrierwave as an uploader to upload files to fog storage.
The problem is that when I create say 100 model objects they all upload the same file.
I need the model instances to reference the same uploaded file. A one-to-many relationship where there are many model instances and 1 file.
At the moment the file is an attribute called attachment on my model messages.rb -
class Message < ActiveRecord::Base
attr_accessible :body, :remote_attachment_url, :from, :to, :status, :attachment, :campaign, :version, :user_id, :SmsId, :response, :response_code, :client_id
mount_uploader :attachment, AttachmentUploader
end
I set attachment in my controller when I create a new Message instance in MessagesController.rb -
recipients.each do |value|
#message = Message.new(:attachment => params[:message][:attachment], :campaign => message[:campaign], :version => message[:version], :to => value, :body => body, :status => status, :user_id => current_user.id, :client_id => client.id )
end
I'm using Ruby 2.0, Rails 4
Solution:
I fixed this by pushing my attachment file into a new model then building an association between the message object and the attachment object.
MessagesController:
#attachment = Attachment.create(params[:message][:attachment_attributes])
recipients.each do |value|
#message = Message.new(:campaign => params[:message][:campaign], :version => params[:message][:version], :to => value, :body => params[:message][:body], :status => status, :user_id => current_user.id, :client_id => client.id )
#message.attachment = #attachment
end
Message model:
attr_accessible :attachment_id, :attachment_attributes
belongs_to :attachment
accepts_nested_attributes_for :attachment
Attachment model:
attr_accessible :attached, :remote_attached_url, :attachment_attributes
mount_uploader :attached, AttachmentUploader
If in your model that mounts the carrierwave uploader you have a property:
mount_uploader :attachment, YourUploader
so assuming your new object is created, you should be able to assign the image like this:
newObj.attachment = anotherObj.attachment
newObj.save
Let me know if that works.

Custom password field with devise (ruby)

I'm using a database shared between 2 rails apps.
A webapp using BCrypt and has_secure_password to authenticate user, and my app, an REST API, using Devise to authenticate users. Password hash is the same.
So, I would like to use the field password_digest instead of encrypted_password to authenticate via Devise and I don't know how ! (I'm seeking in the documentation but find nothing). So, I have to copy / paste my password hash from password_digest to encrypted_password yet.
Here my session controller Code :
class SessionsController < Devise::SessionsController
before_filter :ensure_params_exist
def create
build_resource
resource = User.find_for_database_authentication(:email => params[:email])
return invalid_login_attempt unless resource
if resource.valid_password?(params[:password])
#resource.ensure_authentication_token! #make sure the user has a token generated
sign_in("user", resource)
render :json => { :authentication_token => resource.authentication_token, :lastname => resource.lastname, :firstname => resource.firstname, :last_sign_in => resource.last_sign_in_at }, :status => :created
return
end
invalid_login_attempt
end
#def destroy
# # expire auth token
# #user=User.where(:authentication_token=>params[:auth_token]).first
# #user.reset_authentication_token!
# render :json => { :message => ["Session deleted."] }, :success => true, :status => :ok
#end
protected
def ensure_params_exist
return unless params[:email].blank?
render :json=>{:success=>false, :message=>"missing email parameter"}, :status=>422
end
def invalid_login_attempt
warden.custom_failure!
render :json => { :errors => ["Invalid email or password."] }, :success => false, :status => :unauthorized
end
end
And then my User Model
class User < ActiveRecord::Base
before_save :ensure_authentication_token
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :trackable, :token_authenticatable#, :registerable,
#:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :client_id, :firstname, :group_id, :lastname, :password, :password_confirmation, :role_id, :group_ids, :auth_token, :password_digest, :encrypted_password
# Relations dans la base de données
belongs_to :client
belongs_to :role
has_many :memberships
has_many :groups, :through => :memberships
end
I am not aware about how BCrypt/has_secure_password works, but you can either
use virtual attributes as follows
def encrypted_password
return password_digest
end
def encrypted_password= value
return password_digest
end
Or even better, use alias methods
set encrypted_password and encrypted_password= as alias methods for password_digest and password_digest=.
I think the best way to get this work is to use alias_attribute. This problem might be resolved a long time ago but I still want to come up with this.
alias_attribute :encrypted_password, :password_digest

undefined method `password_hash' error with datamapper

I'm trying to build [Ryan Bates' "authenticaion from scratch"][1] using sinatra but authentication does not work. I get a "undefined method password_hash" error.
Everything else is working. I checked datamapper documentation, especially for lazy loading, but couldn't find anything useful. The code is below. What mistake am I doing?
main.rb (only relevant part)
post "/login" do
user = User.authenticate params[:email], params[:password]
if user
session[:user_id] = user.id
redirect "/"
else
session[:errors] = "No such user or bad password."
redirect "/login"
end
end
user.rb
require 'data_mapper'
require 'dm-validations'
require 'bcrypt'
module Kimsin
DataMapper.setup :default, 'sqlite3:///home/barerd/RProjects/kimsin/users.db'
class User
attr_accessor :password, :confirm_password
include DataMapper::Resource
property :id, Serial
property :email, String, :required => true, :unique => true, :format => :email_address,
:messages => { :presence => "We need your email address.", :is_unique => "We already have that email.", :format => "Doesn't look like an email adress.."}
property :password_salt, String
property :password_hash, String, :length => 80
validates_presence_of :password, :confirm_password, :messages => { :presence => "You have to type a password and confirm it." }
validates_format_of :password, :confirm_password, :with => /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])([\x20-\x7E]){8,40}$/, :messages => { :format => "The password should be 8 to 40 characters long and contain at least one digit, one lowercase and one uppercase letter and one special character." }
before :save, :encrypt_password
def self.authenticate email, password
user = User.all :email.like => email
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password != nil
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret password, password_salt
end
end
end
DataMapper.finalize
end
Adding a attr_reader :password_hash solved it.

Validate uniqueness on combined fields in DataMapper

I want to be able to put entries in my database where the manufacturer will be represented multiple times but not the same combination of manufacturer and model.
So "Sony(manufacturer), Tv(model)" is okay "Sony(manufacturer), OtherTv(model)" but the third entry "Sony(manufacturer), Tv(model)" is not okay since the combination of manufacturer and model is not unique. I tried with the :key => true validation but it doesn't seem to work. And I cannot do something like validates_uniqueness_of :manufacturer AND :model I guess. So how do you do it?
class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :key => true
property :model, String, :key => true
validates_uniqueness_of :
end
You can actually go with:
class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :unique_index => :manufacturer_model
property :model, String, :unique_index => :manufacturer_model
validates_uniqueness_of :model, :scope => :manufacturer
end
This will also give you a unique index in the database.
Nevermind.
It seems this did the job:
class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :unique_index => true
property :model, String, :unique_index => true
validates_uniqueness_of :model, :scope => :manufacturer
end
class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :unique_index => :manufacturer_model
property :model, String, :unique_index => :manufacturer_model
validates_is_unique :model, :scope => :manufacturer
end
I needed to modify the example to use "validates_is_unique" to get this to work.
If you remove the property :id Serial line, you will end up with a composite key (Manufacturer, Model), that will not allow duplicate Models for a particular Manufacturer.

Resources