Enable email lazy registration actionMailer Rails 4 - ruby-on-rails

I am new to Rails and trying to get a example working to register with a confirmation email with Rails 4 and devise. I am using this example:
https://github.com/mwlang/lazy_registration_demos
I created the following files:
initialisers/setup_mail.rb
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "gmail.com",
:user_name => "account#gmail.com",
:password => "passwork",
:authentication => "plain",
:enable_starttls_auto => true
}
/app/mailers/welcome_email.rb
class WelcomeMailer < ActionMailer::Base
def registration_confirmation(user)
mail :to => user, :from => "email#domain.com", :subject => "Subject line"
end
end
/devise/mailer/confirmations_instructions.html.erb
<p>
Welcome #{#email}!
</p>
<p>You can confirm your account email through the link below:</p>
<p>
<%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token) %>
</p>
confirmations_controller.rb
class ConfirmationsController < Devise::ConfirmationsController
# Remove the first skip_before_filter (:require_no_authentication) if you
# don't want to enable logged users to access the confirmation page.
skip_before_filter :require_no_authentication
skip_before_filter :authenticate_user!, except: [:confirm_user]
def update
with_unconfirmed_confirmable do
if confirmable_user.blank_password?
confirmable_user.update_password(params[:user])
if confirmable_user.valid?
do_confirm
else
do_show
confirmable_user.errors.clear # prevent rendering :new
end
else
self.class.add_error_on(self, :email, :password_allready_set)
end
end
render 'devise/confirmations/new' unless confirmable_user.errors.empty?
end
def confirm_user
if confirmation_token && (#confirmable_user = User.find_by(:confirmation_token => confirmation_token))
do_show
else
flash[:error] = "Invalid confirmation token"
redirect_to :unconfirmed
end
end
def show
with_unconfirmed_confirmable do
confirmable_user.blank_password? ? do_show : do_confirm
end
unless confirmable_user.errors.empty?
self.resource = confirmable_user
render 'devise/confirmations/new'
end
end
protected
def confirmation_token
#confirmation_token ||= params["user"] && params["user"]["confirmation_token"] || params["confirmation_token"]
end
def confirmable_user
#confirmable_user ||= User.find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
end
def with_unconfirmed_confirmable
unless confirmable_user.new_record?
confirmable_user.only_if_unconfirmed {yield}
end
end
def do_show
self.resource = confirmable_user
render 'devise/confirmations/show'
end
def do_confirm
confirmable_user.confirm!
set_flash_message :notice, :confirmed
sign_in_and_redirect(resource_name, confirmable_user)
end
end
/devise/registrations/new.html.haml
%h2 Sign up
= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
= devise_error_messages!
%div
= f.label :email
= f.email_field :email, :autofocus => true
%div{style: "margin-top: 25px"}= f.submit "Sign up", class: "btn btn-primary btn-large"
%hr
= render "devise/shared/links"
To trigger the email to be send I need to add
WelcomeMailer.registration_confirmation(#user).deliver
But I have no clue where I need to add this trigger. Do I need to do this in the controller? Or in the view?
Thanks a lot

Managed to fix this issue myself using mailcatcher
Steps to fix:
clone github project lazy_registrations
gem install mailcatcher
add lines to /environments/development.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { :address => "localhost", :port => 1025 }
run mailcatcher
check email using 127.0.0.1:1080
ignore all other code above, just needed a night of sleep :)

Related

Rails, Devise & Omniauth - problems with setup

I am trying (again) to set up authentications with Rails 4, devise and omniauth.
I tried to follow the example in this post: Rails 4, Devise, Omniauth (with multiple providers)
I have these gems installed:
gem 'devise'
gem 'omniauth-google-oauth2'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
gem 'omniauth-linkedin-oauth2'
gem 'oauth2'
I have a user model, and an authentications model.
I have:
User.rb:
has_many :authentications
def disapprove
self.approved = false
end
def approve
self.approved = true
end
SOCIALS = {
facebook: 'Facebook',
google_oauth2: 'Google',
linkedin: 'Linkedin'
}
def self.from_omniauth(auth, current_user)
authentication = Authentication.where(:provider => auth.provider,
:uid => auth.uid.to_s,
:token => auth.credentials.token,
:secret => auth.credentials.secret).first_or_initialize
authentication.profile_page = auth.info.urls.first.last unless authentication.persisted?
if authentication.user.blank?
user = current_user.nil? ? User.where('email = ?', auth['info']['email']).first : current_user
if user.blank?
user = User.new
user.skip_confirmation!
user.password = Devise.friendly_token[0, 20]
user.fetch_details(auth)
user.save
end
authentication.user = user
authentication.save
end
authentication.user
end
def fetch_details(auth)
self.first_name = auth.info.first_name
self.last_name = auth.info.last_name
self.email = auth.info.email
self.image = URI.parse(auth.info.image)
end
Authentication.rb
belongs_to :user
Routes.rb
devise_for :users,
:controllers => {
:registrations => "users/registrations",
:omniauth_callbacks => 'users/omniauth_callbacks',
}
User/registrations_controller
class Users::RegistrationsController < Devise::RegistrationsController
#before_filter :check_permissions , :only => [ :new, :create, :cancel ]
#skip_before_filter :require_no_authentication
def check_permissions
authorize! :create, resource
end
def index
if params[:approved] == "false"
#users = User.find_all_by_approved(false)
else
#users = User.all
end
end
def create
#user = User.new(user_params) #(params[:user])
respond_to do |format|
if resource.save
# Tell the UserMailer to send a welcome email after save
# {#user.send_admin_mail
# #user.send_user_welcome_mail}
format.html { redirect_to(profile_path(#user.profile))}
#, notice: 'We have received your registration. We will be in touch shortly.') }
#format.json { render json: root_path, status: :created, location: #user }
else
#format.html { redirect_to(root_path, alert: 'Sorry! There was a problem with your registration. Please contact us to sort it out.') }
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password )
end
# protected
# def after_sign_up_path_for(resource)
# 'subscribers/new'
# end
end
User/Omniauth_callbacks controller
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# try again following https://stackoverflow.com/questions/21249749/rails-4-devise-omniauth-with-multiple-providers
def all
user = User.from_omniauth(env['omniauth.auth'], current_user)
if user.persisted?
sign_in user
flash[:notice] = t('devise.omniauth_callbacks.success', :kind => User::SOCIALS[params[:action].to_sym])
if user.sign_in_count == 1
redirect_to profile_path(#user.profile)
else
redirect_to root_path
end
else
session['devise.user_attributes'] = user.attributes
redirect_to root_path
end
end
User::SOCIALS.each do |k, _|
alias_method k, :all
end
end
The devise/new registrations view says:
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<div class="row">
<div class="col-md-3 col-md-offset-3">
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="facebookauth">
<%= link_to "Join with Facebook", user_omniauth_authorize_path(:facebook) %>
</div>
<% end -%>
</div>
</div>
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="googleauth">
<%= link_to "Join with Google", user_omniauth_authorize_path(:google_oauth2) %>
</div>
<% end -%>
</div>
</div>
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="linkedinauth">
<%= link_to "Join with LinkedIn", user_omniauth_authorize_path(:linkedin) %>
</div>
<% end -%>
</div>
</div>
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="twitterauth">
<%= link_to "Join with Twitter", user_omniauth_authorize_path(:twitter) %>
</div>
<% end -%>
</div>
</div>
</div>
<div class="col-md-5">
<div class="emailform">
<div class="form-inputs", style="margin-left: 7%">
<%= devise_error_messages! %>
<%= f.input :first_name, :label_html => {:class => 'deviselabels'}, autofocus: true, required: false, :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %>
<%= f.input :last_name, :label_html => {:class => 'deviselabels'}, required: false, :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %>
<%= f.input :email, :label_html => {:class => 'deviselabels'}, required: false, autofocus: false, placeholder: "Please use your work or university address", :input_html => {:maxlength => 55, :size => 40, class: 'lineitemdevise'} %>
<%= f.input :password, :label_html => {:class => 'deviselabels'}, required: false, placeholder: "Minimum 8 characters", :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %>
</div>
<div class="form-actions">
<%= f.button :submit, "Join by email", :class => "dcpb" %>
</div>
<% end %>
</div>
</div>
I have another model called profile.rb.
profile belongs_to user
Problems:
None of this works. When I click on each of the social media login links, the page just jumps to the sign up by email form.
The heroku logs error message says:
(facebook) Authentication failure! invalid_credentials: OAuth2::Error, :
2015-11-03T07:05:48.237549+00:00 app[web.1]: {"error":{"message":"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request","type":"OAuthException","code":100,"fbtrace_id":"HD3mnzmSTEw"}}
When I complete the sign up by email form with an email and password, the user name is recognised (in that the navbar says Hello , but when I go into the rails console, the user is not listed.
Also, when I click on the user name, I get an error which says that profile does not exist. The heroku logs say:
(Couldn't find Profile with 'id'=3)
Is there another step required to make the social media registrations work to create a new user?
MY NEXT ATTEMPT:
I've changed all of the above and tried again, following the approach in the Railscasts videos.
I now use a user model and an authentications model.
In the user.rb, I have:
has_many :authentications, :dependent => :delete_all
def apply_omniauth(omniauth)
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token'])
end
authentication.rb
belongs_to :user
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do | user |
authentication.provider = auth.provider
authentication.uid = auth.uid
authentication.user.first_name = auth.first_name
authentication.user.last_name = auth.last_name
authentication.user.image = auth.info.image
end
end
Authentications_controller:
class AuthenticationsController < ApplicationController
before_action :set_authentication, only: [:destroy]
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
sign_in_and_redirect_user(:user, authentication.user.profile)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
redirect_to user.profile_url
else
user = User.new
user.omniauth(omniauth)
if user.save!
sign_in_and_redirect_user(:user, user.profile)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
def destroy
#authentication.destroy
respond_to do |format|
format.html { redirect_to authentications_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_authentication
#authentication = current_user.authentications.find(params[:id])
end
end
In the routes.rb, I have:
devise_for :users,
:controllers => {
:registrations => "users/registrations",
}
patch '/auth/:provider/callback' => 'authentications#create'
Omniauth.rb
require 'omniauth-facebook'
require 'omniauth-google-oauth2'
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_KEY'],
:scope => 'public_profile', info_fields: 'id,first_name,last_name,link,email',
:display => 'popup',
:client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}
Then when I try this, I get this error:
(facebook) Authentication failure! invalid_credentials: OAuth2::Error, :
2015-11-05T06:4839+00:00 app[web.1]: {"error":{"message":"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request","type":"OAuthException","code":100,"fbtrace_id":"CrvXN22Z"}}
I find the next part of the error message odd because it refers to the callbacks controller which I no longer use (the whole thing is commented out and there is no route for it).
Authentication failure! invalid_credentials: OAuth2::Error, :
2015-11-05T08:24:16.010951+00:00 app[web.1]: Processing by Devise::OmniauthCallbacksController#failure as HTML
2015-11-05T08:24:16.012648+00:00 app[web.1]: Redirected to http://www.dder.com/users/sign_in
A FURTHER ATTEMPT
I have been trying to set up devise with omniauth for more than 1.5 years now. This is my latest attempt (following the Sitepoint tutorial at sitepoint.com/rails-authentication-oauth-2-0-omniauth). I've tried to use this tutorial before and not had any success, so I've made some tweaks to try and adapt it to some aspects of other tutorials on this topic.
I now have:
user.rb
has_many :authentications, :dependent => :delete_all
def apply_omniauth(omniauth)
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token'])
end
authentication.rb
belongs_to :user
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do | user |
authentication.provider = auth.provider
authentication.uid = auth.uid
authentication.user.first_name = auth.first_name
authentication.user.last_name = auth.last_name
authentication.user.image = auth.info.image
end
end
authentications controller
class AuthenticationsController < Devise::OmniauthCallbacksController
before_action :set_authentication, only: [:destroy]
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
sign_in_and_redirect_user(:user, authentication.user.profile)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
redirect_to user.profile_url
else
user = User.new
user.omniauth(omniauth)
if user.save!
sign_in_and_redirect_user(:user, user.profile)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
def destroy
#authentication.destroy
respond_to do |format|
format.html { redirect_to authentications_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_authentication
#authentication = current_user.authentications.find(params[:id])
end
end
registrations controller
class Users::RegistrationsController < Devise::RegistrationsController
#before_filter :check_permissions , :only => [ :new, :create, :cancel ]
#skip_before_filter :require_no_authentication
# before_action :configure_permitted_parameters, if: :devise_controller? # Suggestion from Sitepoint tutorial - not currently implemented because not sure about the difference between this and set params.
def check_permissions
authorize! :create, resource
end
def index
if params[:approved] == "false"
#users = User.find_all_by_approved(false)
else
#users = User.all
end
end
def create
super
session[:omniauth] = nil unless #user.new_record?
end
# THIS IS A SUGGESTION FROM SITEPOINT TUTORIAL
# protected
# def configure_permitted_parameters
# devise_parameter_sanitizer.for(:sign_up) << [:first_name, :last_name]
# end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password )
end
def build_resource(*args)
super
if session[:omniauth]
#user.apply_omniauth(session[:omniauth])
#user.valid?
end
end
end
routes
devise_for :users,
:controllers => {
:registrations => "users/registrations",
:omniauth_callbacks => "authentications"
# :omniauth_callbacks => 'users/omniauth_callbacks',
}
get '/auth/:provider/callback' => 'authentications#create'
I can check these routes with:
rake routes | grep auth
user_omniauth_authorize GET|POST /users/auth/:provider(.:format) authentications#passthru {:provider=>/facebook|linkedin|twitter|google_oauth2/}
user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) authentications#:action
GET /auth/:provider/callback(.:format) authentications#create
new registration partial in the view
<%- if devise_mapping.omniauthable? %>
<div class="twitterauth">
<%= link_to "Join with Twitter", user_omniauth_authorize_path(:twitter) %>
</div>
<% end -%>
I'm really not sure where this path is coming from. Not sure why it's named as it is.
new session partial in the view
<%- if devise_mapping.omniauthable? %>
<div class="twitterauth">
<%= link_to "Login with Twitter", user_omniauth_authorize_path(:twitter) %>
</div>
<% end -%>
Current error:
AbstractController::ActionNotFound at /users/auth/twitter/callback
The action 'twitter' could not be found for AuthenticationsController
Devise comes with an out of the box solution for integration with omniuth. You can checkout these urls:
1. https://www.digitalocean.com/community/tutorials/how-to-configure-devise-and-omniauth-for-your-rails-application
This one shows integration with DigitalOcean but can be extended to others.
2. https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
This one is from devise wiki
Hope it helps
There is a gem called dom that was made exclusively to manage Devise with multiple providers. It makes things deadly simple!
Also, I think you should read these articles. I'm sure you can solve all your questions with them:
Devise OmniAuth: Overview
OmniAuth Managing multiple provaders

Ruby on rails Issue with mailer

hello I' am new at ruby on rails and I am trying to implement an email sender. I would like the email sender to send an email every time somebody types their email. But is not working for some reason, please help me.
class ZipMailer < ActionMailer::Base
default from: "Example#gmail.com"
def zip_email_confirmation(zip_mailer)
recipents zip_mailer
from "Example#gmail.com"
subject "Thanks from Example"
body :zip_mailer => zip_mailer
end
end
ActionMailer::Base.smtp_settings = {
:address =>"smtp.gmail.com",
:port =>587,
:domain =>"gmail.com",
:user_name =>"gmail",
:password =>"12345",
:authentication =>"plain",
:enable_starttls_auto => true
}
def create
#box = Box.new(box_params)
#TO DO: validations. return errors or save
if #box.save
ZipMailer.zip_email_confirmation(#zip_mailer).deliver
ConfirmMailer.box_alert(#box).deliver
session[:box_id] = #box.id
render 'charges/new'
else
render action: 'new'
end
<%= form_tag do %>
<%= email_field(:zip_mailer, :address) %>
<%= submit_tag("sub") %>
<% end %>

Devise edit on custom view without current_password

I am trying to put profile edit capabilities on to a custom '/info' page without needing current_password. It only works when you enter your current_password. Without the current password no error happens but it redirects to the unsuccessful update path specified in the controller.
I have a registrations_controller that overrides the devise one:
class RegistrationsController < Devise::RegistrationsController
def info
#user = current_user
if #user
render :info
else
render file: 'public/404', status: 404, formats: [:html]
end
end
def update
#user = User.find(current_user.id)
successfully_updated = if needs_password?(#user, params)
#user.update_with_password(devise_parameter_sanitizer.for(:account_update))
else
params[:user].delete(:current_password)
#user.update_without_password(devise_parameter_sanitizer.for(:account_update))
end
if successfully_updated
set_flash_message :notice, :updated
sign_in #user, :bypass => true
redirect_to user_path(current_user)
else
redirect_to user_path(current_user)
end
end
def needs_password?(user, params)
user.email != params[:user][:email] ||
params[:user][:password].present?
end
protected
def after_sign_up_path_for(resource)
'/info'
end
def needs_password?(user, params)
user.email != params[:user][:email] ||
params[:user][:password].present?
end
end
application_controller:
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :email, :password, :password_confirmation, :image) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:name, :email, :current_password, :password, :password_confirmation, :image) }
end
routes.rb:
devise_for :users, :controllers => { :registrations => "registrations" }
devise_scope :user do
get "/info" => "registrations#info"
end
info.html.erb:
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put}) do |f| %>
<%= f.error_notification %>
<%= f.input :image %>
<%= f.submit "Update", class: "button5"%>
<% end %>
If you don't want it to require the password, you could either get rid of the if needs_password? / else code and just use update_without_password all the time -- or you could define needs_password? to always return false.
Note: your needs_password? method is defined twice in your sample code.

Is attr_accessor the issue with this contact form in Rails 4?

First off, i know attr_accessible is deprecated in Rails 4, but what about attr_accessor?
When you hit submit it's returning a "Template is Missing" error, but that's because its hitting an error somewhere in the send proccess then just trying to return "connect#create" which doesn't exist as a physical page.
When i check the log files, I am getting a 500 internal server error when trying to send a contact form, and I'm not sure if using attr_accessor in Rails 4 is the culprit. Is there a newer way to write this?
class Message
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :phone, :subject, :company, :title, :market, :body
validates :name, :email, :subject, :company, :body, :presence => true
validates :email, :format => { :with => %r{.+#.+\..+} }, :allow_blank => true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
The above is the message model for the contact form:
Is it something within the process of sending the data?
The rest of the code for the contact mail functionality is:
Contact Mailer
class ContactMailer< ActionMailer::Base
default :from => "noreply#test.com"
default :to => "{{MY EMAIL}}"
def new_message(message)
#message = message
mail(:subject => "Test Message")
end
end
In /views/contact_mailer/ there is a new_message.text.erb file:
Name: <%= #message.name %>
Email: <%= #message.email %>
Phone: <%= #message.phone %>
Subject: <%= #message.subject %>
Company: <%= #message.company %>
Title: <%= #message.title %>
Market: <%= #message.market %>
Body: <%= #message.body %>
My Routes are:
match 'connect' => 'connect#index', :as => 'connect', :via => :get
match 'connect' => 'connect#create', :as => 'connectpost', :via => :post
The connect page controller:
class ConnectController < ApplicationController
def index
#message = Message.new
end
def create
#message = Message.new(params[:message])
if #message.valid?
NotificationsMailer.new_message(#message).deliver
redirect_to(connect_path, :notice => "Message was successfully sent.")
else
flash.now.alert = "Please fill all fields."
render :new
end
end
end
And finally....the SMTP settings in /config/initializers/smtp_settings.rb
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "{{SITE DOMAIN}}",
:user_name => "{{GMAIL EMAIL}}",
:password => "{{GMAIL EMAIL PASSWORD}}",
:authentication => "plain",
:enable_starttls_auto => true
}
My ConnectController#Create was trying to initialize
NotificationMailers.new_message()
But it needed to be:
ContactMailer.new_message()
I have no idea why the tutorial I followed would have the wrong class name there...but that was the issue.
Thanks all.
attr_accessor, attr_writer and attr_reader are all part of vanilla core Ruby and are helper methods for Modules and Classes.
They work fine in Ruby 2.0, so you'll have to mark them off your suspect list.

new find view is being processed as new create request

I had a question earlier on this, I am trying to make a ldap search form.
So far I did rails generate for users/find. In the model I have a function to search a user in ldap, which works fine independently outside of rails.
but the request through this view is actually getting treated as a request to create a new user, instead to just search the user in ldap.
I am new to rails, dont what the missing link is. Need some help here understanding this, in future there will be a lot of functions/features like this I have to add in this test app. Which I think will probably lead to the same issue.
# rails generate controller users find
error -
undefined method `gsub' for nil:NilClass
Started GET "/users/find" for 10.85.41.23 at 2012-04-05 19:56:27 -0400
Processing by UsersController#find as HTML
Completed 500 Internal Server Error in 15ms
NoMethodError (undefined method `gsub' for nil:NilClass):
app/models/user.rb:54:in `FindActiveDirectory'
app/controllers/users_controller.rb:10:in `find'
Model -
class User < ActiveRecord::Base
attr_accessible :user_id, :firstname, :lastname, :email, :role, :misc, :password
validates_presence_of :user_id, :firstname, :lastname, :email, :role, :on => :create
validates_uniqueness_of :user_id, :email
ROLES = ['Admin','User']
####################
SERVER = '10.10.10.1'
PORT = 389
BASE = 'DC=User,DC=mysite,DC=com'
DOMAIN = 'ldap.mysite.com'
####################
def self.ActiveDirectoryAuthenticate(login, pass)
user = find_by_user_id(login)
if user
nil
else
return false
end
conn = Net::LDAP.new :host => SERVER,
:port => PORT,
:base => BASE,
:auth => { :username => "#{login}##{DOMAIN}",
:password => pass,
:method => :simple }
if conn.bind
return user
else
return false
end
rescue Net::LDAP::LdapError => e
return false
end
def self.FindActiveDirectory(login)
conn = Net::LDAP.new :host => SERVER,
:port => PORT,
:base => BASE,
:auth => { :username => 'admin',
:password => 'adminpass',
:method => :simple }
if conn.bind
conn.search(:base => BASE, :filter => Net::LDAP::Filter.eq( "sAMAccountName", login ),
:attributes => ['givenName','SN','mail'], :return_result => true) do |entry|
entry.each do |attributes, values|
if "#{attributes}" == "sn"
values.each do |value|
puts "Lastname: "+"#{value}"
$lastname = "#{value}"
end
end
if "#{attributes}" == "givenname"
values.each do |value|
puts "Firstname: "+"#{value}"
$firstname = "#{value}"
end
end
if "#{attributes}" == "mail"
values.each do |value|
puts "Email: "+"#{value}"
$email = "#{value}"
end
end
end
end
return true
else
return false
end
rescue Net::LDAP::LdapError => e
return false
end
end
controller -
class UsersController < ApplicationController
def new
#user = User.new
end
def find
#user = User.FindActiveDirectory(params[:user_id])
end
def create
#user = User.new(params[:user_id])
if #user.save
redirect_to users_added_url, :notice => "Signed up!"
else
render "new"
end
end
end
View -
<h1>Users#find</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :Username %><br />
<%= f.text_field :user_id %>
</p>
<p class="button"><%= f.submit %></p>
<% end %>
routes -
rubyapp::Application.routes.draw do
get "users/find"
get "myapp/new"
root :to => "sessions#new"
#root :to => "home#index"
get "sessions/new"
get "users/new"
get "users/added" => "users#added"
get "myapp" => "myapp#new"
get "log_out" => "sessions#destroy", :as => "log_out"
get "log_in" => "sessions#new", :as => "log_in"
get "sign_up" => "users#new", :as => "sign_up"
resources :users
resources :sessions
end
You need another method to handle the data you returned:
the controller:
def find
end
def display_result
#result = User.findActiveDirectory( params[:user_id] )
if #result.empty?
render action: "find", notice: "Could not find a user with id #{params[:user_id]}"
end
end
next step is to add a route to the routes.rb:
get 'users/find'
post 'users/display_result'
now we have to update the view for find:
<h1>Users#find</h1>
<p><%= notice %></p>
<%= form_tag users_display_result_path do %>
<p>
<%= label_tag :Username %><br />
<%= text_field_tag :user_id %>
</p>
<p class="button"><%= submit_tag %></p>
<% end %>
and create the new view for displaying the result (this one is very basic, i guess you need to improve this a lot, but this should give you an idea):
<h1>Users#display_result</h1>
<%= debug #result %>
and last but not least change some stuff in the model:
def self.FindActiveDirectory(login)
conn = Net::LDAP.new :host => SERVER,
:port => PORT,
:base => BASE,
:auth => { :username => 'admin',
:password => 'adminpass',
:method => :simple }
if conn.bind
result = HashWithIndifferentAccess.new
conn.search( :base => BASE,
:filter => Net::LDAP::Filter.eq( "sAMAccountName", login ),
:attributes => ['givenName','SN','mail'],
:return_result => true
) do |entries|
entries.each do |attribute, value|
result[attribute] = value
end
end
return result
rescue Net::LDAP::LdapError => e
return false
end
You will end up in the controller/ view with a variable called #result. This variable is a hash with the attributes as key. So you could do something like this in the view:
<% #result.each do |key,value| %>
<%= key.to_s.normalize + ": " + value.to_s %>
<% end >

Resources