i am new in ruby and like the syntax! But i keep getting this error, can someone tell me why? I did also try to include it with include ActiveModel::Validations without any luck. Getting this "stack level too deep"
class HomeController < ApplicationController
def index
if params[:username]
l = Users.new(:username => params[:username], :password => params[:password], :email => params[:email]).save
z = Users.where(:username => params[:username]).limit(1).last
#debugging = "Howdy" + z[:username] + ""
end
end
end
users model:
class Users < ActiveRecord::Base
validates :username, :presence => true
attr_accessible :email, :password, :username
end
It should be in your model if you are using active record:
validates :username, :presence => true
It should be User < ActiveRecord::Base:
user.rb
class User < ActiveRecord::Base
validates :username, :presence => true #or you can also write as 'validates_presence_of :username'
attr_accessible :email, :password, :username
end
home_controller.rb
class HomeController < ApplicationController
def index
if params[:username]
l = User.new(:username => params[:username], :password => params[:password], :email => params[:email])
if l.save?
flash[:success] = "Valid user"
else
flash[:error] = "Invalid user"
end
z = User.where(:username => params[:username]).limit(1).last
#debugging = "Howdy" + z[:username] + ""
end
end
end
Your model seems ok
Try to change your index action for this:
if params[:username]
user = User.create(:username => params[:username], :password => params[:password], :email => params[:email])
if user.persisted?
#debugging = "Howdy #{user.username}"
else
#debugging = "Error while creating user"
end
end
If the user is not valid User.create will create an User object not persisted in database
Related
I am getting this error in rails console when trying to create new User:
models/user.rb:32: syntax error, unexpected tSTRING_DEND, expecting ')'
..."#{Time.now.utc}--#{password}"})if self.new_record?
Here is my Model:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
email_regex = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :name, :presence => true
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_senstive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
private
def encrypt_password
#generate salt for new user
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}"}) if self.new_record?
#encrypt password; store in encrypted_password
self.encrypted_password = encrypt_password
end
#encrypt with salt
def encrypt(pass)
Digest::SHA2.hexdigest("#{self.salt}--#{pass}")
end
end
I am not sure of the error, but console does point to the parentheses after the --#{password}"})
^
You have an extra } symbol right at the end of the string
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}"}) if self.new_record?
Replace Above Line With This
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}") if self.new_record?
change your method
def encrypt_password
#generate salt for new user
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}") if self.new_record?
#encrypt password; store in encrypted_password
self.encrypted_password = encrypt_password
end
syntax error was on
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}"}) if self.new_record?
it should be
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}") if self.new_record?
you have given a extra '}'
I have an old Rails 2 app where I have a User model that handles profiles of users coming from web and mobile applications. I would like to have 2 separate groups of validations for web and mobile users. I use DEVISE for authentication.
In order to recognize if a user relates to web or mobile, I use an attr_accessor called validation_for_mobile that I set on the controller side, before saving/updating the record.
It appears that some validations, especially the "validates_length_of :password", get executed even if they are inside a block with_options that should not be evaluated.
Inside the User model I have this code:
# WEB VALIDATIONS
with_options :if => "self.validation_for_mobile == false && !self.remote_sync" do |vm1|
vm1.validates_date :birthday, :allow_blank => true
vm1.validates_presence_of :company, :name, :surname, :address, :city, :province, :postal_code, :position, :company_type, :phone, :unless => :is_imported
vm1.validates_format_of :phone, :with => /\A([0-9]+)\Z/i, :message => 'deve contenere solo numeri', :unless => :is_imported
vm1.validates_presence_of :vat, :if => "!imported && !self.script_imported && company_type != 'individuale' && !company_type.blank?"
vm1.validates_presence_of :social_number, :if => "!imported && !self.script_imported && company_type == 'individuale' && !company_type.blank? "
vm1.validates_presence_of :remote_id, :if => "!came_from_user && !imported && !script_imported"
vm1.validates_acceptance_of :privacy_accepted, :privacy_third_part, :accept => true, :allow_nil => false, :unless => :is_imported
vm1.validates_presence_of :login, :email
vm1.validates_email_format_of :email, :message => "email non valida"
vm1.validates_presence_of :remote_sap_code, :remote_as_code, :if => "!came_from_user"
vm1.validates_uniqueness_of :login, :scope => :branch_id, :case_sensitive => false
vm1.with_options :if => :password_required? do |v|
v.validates_presence_of :password
v.validates_confirmation_of :password
v.validates_format_of :password, :with => /^(?=(.*\d){1})(?=.*[a-zA-Z])[0-9a-zA-Z]+$/i, :message => 'solo lettere e almeno 1 numero!'
v.validates_length_of :password, :within => 6..10, :allow_blank => true
end
end
# MOBILE VALIDATIONS
with_options :if => "self.validation_for_mobile == true && !self.remote_sync" do |vm2|
with_options :if => :mobile_validations do |vm2|
vm2.validates_presence_of :company, :vat, :name, :surname, :phone
vm2.validates_format_of :phone, :with => /\A([0-9]+)\Z/i, :message => 'deve contenere solo numeri'
vm2.validates_length_of :vat, :within => 11..15
vm2.validates_presence_of :login, :email, :branch_id
vm2.validates_email_format_of :email, :message => "email non valida"
vm2.validates_uniqueness_of :login, :scope => :branch_id, :case_sensitive => false
vm2.with_options :if => :password_required? do |v|
v.validates_presence_of :password
v.validates_confirmation_of :password
v.validates_format_of :password, :with => /^(?=(.*\d){1})(?=.*[a-zA-Z])[0-9a-zA-Z]+$/i, :message => 'solo lettere e almeno 1 numero!'
v.validates_length_of :password, :within => 1..10, :allow_blank => true
end
end
Every time I try to create a new user from mobile, I expect only the second block of validations to be evaluated, where "validates_length_of :password" is "within => 1..10"
But I receive the error that password is too short (at least 6 chars). And that's the first block!!!
Can you help me?
I also tried to move the conditions of with_options inside a method, like this:
with_options :if => :web_validations
with_options :if => :mobile_validations
but nothing changed.
This is the code I use to test it:
#user = User.new
#user.company = "Testuser"
#user.vat = "123456789012"
#user.name = "Fafag"
#user.surname = "Fafag"
#user.phone = "9182624"
#user.email = "utentest9876#test.it"
#user.login = "Utentest63"
#user.branch_id = 2
#user.password = "TEST1"
#user.password_confirmation = "TEST1"
#user.plain_password = "TEST1"
#user.mobile_signup = true
#user.mobile = true
#user.validation_for_mobile = true # model custom validation
#user.renew_mobile_token!
#user.came_from_user = true
#user.remote_id = 0
#user.confirmed = nil
#user.active = false
if #user.save
return true
else
puts #user.errors.full_messages.inspect
end
Ok, I solved this puzzle!
It seems nested with_options blocks don't inherit the outer condition. So I had to specify the first condition inside the nested with_option block, like this:
with_options :if => :mobile_validations do |vm2|
vm2.validates_presence_of :company, :vat, :name, :surname, :phone
vm2.validates_format_of :phone, :with => /\A([0-9]+)\Z/i, :message => 'deve contenere solo numeri'
vm2.validates_length_of :vat, :within => 11..15
vm2.validates_presence_of :login, :email, :branch_id
vm2.validates_email_format_of :email, :message => "email non valida"
vm2.validates_uniqueness_of :login, :scope => :branch_id, :case_sensitive => false
vm2.with_options :if => [:password_required?, :mobile_validations] do |v2|
v2.validates_presence_of :password
v2.validates_confirmation_of :password
v2.validates_format_of :password, :with => /^(?=(.*\d){1})(?=.*[a-zA-Z])[0-9a-zA-Z]+$/i, :message => 'solo lettere e almeno 1 numero!'
v2.validates_length_of :password, :within => 1..10, :allow_blank => true
end
end
I have sidekiq running and I am getting a NoMethodError undefined method `messages' in my log for the worker. I have everything defined so I am not sure what I am doing wrong.
class UserMessageWorker
include Sidekiq::Worker
def perform(message_id, recipient_id)
message = Message.find(message_id)
user = User.find(recipient_id)
message.read_at = Time.now
old_msg_count = user.messages.count
usermessages = user.received_messages.where("read_at IS NOT NULL").count + user.sent_messages.where("read_at IS NOT NULL").count
if message.save
msg_response_time = message.read_at - message.created_at
readmessages = []
usermessages.each do |um|
if um.read_at != nil
readmessages << um
end
end
response_rate = usermessages/(old_msg_count + 1)
response_time = ((user.average_response_time * old_msg_count)+msg_response_time)/(old_msg_count + 1)
user.update_attributes(:response_rate => response_rate, :average_response_time => average_response_time )
end
end
end
Messages controller:
def show
#reply_message = Message.new
#message = Message.find(params[:id])
if #message.recipient == current_user
UserMessageWorker.perform_async(#message.id, current_user.id)
end
#message.readingmessage if #message.recipient == current_user
end
Messages model:
attr_accessible :subject, :conversation_id, :body, :parent_id, :sender_id, :recipient_id, :read_at,:sender_deleted,:recipient_deleted
validates_presence_of :subject, :message => "Please enter message title"
has_many :notifications, as: :event
belongs_to :conversation, inverse_of: :messages
belongs_to :user
scope :unread, -> {where('read_at IS NULL')}
scope :not_deleted_by_recipient, where('messages.recipient_deleted IS NULL OR messages.recipient_deleted = ?', false)
scope :not_deleted_by_sender, where('messages.sender_deleted IS NULL OR messages.sender_deleted = ?', false)
belongs_to :sender,
:class_name => 'User',
:foreign_key => 'sender_id'
belongs_to :recipient,
:class_name => 'User',
:foreign_key => 'recipient_id'
def reply
new_message.reply_from_user_id = self.id #save the user id of original repost, to keep track of where it originally came from
end
def self.by_date
order("created_at DESC")
end
# marks a message as deleted by either the sender or the recipient, which ever the user that was passed is.
# When both sender and recipient marks it deleted, it is destroyed.
def mark_message_deleted(id,user_id)
self.sender_deleted = true if self.sender_id == user_id
self.recipient_deleted = user_id if self.recipient_id == user_id
(self.sender_deleted > 0 && self.recipient_deleted > 0) ? self.destroy : self.save!
(self.sender_deleted != 0 && self.recipient_deleted != 0)
end
# Read message and if it is read by recipient then mark it is read
def readingmessage
self.read_at ||= Time.now
save
end
# Based on if a message has been read by it's recipient returns true or false.
def read?
self.read_at.nil? ? false : true
end
def self.received_by(user)
where(:recipient_id => user.id)
end
def self.not_recipient_deleted
where("recipient_deleted = ?", false)
end
def self.sent_by(user)
Message.where(:sender_id => user.id)
end
def next(same_recipient = true)
collection = Message.where('id <> ? AND created_at > ?', self.id, self.created_at).order('created_at ASC')
collection.where(recipient_id: self.recipient_id) if same_recipient
collection.first
end
def previous(same_recipient = true)
collection = Message.where('id <> ? AND created_at < ?', self.id, self.created_at).order('created_at DESC')
collection.where(recipient_id: self.recipient_id) if same_recipient
collection.first
end
end
private
def send_notification(message)
message.notifications.create(user: message.recipient)
end
User model:
has_secure_password
attr_accessible :role, :name, :time_zone, :code, :lat, :lon, :city, :age, :age_end, :password_confirmation, :about_me, :feet, :inches, :password, :birthday, :career, :children, :education, :email, :ethnicity, :gender, :height, :name, :password_digest, :politics, :religion, :sexuality, :user_drink, :user_smoke, :username, :zip_code
# this prevented user from registering as I don't have timezone select on user reg form
# validates_inclusion_of :time_zone, in: ActiveSupport::TimeZone.zones_map(&:name)
has_many :photos
has_many :letsgos, dependent: :destroy
belongs_to :default_photo, :class_name => "Photo"
has_many :notifications
has_many :questions
belongs_to :location
belongs_to :zip
has_many :messages
belongs_to :avatar, class_name: 'Photo'
has_many :received_messages, class_name: 'Message', foreign_key: 'recipient_id'
has_many :sent_messages, class_name: 'Message', foreign_key: 'sender_id'
has_many :users, dependent: :destroy
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id", class_name: "Relationship", dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
validates_format_of :zip_code,
with: /\A\d{5}-\d{4}|\A\d{5}\z/,
message: "should be 12345 or 12345-1234"
validates_uniqueness_of :email
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates_uniqueness_of :username
validates_presence_of :username
validates_format_of :username, :with => /\A[a-zA-Z0-9]+\Z/, :message => "should only contain letters or numbers"
validates :password, :presence => true,
:confirmation => true,
:length => {:within => 6..40},
:on => :create
before_create { generate_token(:auth_token) }
ROLES = %w[admin user guest banned]
def received_messages
Message.received_by(self)
end
def unread_messages?
unread_message_count > 0 ? true : false
end
def unread_messages
received_messages.where('read_at IS NULL')
end
def sent_messages
Message.sent_by(self)
end
def deleted_messages
Message.where(recipient_deleted: self)
end
# Returns the number of unread messages for this user
def unread_message_count
eval 'messages.count(:conditions => ["recipient_id = ? AND read_at IS NULL", self.user_id])'
end
Log:
2014-02-05T20:46:24Z 36507 TID-107jr10 WARN: {"retry"=>true, "queue"=>"default", "class"=>"UserMessageWorker", "args"=>[152, 1], "jid"=>"68109564031c679162dda497", "enqueued_at"=>1391632954.347344, "error_message"=>"Mysql2::Error: Unknown column 'messages.user_id' in 'where clause': SELECT COUNT(*) FROM `messages` WHERE `messages`.`user_id` = 1", "error_class"=>"ActiveRecord::StatementInvalid", "failed_at"=>"2014-02-05T20:42:34Z", "retry_count"=>3, "retried_at"=>2014-02-05 20:46:24 UTC}
2014-02-05T20:46:24Z 36507 TID-107jr10 WARN: Mysql2::Error: Unknown column 'messages.user_id' in 'where clause': SELECT COUNT(*) FROM `messages` WHERE `messages`.`user_id` = 1
What does you User model looks like?
EDIT:
You might need to add
usermessages = user.received_messages + user.sent_messages
to you worker and edit the response_rate line to this
readmessages = []
usermessages.each do |um|
if um.read_at != nil
readmessages << um
end
end
response_rate = (readmessages.count)/(old_msg_count + 1)
Let me know if this help. You might need to tweak it a little to work correctly but that should fix it
EDIT:
Or even better i think you can do this
usermessages = user.received_messages.where("read_at IS NOT NULL").count + user.sent_messages.where("read_at IS NOT NULL").count
and edit this line:
response_rate = usermessages/(old_msg_count + 1)
FULL WORKING CLASS:
class UserMessageWorker
include Sidekiq::Worker
def perform(message_id, recipient_id)
message = Message.find(message_id)
user = User.find(recipient_id)
message.read_at = Time.now
old_msg_count = user.received_messages.count + user.sent_messages.count
usermessages = user.received_messages.where("read_at IS NOT NULL").count + user.sent_messages.where("read_at IS NOT NULL").count
if message.save
msg_response_time = message.read_at - message.created_at
response_rate = usermessages/(old_msg_count + 1)
response_time = ((user.average_response_time * old_msg_count)+msg_response_time)/(old_msg_count + 1)
user.update_attributes(:response_rate => response_rate, :average_response_time => average_response_time )
end
end
end
A user can register through Devise.
After the registration a User should be able to connect his
Twitter Account
In the past i used omniauth to get facebook and twitter connect working. But in this particular Situation i need to LINK a twitter account to an existing Devise Account.
Can anyone give me a helping hand on where to start or read, i'm completely clueless.
gems
gem 'omniauth-twitter'
gem 'omniauth-facebook'
gem 'omniauth-linkedin'
in views
<%= check_connection('Facebook')%>
<%= check_connection('Linkedin')%>
<%= check_connection('Twitter')%>
helpers
def check_connection(provider)
if current_user.has_connection_with(provider)
html = link_to disconnect_path(social: provider.downcase), class: "#{provider}-m phone-verified row" do
content_tag :span, 'Verified', class: "verified"
end
else
html = link_to user_omniauth_authorize_path(provider: provider.downcase), class: "#{provider}-m phone-verified row" do
content_tag :span, 'Click to verify', class: "un-verified"
end
end
end
in user model - for you this might be different
devise :database_authenticatable, :registerable, :confirmable, :lockable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable,
:omniauth_providers => [:facebook, :twitter, :linkedin]
has_many :authorizations, :dependent => :destroy
def has_connection_with(provider)
auth = self.authorizations.where(provider: provider).first
if auth.present?
auth.token.present?
else
false
end
end
in routes I have
devise_for :users, :controllers => {:registrations => "users/registrations",
:sessions => "users/sessions",
:passwords => "users/passwords",
:omniauth_callbacks => "users/omniauth_callbacks" #<- this one you need
}
create authorization table - see this link uninitialized constant User::Authorization | omniauth
class CreateAuthorizations < ActiveRecord::Migration
def change
create_table :authorizations do |t|
t.string :provider
t.string :uid
t.integer :user_id
t.string :token
t.string :secret
t.string :first_name
t.string :last_name
t.string :name
t.string :link
t.timestamps
end
end
end
OmniauthCallbacksController /controllers/users/...
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
require 'uuidtools'
def facebook
oauthorize "Facebook"
end
def twitter
oauthorize "Twitter"
end
def linkedin
oauthorize "LinkedIn"
end
def passthru
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
end
private
def oauthorize(kind)
#user = find_for_ouath(kind, env["omniauth.auth"], current_user)
if #user
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => kind
session["devise.#{kind.downcase}_data"] = env["omniauth.auth"]
sign_in_and_redirect #user, :event => :authentication
end
end
def find_for_ouath(provider, access_token, resource=nil)
user, email, name, uid, auth_attr = nil, nil, nil, {}
case provider
when "Facebook"
uid = access_token['uid']
email = access_token['info']['email']
auth_attr = { :uid => uid, :token => access_token['credentials']['token'],
:secret => nil, :first_name => access_token['info']['first_name'],
:last_name => access_token['info']['last_name'], :name => access_token['info']['name'],
:link => access_token['extra']['raw_info']['link'] }
when "Twitter"
uid = access_token['extra']['raw_info']['id']
name = access_token['extra']['raw_info']['name']
auth_attr = { :uid => uid, :token => access_token['credentials']['token'],
:secret => access_token['credentials']['secret'], :first_name => access_token['info']['first_name'],
:last_name => access_token['info']['last_name'], :name => name,
:link => "http://twitter.com/#{name}" }
when 'LinkedIn'
uid = access_token['uid']
name = access_token['info']['name']
auth_attr = { :uid => uid, :token => access_token['credentials']['token'],
:secret => access_token['credentials']['secret'], :first_name => access_token['info']['first_name'],
:last_name => access_token['info']['last_name'],
:link => access_token['info']['public_profile_url'] }
else
raise 'Provider #{provider} not handled'
end
if resource.nil?
if email
user = find_for_oauth_by_email(email, resource)
elsif uid && name
user = find_for_oauth_by_uid(uid, resource)
if user.nil?
user = find_for_oauth_by_name(name, resource)
end
end
else
user = resource
end
auth = user.authorizations.find_by_provider(provider)
if auth.nil?
auth = user.authorizations.build(:provider => provider)
user.authorizations << auth
end
auth.update_attributes auth_attr
return user
end
def find_for_oauth_by_uid(uid, resource=nil)
user = nil
if auth = Authorization.find_by_uid(uid.to_s)
user = auth.user
end
return user
end
def find_for_oauth_by_email(email, resource=nil)
if user = User.find_by_email(email)
user
else
user = User.new(:email => email, :password => Devise.friendly_token[0,20])
user.save
end
return user
end
def find_for_oauth_by_name(name, resource=nil)
if user = User.find_by_name(name)
user
else
first_name = name
last_name = name
user = User.new(:first_name => first_name, :last_name => last_name, :password => Devise.friendly_token[0,20], :email => "#{UUIDTools::UUID.random_create}#host")
user.save(:validate => false)
end
return user
end
end
I've got a form view of an Order model (orders_form.html.erb) with a select option:
<%= f.select :pay_type, PaymentType.array_of_payment_types,
:prompt => 'Select a payment method' %>
PaymentType is another model and .array_of_payment_types is an array created out of the entries in the payment_type_name column, like so:
def self.array_of_payment_types
#array_of_payment_types ||= PaymentType.pluck(:pay_type_name)
end
... from models\payment_type.rb
But I get a proc 'empty?' error:
undefined method `empty?' for #
I hope my problem is clear, it seems like there is an obvious solution but I haven't found one reading other questions so far...
I will update with the relationships in the models...
My models:
payment_type.rb:
class PaymentType < ActiveRecord::Base
attr_accessible :pay_type_name
has_many :orders
validates :pay_type_name, :uniqueness
def self.names
all.collect { |pt| pt.pay_type_name }
end
def self.array_of_payment_types
PaymentType.all.map{ |p| [p.pay_type_name, p.id] }
end
end
order.rb:
class Order < ActiveRecord::Base
attr_accessible :address, :email, :name, :pay_type, :payment_type_id, :cart_id,
:product_id
has_many :line_items, :dependent => :destroy
belongs_to :payment_type
#PAYMENT_TYPES = ['Check','Purchase order','Credit card']
validates :name, :address, :email, :presence => true
validates :pay_type,
:presence => true,
:inclusion => { :in => proc { PaymentType.array_of_payment_types } }
def add_line_items_from_cart(cart)
cart.line_items.each do |item|
item.cart_id = nil
line_items << item
end
end
end
Try using the options_for_select:
# in the view:
<%= f.select :pay_type, options_for_select(PaymentType.array_of_payment_types),
:prompt => 'Select a payment method' %>
# in the PaymentType model:
def self.array_of_payment_types
PaymentType.all.map{ |p| [p.pay_type_name, p.id] }
end
You also need to update your validates statement in the Order model:
validates :pay_type,
:presence => true,
:inclusion => { :in => proc { PaymentType.pluck(:pay_type_name) } }