Navbar login form in a Rails web app (with Bootstrap) - ruby-on-rails

I'm making a Rails web app with the limited knowledge I have - mostly from the Hartl Rails Tutorial. I'm also using Bootstrap.
I decided it would be good to have a dropdown login form in the navbar, in addition to the form at '/login'. The form looks nice enough, but I can't get it to work.
Here is my current code for my working, '/login' form:
<%= form_for(:session, url: login_path) do |f| %>
<div class="form-group">
<%= f.label :username %>
<%= f.email_field :username, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<%= f.submit "Log in", class: "btn btn-primary center-block" %>
<% end %>
Here's my code for the non-working navbar form:
<%= form_for(:session, url: login_path, method: :post,
html: { role: "form", id: "navbar-login" }) do |f| %>
<div class="form-group-sm">
<%= f.label :username %>
<%= f.text_field :username, class: 'form-control',
name: 'username', placeholder: 'Username' %>
</div>
<div class="form-group-sm">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control',
id: 'password', name: 'password',
placeholder: 'Password' %>
<%= link_to "Forgot password?", '#' %>
</div>
<%= f.submit "Log in", class: "center-block" %>
<% end %>
And here's my sessions_controller.rb create method:
def create
user = User.find_by(username: params[:session][:username])
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
else
flash.now[:danger] = "That email and password combination isn't
correct."
render 'new'
end
end
The error I get when submitting the form is as follows:
NoMethodError in SessionsController#create
undefined method `[]' for nil:NilClass
The error also points to this line of the create method:
user = User.find_by(username: params[:session][:username])
I guess the answer is pretty simple, but I can't quite figure it out. I'm sure it must be either form_for or the create method that isn't working.
Thanks in advance for any help.

Remove the name attribute from every field in the form.
Rails handles it for you and the way you are naming it is not creating the param that you expect.

Related

How to invoke devise authentication from a different controller?

I am building a movies website. I would like the home page (views/movies/index.html.erb) to display a list of all movies even to visitors who are not signed in. And I would like to provide a login link on the home page which when clicked should invoke the authentication system of devise gem. How do I achieve this?
I provide this link on the home page (views/movies/index.html.erb)
<%= link_to 'Log in', login_path, :class => "btn btn-primary" %>
I have this in my routes.rb file:
get 'login', to: 'devise#new', as: 'login'
I have provided this dummy method in movies_controller.rb
def login
end
This is the new session (login) code generated by devise in /views/devise/sessions/new.html.erb
<header>
<h1>
Log in
</h1>
</header>
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.label :email %> <%= f.email_field :email, autofocus: true, class: "form-control" %>
<%= f.label :password %> <%= f.password_field :password, autocomplete: "off", class: "form-control" %>
<% if devise_mapping.rememberable? -%>
<%= f.check_box :remember_me %> Remember Me
<% end -%> <%= f.submit "Log in", class: "btn btn-primary btn-lg" %>
<% end %>
<%= render "devise/shared/links" %>
If I somehow invoke /views/devise/sessions/new.html.erb, would that solve my problem?
If yes, then how can I invoke this erb from movies_controller?
If no, then how else can I solve my login problem?

Rails/Devise: pass param after sign_in

In my app I use Devise for authentication. Users can be invited to sign_in to the app through a link that has a token attached as a param.
The link looks e. g. like this:
https://chaos-jadz.c9users.io/tokens/?token_value=88042c1c-822e-4e80-b911-3c25a41fdc3f
At the moment once a user signs in the app redirects to the root path.
What I want to do now is: once a user signs in and if token_value is present then I want the app to redirect to a specific controller/action with the token as param.
I'm aware of the after_sign_in_path method Devise provides. Redirecting after sign_in to my specified controller/action is no problem. However I am not aware how to pass the param token_value also to the controller/action.
This is my sign_in form (I am using the param here as a hidden field):
<div class="panel panel-default devise-bs" style="font-family:arial">
<div class="panel-heading">
<h4><%= t('.sign_in', default: 'Sign in') %></h4>
</div>
<div class="panel-body">
<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { role: 'form' }) do |f| %>
<div class="form-group">
<%= f.label :spielername %>
<%= f.text_field :username, autofocus: true, class: 'form-control', placeholder: "player101" %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, autocomplete: 'off', class: 'form-control' %>
</div>
<div class="form-group">
<%= f.hidden_field :token, :value => params[:token_value], class: 'form-control' %>
</div>
<% if devise_mapping.rememberable? %>
<div class="checkbox">
<%= f.label :remember_me do %>
<%= f.check_box :remember_me %> <%= t('.remember_me', default: 'Remember me') %>
<% end %>
</div>
<% end %>
<%= f.submit t('.sign_in', default: 'Sign in'), class: 'btn btn-primary' %>
<% end %>
</div>
</div>
<div class="col-xs-12 shared-links">
<%= render 'devise/shared/links' %>
</div>
Can you help?
I was facing a similar, if not identical, problem trying to pass params from a Devise registration form through the default auto-login via after_sign_in_path_for(resource). The goal was to route a new user to the page from which they had originally clicked the "Sign up" button. (It's an events app, and the user should be sourced back to the event they came to sign up for.)
I got it working by including a hidden form field as you did, and making sure it was permitted by including this in my ApplicationController:
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:event_token])
end
Then I just referenced resource.event_token in the after_sign_in_path_for(resource) block:
def after_sign_in_path_for(resource)
if resource.event_token
event_path(Event.find_by(token: resource.event_token))
else
user_path(resource)
end
end
So if a user signs in with an event token, it fires; if not, it doesn't.
I imagine you could do the same thing with resource.token to pass your params forward inside the path helper.
if you have specific url for that controller/action then below code will work
def after_sign_in_path_for(current_user)
specific_url(token: params["user"]["token"])
end

I can't implement un-clickable text_fields in Rails

I have an application that I have been working on and have everything wired up to my liking but was wondering if this is possible:
I am displaying a users username in an edit.html.erb template. I want it to display the users username inside of the <%= f.text_field :username, :class=> "uneditable-input" %>. I am using Bootstrap and in the documentation, it states to add a class of uneditable-input, when I hove rover the username text field, it shows a little white stop sign but I am still able to click on the field and edit it. Any help?
<%= render 'shared_partials/errors', errors_object: #user %>
<div class="page-header">
<h2> Edit Your Profile<small> - <%= #user.username %></h2></small>
</div>
<div class="well">
<%= form_for #user do |f| %>
<%= f.label :username %>
<%= f.text_field :username, :class=> "uneditable-input" %>
<%= f.label :password %>
<%= f.password_field :password, :class=> "input", :placeholder=>"Password goes here" %><br/>
<%= f.submit "Update Changes", class: 'btn btn-primary' %>
<% end %>
</div>
Make the field disabled.
<%= f.text_field :username, :class=> "uneditable-input", :disabled => true %>
While submitting the form, browser will not send the value for the field username and thats correct, why it should be sent if it is un-editable.

trouble converting from form_for to form_tag

How do I convert this to form_tag? This code is basically from RoR Tutorial by Michael Hartl Chapter 8 Exercise 1
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
I tried something like this
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<% form_tag sessions_path, methods=> :post do %>
<%= label_tag 'email' %><br />
<%= text_field_tag :email, params[:email], :placeholder => "Email" %>
<%= label_tag 'password' %><br />
<%= password_field_tag :password %>
<%= submit_tag 'Sign in' %>
<% end -%>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
But its not displaying the form at all.
Thanks
You need to add an equal sign:
<%= form_tag sessions_path, methods=> :post do %>
However, I wonder why you want to switch to form_tag. form_for has many advantages in my opinion e.g. the form builder.
I am also trying to convert to the form_tag.
Correct Syntax
<%= form_tag sessions_path, :method => 'post' do %>
Incorrect Syntax
<% form_tag sessions_path, methods=> :post do %>
You need to add an '=' to the opening embed tag, change methods to :method, and :post to 'post'
The reasons for using form_for vs form_tag, are discussed in another stack overflow thread.
Another change that needs to be made is in the sessions_controller.rb. The hash passed back wont be recognized by the controller, as it is set up to accept a hash from form_for method. You must remove the first [:session] hash in two lines. Your sessions_controller.rb should look like this,
def create
user = User.find_by(email: params[:email].downcase)
if user && user.authenticate(params[:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
The next will be the code for the Tutorial (Michael Hartl 3.2) Chapter 8 . Exercise 1
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_tag sessions_path, :method => 'post' do %>
<%= label_tag 'email', 'Email' %>
<%= text_field_tag :email, params[:email], :placeholder => "Email" %>
<%= label_tag 'password', 'Password' %>
<%= password_field_tag :password %>
<br>
<%= submit_tag "Sign In" , :class=> "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>

How can I convert this form_tag form into a form_for form in ruby on rails?

I've been trying to figure out how to write a form_for version of this form for my passwords_controller. I have resources :passwords in my routes.rb file. I looked at my login form and even though it doesn't really access the model I still used form_for and it worked. I tried the same thing and I keep getting issues so I'm using the code below and that's working but would really like to know what I'm doing wrong?
<%= form_tag passwords_path, :method => :post do %>
<div id="#emailFieldJoin">
<%= text_field_tag :email, params[:email], :placeholder => "Email" %>
</div>
<div class="actions"><%= submit_tag "Reset Password" %></div>
<% end %>
Something like:
<%= form_for #password do |f| %>
<div id="#emailFieldJoin">
<%= f.text_field :email %>
</div>
<div class="actions"><%= f.submit "Reset Password" %></div>
<% end %>
So in your controller you should create a #password object, probably fill the email from the params and then render this form.
Hope this helps.
Figured it out by studying my sessions_controller and associated view file.
Basically:
<%= form_for :password_reset, :url => passwords_path do |f| %>
<%= f.text_field :email, :placeholder => "Email" %>
<%= f.submit "Reset Password", :disable_with => 'Log In'%>
<% end %>
The first argument is a symbol of your choice.
I used params[:password_reset][:email] to grab these params from my view in my passwords controller.
So the important thing is the first argument passed to the form_for helper.

Resources