I am trying to implement two factor authentication via authy 2FA of twilio using devise-authy gem.
I want to customize the views with three pages for 2FA.
first page - My login page where user enters username and password, on submit it will be redirected to a page
Second page - In this page he can select the 2FA method to receive the code via phone or sms after which he is redirected
Third page - Here he finally enters the code.
I am able to configure the first two pages.
My PROBLEM is that in the third page, where i am setting up the authy form for code verification, I am getting error undefined method id for nil class
<%= verify_authy_form do %>
<legend><%= I18n.t('submit_token_title', {:scope => 'devise'}) %></legend>
<%= label_tag :token %>
<%= text_field_tag :token, "", :autocomplete => :off, :id => 'authy-token' %>
<label>
<%= check_box_tag :remember_device %>
<span><%= I18n.t('remember_device', {:scope => 'devise'}) %></span>
</label>
<!-- Help tooltip -->
<!-- You need to configure a help message. -->
<!-- See documentation: https://github.com/authy/authy-form-helpers#help-tooltip -->
<!-- <%= link_to '?', '#', :id => 'authy-help' %> -->
<%= authy_request_sms_link %>
<%= authy_request_phone_call_link %>
<%= submit_tag I18n.t('submit_token', {:scope => 'devise'}), :class => 'btn' %>
<% end %>
I am getting error in this line verify_authy_form
On inspecting the code of gem i found that i need #authy_id so i tried
<%#authy_id=User.find(session[:user_id]).authy_id%>
in view no still no success.
This is my Users::AuthyCustomController, where i have overridden some of the methods as stated in gem
class Users::AuthyCustomController < Devise::DeviseAuthyController
protected
def after_authy_enabled_path_for(resource)
my_own_path
end
def after_authy_verified_path_for(resource)
my_own_path
end
def after_authy_disabled_path_for(resource)
my_own_path
end
def invalid_resource_path
my_own_path
end
def authentication_sms
end
def authentication_phone
#authy_id=User.find(session[:user_id]).authy_id
# redirect_to user_verify_authy_path
# redirect_to user_verify_authy_path and return
end
end
I have googled, but I was not able to find a solution
I am getting error undefined method id for nil class
This is the form helper
def verify_authy_form(opts = {}, &block)
opts = default_opts.merge(:id => 'devise_authy').merge(opts)
form_tag([resource_name, :verify_authy], opts) do
buffer = hidden_field_tag(:"#{resource_name}_id", #resource.id)
buffer << capture(&block)
end
end
I belive that #resource is nil so when it does #resource.id triggers the error
I believe this form is managed from this controller action
# verify 2fa
def POST_verify_authy
token = Authy::API.verify({
:id => #resource.authy_id,
:token => params[:token],
:force => true
})
if token.ok?
#resource.update_attribute(:last_sign_in_with_authy, DateTime.now)
session["#{resource_name}_authy_token_checked"] = true
remember_device if params[:remember_device].to_i == 1
if session.delete("#{resource_name}_remember_me") == true && #resource.respond_to?(:remember_me=)
#resource.remember_me = true
end
sign_in(resource_name, #resource)
set_flash_message(:notice, :signed_in) if is_navigational_format?
respond_with resource, :location => after_sign_in_path_for(#resource)
else
handle_invalid_token :verify_authy, :invalid_token
end
end
and you can prove that by checking and including the relevant output from rake routes. So maybe you should debug that two pieces of code, the controller action is responsible to feeding #resource to the form
Related
In homepage/index:
<%= form_tag :controller => 'hotels', :method => 'get' do %>
<%= text_field_tag :search, nil, :class => 'search-box'%>
<%= submit_tag "Search", :name=>'btnsearch' %>
<%end%>
In hotels_controller:
def index
#hotels= Hotel.where('hotel_location LIKE ?',"%#{params[:search]}%")
I am new to Rails and I am wondering that how to validate text_field_tag for nil value.Means if no record was found, then display the error message without redirecting to the hotel/index page.
Your question is somewhat paradoxial:
If no record was found, then display the error message without
redirecting to the hotel/index page
What you're asking is to perform the functionality which can only be achieved after you've sent a request to your app, and then display the message without redirecting?
Ajax
You'll probably be best using Ajax (Asynchronous Javascript and XML):
This is a way of sending & receiving requests outside the scope of the typical "HTTP" request (IE without reloading the page). This sounds like what you're looking for, as it will ensure you're able to return the data you want without redirecting to your index view again.
The importance of Ajax is that it provides many HTTP developers with the ability to create much more "organic" interaction structures within their applications (IE not having to reload the page every time you want to do something)
Ajax is very simple to implement - I'd recommend it for you:
--
Search
Here's what I'd do:
#app/assets/javascripts/application.js
$(document).on("ajax:success", "#search", function(status, data, xhr){
$(this).append(data);
});
#config/routes.rb
...
resources :hotels do
get :search, on: :collection
end
#app/views/homepage/index.html.erb
<%= form_tag hotels_search_path, method: :get, id: "search", remote: true do %>
<%= text_field_tag :search, nil, :class => 'search-box'%>
<%= submit_tag "Search", :name=>'btnsearch' %>
<% end %>
This will send a "get" request to your hotels_search path - which will allow you to do the following:
#app/models/hotel.rb
class Hotel < ActiveRecord::Base
def self.search search
results = where('hotel_location LIKE ?',"%#{search}%") if search
if results
return results
else
return "No Records"
end
end
end
#app/controllers/hotels_controller.rb
class HotelsController < ApplicationController
respond_to :js, :json, :html
def search
#hotels = Hotel.search params[:search]
respond_with #hotels, layout: false
end
end
how to validate text_field_tag for nil. if no record was found, then display the error message without redirecting to the hotel/index page.
Looks like you need to validate it on client side. You can checkout bootstrap validator which is really nice for using validations on client side.
If you want to write your own js to handle it then you can do something like this:
$(document).on("click","#your_btn_id",function(e){
var textValue = $(this).closest(".search-box").val();
if(textValue == ""){
e.preventDefault();
alert("Please enter some value");
}
});
Update:
You can also utilize HTML5 validations and won't need any js
<%= form_tag :controller => 'hotels', :method => 'get', :validate=>true do %>
<%= text_field_tag :search, nil, :class => 'search-box', :required => true %>
<%= submit_tag "Search", :name=>'btnsearch' %>
<%end%>
If you don't want to use ajax then you can do:
def index
#hotels= Hotel.where('hotel_location LIKE ?',"%#{params[:search]}%")
if #hotels
#your action
else
flash[:notice] = "Please enter a valid value"
render 'your_form_action'
end
end
Since Rails generates HTML5, I am sure you can leverage its required attribute to have Search text box as a mandatory field on your view page. Like this:
<%= form_tag :controller => 'hotels', :method => 'get' do %>
<%= text_field_tag :search, nil, :class => 'search-box', :required => true %>
<%= submit_tag "Search", :name=>'btnsearch' %>
<%end%>
Just to be assured that your controller doesn't get nil in params[:search], you can change controller's index action with:
before_filter :validate_search, :only => [:index]
def index
#hotels = Hotel.where('hotel_location LIKE ?',"%#{params[:search]}%")
if #hotels.present?
# other operation here!
else
redirect_to :back # will work only when referrer is present!
rescue ActionController::RedirectBackError
redirect_to root_path
end
end
def validate_search
if params[:search].nil?
redirect_to root_path, notice: 'Enter few characters to search!'
end
end
Update
The error was that rails cant find the root_url
Visit <%= link_to root_url, root_url %> and go to your inbox for more info.
for a quick fix and I dont need to sent the user to the root_url just a notification for the user to go to the app. I change the code to this: on the mailbox email views
Visit **messages** and go to your inbox for more info.
Question
I got devise set with my rails 4 app. Im following the example mailboxer-app when I sent the message I get a error:
`error undefined local variable or method `root_url' for #<#<Class:0x007ffe0b881678>:0x007ffe0b068298>`
Stuff I have fix to get it working
Got the form sending message to user with email
user can sent and reply
mark as delete
view inbox,sentbox and trash
this are my steps
install gem -v 0.12.1
rails g mailboxer:install
run migration
use the code from the example app(controller,view,routes)
add to my user.rb acts_as_messageable and
Conversations Controller
before_filter :authenticate_user!
helper_method :mailbox, :conversation
def index
#inbox ||= current_user.mailbox.inbox.paginate(:page => params[:inbox], :per_page => 5 )
#sentbox ||= current_user.mailbox.sentbox.paginate(:page => params[:sentbox], :per_page => 5 )
#trash ||= current_user.mailbox.trash.paginate(:page => params[:trash], :per_page => 5 )
end
def create
recipient_emails = conversation_params(:recipients).split(',')
recipients = User.where(email: recipient_emails).all
conversation = current_user.
send_message(recipients, *conversation_params(:body, :subject)).conversation
redirect_to :conversations
end
form
<%= bootstrap_form_for :conversation, url: :conversations do |f| %>
<%= f.text_field :recipients%>
<%= f.text_field :subject%>
<%= f.text_field :body %>
<div class="form-actions">
<%= f.primary "send" %>
<%= submit_tag 'Cancel', type: :reset, class: 'btn btn-danger' %>
</div>
<% end %>
View
<% #inbox.each do |conversation| %>
<%= conversation.originator.username%>
<%= link_to raw(truncate(strip_tags(conversation.subject), :length => 15)), conversation_path(conversation) %>
<% end %>
Ok got the fix to this problem.
what happen is that the mailboxer mailer was looking for root_url. Rails 4.1 wont generate the views for that just copy the files from the source code and works greate.
and just change that part of the code here.
view/mailboxer/all of this files
message_mailer
notification_mailer
change this
Visit <%= link_to root_url, root_url %> and go to your inbox for more info.
to this
Visit **messages** and go to your inbox for more info.
Thanx to this guy supremebeing7. on the mailboxer issue page
I am working on a simple youtube list app where the user can add videos to the list. I am validating for the presence of the video_id field.
class Track < ActiveRecord::Base
attr_accessible :title, :thumbnail_url, :video_id
validates :video_id, :presence => true
end
i have the following create function defined in my controller:
def create
#fetches the video info, stores it in #trackinfo
if is_url(params[:track][:query])
#trackinfo = getTrackInfo(params[:track][:query])
else
#trackinfo = youTubeQuery(params[:track][:query])
end
#use #trackinfo to create track object
#track = Track.new(#trackinfo)
#tracks = Track.all
#video_ids = Track.pluck(:video_id)
if #track.save
else
render :action=>"index"
end
end
in my index.erb.html i have the following block:
<%= render partial: "error_message" %>
the corresponding _error_message.erb.html just contains the error messages from the validation:
<% if #track.errors.any? %>
<% #track.errors.full_messages.each do |msg| %>
<%= msg %><br>
<% end %>
<% end %>
the problem is when the validation fails, i am not able to see the error message from the rendered view. I logged the messages right before it entered the render index, and was able to see the messages:
from the controller:
if #track.save
else
puts "#{#track.errors.full_messages}" #i am able to see this
render :action=>"index"
end
i dont know what happens during the render causing the error messages not to be displayed, on the server logs it does say that the _error_messages.erb.html has been rendered, but i just dont see anything happen to the page. I feel like i have missed something really obvious. anyone knows what i should do?
Thanks
i think i resolved this issue, but im not sure if my fix is proper. I forgot to mention that on the main index.erb.html i have a search bar and a submit buttom embedded in an ajax form that calls the create function inside the controller
<%= form_tag(#track, :remote=>true, :method => :post, :class => 'new_track') do %>
<%= text_field_tag "track_query", nil, :placeholder => 'enter a query or a link', :id => "search_bar", :name => "track[query]", :size => 30, :required => true %>
<%= submit_tag "add" , :name => 'commit'%>
</p>
<% end %>
i also now have the error div in the same page (I deleted the render partial and just stuck an empty div to be populated in the index.erb.html):
<div id = "error_message">
</div>
in the file create.js.erb, I added the following lines:
<% elsif #track.errors.any? %>
if($.trim($("#error_message").html())==''){
<% #track.errors.full_messages.each do |msg| %>
$('#error_message').hide().append('<%= msg %>');
<% end %>
$('#error_message').fadeIn();
}
$('#search_bar').val('');
it seems that when i remove the render :action=>"index" completely from my create function in the controller, the error messages were able to be displayed on the index page. I was hoping to not put so much processing on the client javascript side and more on the controller side. Is there another way to do this? Still wondering why the render did not render that partial html. is it because the form is ajax and wont render the whole page? i apologize if i dont exactly know what im talking about :)
I have looked around S.O. and other resources on the web and I am finding other questions that are similar to this one but not exactly like mine. I'm sure that there is a response out there that works but I am asking this question for clarification as much as I am asking to find the solution. Sorry if this sounds redundant to other questions but I have yet to find something that definitively answers my question.
I have an app where businesses have a listing page and each of those pages has a section where users can submit comments about that business.
Each business page is handled via a 'merchants_controller' using the 'show' action:
def show
#merchant = Merchant.merchant_link_test(params[:id])
#title = #merchant.name
# used inside maps javascript
#map_height = '290px'
#map_width = '350px'
#user_reviews = Review.where(:merchant_id => #merchant.id).order("created_at....
#user_reviews_count = Review.where(:merchant_id => #merchant.id).count
#user_or_merchant = 'merchant'
#review = Review.new
#average_rating = Review.where(:merchant_id => #merchant.id).average(:rating)
#rounded = round_rating(#average_rating)
#yelp_query = #merchant.yelp_string
#yelp_count = yelp(#yelp_query, 'avg_rating')
#num_of_yelp = yelp(#yelp_query, 'review_count')
end
I have a partial in the 'show' layout that displays a form for submitting comments about that business. The form input is handled via a 'reviews_controller' using the 'create' action:
def create
user = User.find_by_id(current_user.id)
id = user.id
#merchant = Merchant.find(params[:review][:merchant_id])
params[:review].store(:user_id, id)
#review = Review.new(params[:review])
if #review.save
flash[:success] = "Your review was submitted!"
redirect_to #merchant
else
flash[:error] = "There was an error submitting your review"
render :template => 'merchants/show', :locals => { :id => #merchant.id, }
end
end
The form uses the 'form_for' helper and looks like this:
<% if signed_in? %>
<div class = "comment_form">
<%= form_for #review do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<div class = "field">
<div id = "required_rating"> * </div><%= f.label :rating %>
</br>
<%= f.select :rating, [['', ''],['1 star (terrible)', 1],
['2 stars', 2],['3 stars', 3],['4 stars', 4],['5 stars
(bomb.com)', 5]] %>
</br>
</div>
<div class = "field">
<div id = "required_comment"> * </div><%= f.label :comment,
"Comment (limit 1000 characters)" %>
<br/>
<%= f.text_area :comment, :cols => 80, :rows => 6 %>
</div>
<div id = "denotes_text"> * Denotes required field </div>
<div class = "actions">
<%= f.submit "Submit Review" %>
<% end %>
<% else %>
<div class = "sign_in_to_comment">
<%= link_to "Sign in to submit a review of this merchant",
signin_path %>
</div>
</div>
<% end %>
I have a two tables and two models, 'merchants' and 'reviews' that handle the data for the respective resources. My 'routes' file looks like this:
resources :merchants, :only => [ :new, :create, :show ]
match '/merchants/:name', :to => 'merchants#show'
match '/merchants/:id/all', :to => 'comments#all_comments_merchant', :as => :all
match '/merchants/:id/map', :to => 'merchants#map', :as => :map
resources :reviews, :only => [ :create ]
My issue is that when a user submits a comment, if an error is generated via my validations in the model, the error object is passed back to the create action in the 'reviews_controller.' I then want to display that error message on the 'merchant_show_page' but need to pass the error object from the 'reviews_controller' back to the 'merchants_controller.'
From what I have read, it seems like the error object has some 'automagic' functionality when being passed between actions within the same controller. Specifically, it seems like the model knows the action that submitted the data and returns the error object using 'render' without having to initialize any instance variables on the page.
A few of the solutions that I have seen regarding similar questions:
1. Move the form submission action into the 'merchants_controller' and lose the
'reviews_controller' altogether.
2. Use 'redirect_to' instead of 'render' and pass the error object as a variable in the
redirect call.
It seems like there has to be an easy, 'rails way' to do this. Having separate controllers seems to make logical sense and it allows me to keep merchants and reviews as separate resources which, from what I have read, is the proper rails convention I should be shooting for. Is this just an issue where there is not a proper 'rails way' to do it? If so, what other rails convention should I be defaulting to?
Any help that can be given would be much appreciated.
Thanks for your help,
noob :)
I have what seems to be a non-standard signup process:
[welcome! enter your email and password] => [cool, enter a lot more information] => [registered]
I'm having trouble getting rails to recognize that I want to validate only the email and password on page 1, and all the other stuff on page 2.
When the user hits the site, they see my welcome page:
class WelcomeController < ApplicationController
def index
#user = User.new
end
end
<%= form_for(#user) do %>
<div class="formItem">
<%= label_tag(:email, "Your email address:") %>
<%= text_field(:user, :email) %>
<br clear="all" />
</div>
<div class="formItem">
<%= label_tag(:password, "Select a password:") %>
<%= password_field_tag(:password) %>
<br clear="all" />
</div>
<%= submit_tag("Sign up today - it's free and easy!", :class => "submitForm") %>
<% end %>
=
class UsersController < ApplicationController
def create
#user = User.new(params[:user])
if #user.save
redirect_to(edit_user_path(#user, :noticeHeader => true ), :notice => 'Please take a minute and answer these additional questions.')
else
render :action => "welcome/index"
end
end
=
Once they click Sign Up, they see my next page of form fields.
The problem I'm running into is that I validates_presence_of fields that are on both pages, in the user model. Since these fields aren't on the welcome page, I get a "undefined local variable or method" error upon submitting the welcome page. For example, I validates_presence_of :title because I want title to be required, but it's only listed on page 2, so page 1 doesn't validate properly.
Thoughts on how to handle this?
Thanks.
Have a look into one of these plugins/gems where you can create Wizard based forms.
http://ruby-toolbox.com/categories/rails_wizards.html my favourite is "ActsAsWizard"