Getting check_box to work in a Rails form - ruby-on-rails

My objective is to use a check box on the sign-in form to allow the user to choose to stay signed in after browser close. I'm using this code in the sign-in form for the check box (views > sessions > new.html.erb):
<div class="field">
<%= f.check_box :stay_signed_in %> Stay signed in?
</div>
:stay_signed_in is therefore 1 if checked, and 0 if not. I then (attempt to) set a session variable :staysignedin to either true or false depending on the value of :stay_signed_in (in the sessions controller):
def create
session[:staysignedin] = (params[:session][:stay_signed_in] == "1") ? true : false
...
end
There is something wrong with this code. Even when the box is checked and :stay_signed_in is definitely 1, session[:staysignedin] is never set to true. Where am I going wrong?
Edit:
The rest of the sign-in form looks like this:
<%= form_for(:session, :url => sessions_path) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.check_box :stay_signed_in %>
Stay signed in on this computer?
</div>
<div class="actions">
<%= f.submit "Sign in" %>
</div>
<% end %>
Edit: correction: it IS setting session[:staysignedin] to be true or false correctly, so the fault must be elsewhere. The problem is that with 'stay signed in' checked, when I close the browser and reopen it, the user is not still signed in. When I remove the 'stay signed in?' check box on the sign in form and all the relevant code, leaving only the permanent sign-in code, it works fine.
def sign_in(user)
if session[:staysignedin]
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
else
session[:userid] = user.id
end
self.current_user = user
end
def sign_out
if session[:staysignedin]
cookies.delete(:remember_token)
else
session[:userid] = nil
session[:staysignedin] = nil
end
self.current_user = nil
end

What does the rest of your form code look like?
My guess is that :stay_signed_in is not storing to params[:session][:stay_signed_in], but rather params[:something_else][:stay_signed_in] or just params[:stay_signed_in]
If you're running on local WEBrick you can see the parameters that are posted with each request, that will help you make sure you've got the right parameter key.
-EDIT-
Based on your last comment, I would recommend using Devise to handle your authentication logic. It is super-easy to implement, fully Rails 3 compatible, and includes built in code for handling sessions and remembering to stay logged in.
It's probably not worth your time to get stuck for this long on a simple sessions remembering issue when there's such a good plugin available that is lightweight, rock-solid, well-documented etc.
For an intro, see this Railscast.

Related

I can't understand this? (Ruby on Rails)

I'm new to RoR and I am having some trouble understanding some of the code.
I tried looking it up but the results haven't helped me.
Here is the code located in the user controller. (If you need any other code, comment it and I'll update
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params) #I didn't see any parameters in the constructor
if #user.save #Checks if #user was saved?
session[:user_id] = #user.id #Creates a session? What's :user_id and #user_id?
redirect_to'/' #Redirects to http://localhost:8000/
else
redirect_to '/signup' #If all fails go back to signup page
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password)
end
end
This is part of a programming course which failed to explain this to me properly. I'm generally aware that this is for a signup form, but I am having trouble comprehending the create and user_params function processes.
When I'm asking for help I am asking you to lead me through the process of what is happening.
I also need specific help with
params.require(:user).permit(:first_name, :last_name, :email, :password)
#user = User.new(user_params) #I didn't see any parameters in the constructor
user_params is the name of a method. In ruby, you can call a method without writing () after the method name. If you look down at the bottom of the code you posted, you can see the method definition:
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password)
end
end
That method returns something, and that return value is used in the constructor. You can see what the return value is by adding the following to your code:
def create
#user = User.new(user_params)
puts '******'
p user_params
puts '******'
...
...
end
Then look in your server window for the output. You'll see something like:
******
{“first_name"=>”Joe”, “last_name”=>”Smith”, “email”=>”joe_smith#yahoo.com”}
*******
params.require has to do with security. The subject is called strong parameters, which you can read about here:
https://www.sitepoint.com/rails-4-quick-look-strong-parameters/
if #user.save #Checks if #user was saved?
Yes:
By default, save always run validations. If any of them fail the
action is cancelled and save returns false.
session[:user_id] = #user.id #Creates a session? What's :user_id and #user_id?
A session is used to make variables persist from one request to another. A session is like a Hash, and :user_id is just a random key that you are creating in the Hash. You can name the key anything you want, but it should describe the data that you are saving.
#user.id is the value you are saving in the session Hash. The id comes from the user you created here:
#user = User.new(user_params)
I'm generally aware that this is for a signup form, but I am having
trouble comprehending the create and user_params function processes.
First, you use a GET request to display the form for creating a new user--you do that by entering localhost:3000/users/new in your browser. That will display the form. The <form> tag has an action attribute, which specifies the url where the form will send a request accompanied by the data.
If you use your browser's developer tools, you can click on something like Page Source to see the raw html of the form, which will look something like this:
<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
...
...
A POST request that is sent to the url /users is routed to the create action in the UsersController. That's because when you declare a route like:
resources :users
or
resources :photos
Rails uses the chart below to route urls to actions (in this case the urls are routed to actions in the PhotosController):
Note that the url /photos is routed to both the index and the create action. Rails checks whether the request is a GET request or a POST request to determine which action to execute.
For additional information, check out the Rails Guide on routing.
There are two thins going on here. The controller is probably mapped to /users/ path. The controller will direct all POST to create. Similarly, it will direct all GET to index. Which you don't have.
user_params is a function that was created probably as part of your scaffolding. Like rails generate ... In older versions of Rails, it wasn't like this. This allows you to say for the user scope, first_name, last_name, etc are allowed to be submitted via POST. Why is this done? Mostly security. It allows you to whitelisted parameters so that for example user.admin cannot be updated. You can read more about it here.
In your web-app you may want to create and update users' information.
For example, in both your views new.html.erb ( which create new user) and edit.html.erb (which update existing user's information), you will probably render a form to let users type their information (with bootstrap).
<div class='row'>
<div class='col-xs-12'>
<%= form_for(#user, :html => {class: "form-horizontal", role:"form"}) do |f| %>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :first_name,"FName:" %>
</div>
<div class="col-sm-8">
<%= f.text_field :last_name, class: "form-control", placeholder: "Enter username", autofocus: true %>
</div>
</div>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :last_name,"LName:" %>
</div>
<div class="col-sm-8">
<%= f.text_field :last_name, class: "form-control", placeholder: "Enter username" %>
</div>
</div>
<br>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :email, "Email:" %>
</div>
<div class="col-sm-8">
<%= f.email_field :email, class: "form-control", placeholder: "Enter your email" %>
</div>
</div>
<br>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :password, "Password:" %>
</div>
<div class="col-sm-8">
<%= f.password_field :password, class: "form-control", placeholder: "Enter your password" %>
</div>
</div>
<br>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<%= f.submit(#user.new_record? ? "Sign up now!" : "Update your account", class:'btn btn-primary btn-lg') %>
</div>
</div>
<% end %>
<div class="col-xs-6 col-xs-offset-3">
[ <%= link_to 'Cancel request and return to home', root_path %> ]
</div>
</div>
Back to your question:
By doing "params.require(:user).permit(:first_name, :last_name, :email, :password)" will allow the user controller to modify you first_name, last_name, email and password parameter with security.

How does hidden_field_tag works in an reset password form

It's being really hard to understand how a form work with hidden_field_tag in a specific situation. I wish someone would explain me what happens.
It's the form from reset password from railstutorial.
My view is:
<% provide(:title, 'Reset password') %>
<h1>Reset password</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#user, url: password_reset_path(params[:id])) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= hidden_field_tag :email, #user.email %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Update password", class: "btn btn-primary" %>
<% end %>
</div>
</div>
My update action and the strong params method:
def update
if params[:user][:password].empty?
#user.errors.add(:password, "can't be empty")
render 'edit'
elsif #user.update_attributes(user_params)
log_in #user
#user.update_attribute(:reset_digest, nil)
flash[:success] = "Password has been reset."
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:password, :password_confirmation)
end
When access the edit action, the user enter an email an the app send a link to this email, with an activation token, like this path:
/password_resets/9Ij91DFChTeWTitNDVJfYw/edit?email=example%40railstutorial.org
The user open this link and change the password. That is perfectly functional. My question is: if I already have the user from the edit action and doesn't use params[:email] (provided with the hidden_field_tag) explicitly in my update action, why do I need the hidden tag?
Actions are separate from each other. When you first render your password reset form in scope of the edit action, your #user instance variable, being somehow initialized before, is used to supply a value for the hidden email field.
When later user submits the form, its data gets processed by the update action in a completely separate request. This request does not know what happened before, specifically, that the form was originally rendered by the edit action. It also doesn't have access to any of the objects that were there in scope of the edit action.
In order to process the request, your update action code needs to initialize all the objects it needs anew, and that is primarily the #user object.
If current action doesn't know what happened before, how it would know which user record should go to the #user variable? It can find the user by email, this is why you supplied it in the params. Your edit action code made it available for the next request.
From the look of your edit action, there should already be some method in your controller which initializes the #user object before the action code gets executed. Look for before_action callback.
The method probably looks up the user by the email passed in the params. When action itself gets executes, the #user object is already there so it might seem Rails somehow knows how to get it. It doesn't, your controller code makes this happen.
Therefore you need hidden tag to pass context between actions. There are other ways to do that, like using session or cookies, but this way is probably the simplest.

How does rails params are created?

I'm having a trouble when I'm trying to user params.require(...).permit(...)
In my application I received the follow param dic:
{"utf8"=>"✓",
"authenticity_token"=>"Vatzcb5tgTu2+wL1t6Of+FbIK8Ibp+tM03Naai4b2OU=",
"/login"=>{"username_or_email"=>"jonatasteixeira",
"password"=>"[FILTERED]"},
"commit"=>"Save /login" }
I would like to know why the my key received the "/login" name.
My view:
<h1>Login</h1>
<%= form_for(login_path) do |f| %>
<div class="field">
<%= f.label :username_or_email %><br>
<%= f.text_field :username_or_email %>
</div>
<div class="field">
<%= f.label :password %><br>
<%= f.password_field :password %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<%= link_to 'Back', root_path %>
In my controller
class SessionsController < ApplicationController
# GET /login
def new
#user = User.new
end
# POST /login
def create
#user = User.find_by_emai(session_params[:username_or_email]) || User.find_by_username(session_params[:username_or_email])
if #user && #user.authenticate(session_params[:password])
session[:current_user_id] = #user.id
flash[:notice] = 'You are logged in'
else
flash[:notice] = 'Invalid password, username or email'
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def session_params
logger.info :login
params.require("/login").permit(:username_or_email, :password)
end
end
I dont want to use "/login" as key, I would like to use :login. Some one knows how could I adjust it?
Thanks!!
As #Rafal pointed out, you could code your call to form_for like this to get rid of the awkward /login key in your params:
<%= form_for(:login) do |f| %>
Strong parameters are really only for scenarios where you are doing mass assignment on an object. If you were creating the user, for example, then you would probably want to pass the attributes into the new initializer method using strong parameters.
#user = User.new(session_params)
But because you're not doing mass assignment in this case, you can just pass in the values directly without a session_params method:
# POST /login
def create
#user = User.find_by(email: params[:login][:username_or_email]) || User.find_by(username: params[:login][:username_or_email])
if #user && #user.authenticate(params[:login][:password])
session[:current_user_id] = #user.id
flash[:notice] = 'You are logged in'
else
flash[:notice] = 'Invalid password, username or email'
end
end
The whole point of strong parameters is so no one can pass in extra attributes. In your /login scenario, your code is completely in control of the values being handled, so you don't need to worry about it.
Form_For
When you use form_for, Rails expects an object to be passed so it can build a variety of different elements from it:
[The form_for] helper is designed to make working with resources much easier
compared to using vanilla HTML.
The problem is you're passing a route to this method, which I'm surprised actually works.
--
form_tag
You'll be better using a symbol, as recommended by the accepted answer, or by using form_tag, which doesn't require an object:
<%= form_tag login_path do %>
<%= text_field_tag :username_or_email %>
<%= password_field_tag :password %>
<%= submit_button_tag "Go" %>
<% end %>
This will remove the references to the "login" key of your params, and will give you the ability to do this (no need for require):
params.permit(:username_or_email, :password)
Instead of
<%= form_for(login_path) do |f| %>
use
<%= form_for(:login) do |f| %>

Rails Advanced Sign Up Implementation How To?

I am a three week old Rails newbie and I have something that I want to implement but have no idea how to go about it. I'm making an app:
I want a user to enter some sign-up info on the new users view page, then, when they click submit, instead of the user being created and saved in the database right away, instead I want them to be taken to a second webpage where they will be asked for some final verification before they can create their account. Then when they click 'verify' and the verification passes, the account is finally created and saved to the database.
This is hard for me because I only know how to make basic forms, where you enter info, hit submit, and you have a new entry in the database. I don't know how to defer the "user creation" for another webpage, but a friend has mentioned something about http requests, but I still don't know anything. I'll post some of my code so far:
My users_controller new definition:
def new
#user = User.new
#user.websites.build
end
My users_controller create method:
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome!"
redirect_to #user
else
render 'new'
end
end
My users/new.html.erb sign up form:
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<%= render 'shared/error_messages' %>
<%= form_for(#user) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %><br/>
<%= f.label :password %>
<%= f.password_field :password %><br/>
<%= f.label :password_confirmation, 'Confirm Password' %>
<%= f.password_field :password_confirmation %><br/>
<%= f.fields_for :websites do |builder| %>
<%= builder.label :url, 'Website URL' %>
<%= builder.text_field :url %>
<% end %>
<%= f.submit "Sign up", :id => 'submit' %>
<% end %>
I've never asked a question that's just asking for advice like this before, so I'm hoping this is the right place to ask. Any and all help is appreciated.
I think you are trying to create a "multistep" form...
There is a very good railscast about it: http://railscasts.com/episodes/217-multistep-forms?view=asciicast
However, you might face some validation problems, as you need to validate each step individually. So, take a look also here: http://guides.rubyonrails.org/active_record_validations_callbacks.html#conditional-validation
I hope it helps...
You'd better use Devise for user management.
https://github.com/plataformatec/devise
Here's a railscast tutorial.
railscasts.com/episodes/209-introducing-devise
If you're doing multistep, you can always pass information from one page to another. You can store it in a session array, repost it to the other page, or even make a cookie.
Remember to also do every step of this under https, because account creation requires sensitive info.
If Rails is your first I would actually recommend something lower level like PHP so you can understand how everything works before you start doing stuff with a high level framework like rails. MVC is usually not the best first step in web development, even though it is powerful and easier than doing everything from scratch.

How can I get this code to pass when the user is not logged in?

I have this form:
<%= form_for current_user.relationships.build(:followed_id => #profile.user.id) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<div class="follow_button"><%= f.submit "Follow" %></div>
<% end %>
and since it uses current_user it throws an error when the user is not logged in. I want a non-logged in user to be able to see the button, but for it to fail:
before_filter :authenticate
when clicked. How should I change the form code? Seems like I may need to move the relationship.build call to the controller? Or how would I make the button call the authenticate method in my application controller?
I don't think its good practise to call User.new as proposed before. You can always differentiate in your view:
<% if current_user %>
Form goes here
<% else %>
<div class="follow_button">Log in to follow</div>
<% end %>
(or make a second button that leads to sign-in)
You could always add a generic "logged out" user to the system, default to that when no session is present, and then check for that user when the click is handled. That'd give you the kind of flexibility you want without mucking up your model.
how about:
<% user = current_user || User.new %>
<%= form_for user.relationships.build(:followed_id => #profile.user.id) do |f| > <div>
<%= f.hidden_field :followed_id %></div> <div class="follow_button">
<%= f.submit "Follow" %>
</div>
<% end %>
I have pretty much the same relations in my app and it seems to work:
User.new.friendships.build(:friend_id => 4) # =>
<Friendship id: nil, user_id: 0, friend_id: 4, approved: false, canceled: false, marked_as_deleted: false, created_at: nil, updated_at: nil>

Resources