Ruby on rails get id from instance variable - ruby-on-rails

I have an instance variable #user
so in HTML <%=link_to #user %> gives me the result:
{"id"=>2, "restaurant"=>"sea food", "password"=>"123", "name"=>"a", "email"=>"a", "telephone"=>"123", "created_at"=>"2016-10-09T04:00:24.010Z", "updated_at"=>"2016-10-09T04:00:24.010Z"}
I want to get the value of id, but when I write:<%=link_to #user[:id] %> it returns me the result :/restaurant/home, which is the route of my home function inside my restaurant controller and I can't understand why.
This is my controller:
class RestaurantController < ApplicationController
def home
#user = session['loginedUser']
end
def login
end
def checkLogin
#user = User.find_by_restaurant(params[:user][:restaurant])
if #user != nil && #user[:password] == params[:user][:password]
session['loginedUser'] = #user
redirect_to :controller=>'restaurant',:action=>'home'
else
session['loginedUser'] = nil
# redirect_to :controller=>'restaurant',:action=>'login'
end
end
def logout
session['loginedUser'] = nil
redirect_to :controller=>'restaurant',:action=>'home'
end
end
Can anybody help?
Thanks a lot.

You should not save complex objects within your session object. Session data is saved within a cookie by default and many browsers accept only cookies until 4kB. Other issues exists too.
I suggest this change:
def checkLogin
...
session['loginedUser'] = #user.id
...
end
def home
#user = User.find session['loginedUser']
end
Your link to should look like this
<%=link_to id: #user.id %>. This solution is not realy Rails like. There should be an appropriate helper. You can check your routes with rake routes | grep home. You will see something like xxx_xxx_home_xxx_restaurant /restaurant/home(.format) restaurant#home. The first part is the helper name and you can add _path or _url. This may look like <%=link_to xxx_xxx_home_xxx_restaurant_path id: #user.id %>

Related

Login/signup function not working, #current_user not working, sessions not working

I'm new to Rails, and am working on a practice app that involves a simple login function. I've been following a tutorial from CodeAcademy by the books, however the code is not working in quite a few ways. First of all, the sessions do not set, even though Rails is executing the rest of the code inside the "if" block shared with the session declaration (btw, no errors are returned).
The session controller:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_username(params[:session][:name])
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/posts'
else
session[:user_id] = nil
flash[:warning] = "Failed login- try again"
redirect_to '/login'
end
end
def destroy
session[:session_id] = nil
redirect_to login_path
end
end
Extrapolating from that issue, my "current_user" function is not working, which is most likely because the session is not being set.
The application controller:
class ApplicationController < ActionController::Base
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def require_user
redirect_to '/login' unless current_user
end
end
Any help is much appreciated. Let me know if you need to see anything else.
NOTE: I know I should use Devise, and I am planning to in my future, more serious projects. However, like I said, this is a practice/test app to help develop my coding skills, and before using a "magical" gem like Devise I want to get hands-on experience with making a login system myself.
I think the error is that session_controller is not able to find the current_user.
Write the following code in application_controller:
class ApplicationController < ActionController::Base
helper_method :current_user
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def require_user
redirect_to '/login' unless current_user
end
end
Letme know if it works
There are a few possible problems.
First, #current_user is not set until the current_user method is called. And as #Neha pointed out, you'll need to add a helper method to your ApplicationController so that all your views will have access to the current_user method. Add this line to your ApplicationController:
helper_method :current_user
Now, to diagnose the problem, let's set something up that lets you get some visibility into your session and current_user.
First, in views/layouts/application.html.erb, just after the line that says <= yield %>, add this:
<%= render 'layouts/footer' %>
Then add a new file views/layouts/_footer.html.erb:
<hr/>
Session:<br/>
<% session.keys.each do |key| %>
<%= "#{key}: #{session[key]}" %><br/>
<% end %>
<br/>
User:<br/>
<%= current_user&.username || '[None]' %>
Now at the bottom of every view you can see the details of your session.
In your sessions#create action, you have a potential problem with finding your User. You are using params[:session][:name] where you probably should be using params[:session][:username].
Also, tangentially, the proper way to destroy a session is not by setting session[:id] to nil, but instead to use reset_session. So your SessionsController should look like this:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_username(params[:session][:username])
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/posts'
else
session[:user_id] = nil
flash[:warning] = "Failed login- try again"
redirect_to '/login'
end
end
def destroy
reset_session
redirect_to login_path
end
end

Redirecting the user to the same page after login (Rails)

I want to redirect the user to the same page after login. The scenario is that the user will be redirected to a signin page if he is not logged in. On the signin page, when he clicks on one of the available user options, I want to store the user_id and then redirect him back to the same page where he came from.
For this, I'm using the following code:
In application_helper.rb:
module ApplicationHelper
def check_signed_in
if session[:user] == nil
if request.format.html?
session[:referer] = request.url
redirect_to signin_index_path
else
#error = 'Please Signin!'
#forward_page = '/signin'
render 'signin/show_signin.js'
end
end
end
end
In SigninController:
class SigninController < ApplicationController
def index
session[:user] = params[:user_id]
redirect_to session[:referer]
end
end
In signin/index page:
We simulate a signin here. Click on an user and you will logged in as the selected user and you will be redirected the previous page.
<%= link_to 'Sam', controller:"signin", action: "index" , user_id: 284542812, remote: true %>
<%= link_to 'Marge', controller:"signin", action: "index" , user_id: 604700687, remote: true %>
Error that I'm getting:
the user_id is not being saved and while redirecting I get an error saying that session[:referer] is nil.
Please explain what am I doing wrong
You are calling it async if request.format.html? then asking a format is html? it returns false. Since it returns false you are not able to store this session session[:referer] = request.url.
Also Rails has redirect_to :back option too. Try this below first, and let me know...
Helper:
module ApplicationHelper
def check_signed_in
if session[:user]
session[:referer] = request.url
end
end
end
Controller:
class SigninController < ApplicationController
include ApplicationHelper
def index
check_signed_in
session[:user] = params[:user_id]
redirect_to session[:referer]
end
end

Rails Create article with other user not current_user

I would like to create an article with other user not current_user and for that I'm saving in a session the id to the other user and I recover this id with a collection in the view to this point everything work fine but when I'm trying to use my helper :selected_user into my articles controller with a if sentence doesn't work here is my code:
def new
if selected_user.present?
#article = selected_user.articles.build state: :step1
render_wizard
else
#article = current_user.articles.build state: :step1
render_wizard
end
end
so, I'm asking if the selected_user.present? I would like to create the article with this user_id but else I would like to create it with the current_user
my create method is:
def create
if selected_user.present?
step = :step1
#article = selected_user.articles.build article_params_step1
#article.state = step.to_s
if #article.save
redirect_to wizard_path(next_step, article_id: #article)
else
render_wizard
end
else
step = :step1
#article = current_user.articles.build article_params_step1
#article.state = step.to_s
if #article.save
redirect_to wizard_path(next_step, article_id: #article)
else
render_wizard
end
end
end
so, yeah when I run my view the controller jump to the else section.
just for clarify my selected_user not return nil but here is the implementation:
selections_controller.rb:
class SelectionsController < ApplicationController
before_action :authenticate_user!
def create
session[:selected_user_id] = params[:user][ :user_id]
redirect_to root_path
end
end
and in my application_controller.rb:
helper_method :selected_user
def selected_user
#selected_user ||= User.find(session[:selected_user_id])
end
and in the view:
<%= form_tag( { :controller => "selections", :action => "create" } , :class => "navbar-form navbar-left") do %>
<%= collection_select(:user, :user_id, User.all, :id, :name, prompt: "Escoge cliente")%>
<%= submit_tag 'Enviar' %>
<% end %>
if I try create an article without select an user from my collection appear this error:
Couldn't find User with 'id'=
but when I select my user from the collection everything works fine. so just I want when I don't select nothing create with the current_user.
Thanks for your time !
Regards !
The reason why you were seeing the error
Couldn't find User with 'id'=
when you haven't selected a user was that the session[:selected_user_id] was nil and your old selected_user with following code was throwing the error.
def selected_user
#selected_user ||= User.find(session[:selected_user_id])
end
User.find method expects either a single id or an array of ids. If you give a single id and if it finds the relevant record in the database then it will returns that instance. If you give an array of ids and if it finds those relevant records in the database, then it will return array of those instances. But if you pass nil to it, then it will through the error Couldn't find User with 'id'= as it won't find a relevant record.
But your updated selected_user implementation:
def selected_user
#selected_user ||= session[:selected_user_id] && User.find_by_id(session[:selected_user_id])
end
is working because, first you are checking for the existence of session[:selected_user_id] value and second you are using User.find_by_id instead of User.find.
User.find_by_id either returns a single instance of the record if it finds it in the database or will return nil if it doesn't find the record. It will never through an error.
Refer to ActiveRecord#find and ActiveRecord#find_by for more info.
I'm not sure why is working and what is the different but my solution for the problem it was to add this to my selected_user method:
def selected_user
#selected_user ||= session[:selected_user_id] && User.find_by_id(session[:selected_user_id])
end
and with that I don't have the nil error and entry to the if statement without errors.

Does directly visiting a url have the same effect as navigating via a link?

I have a voting system which records users' ip addresses, users can only vote once. If the array of votes contains the user's ip address, then the voting link will not be displayed to the user:
show.html.erb
<% if !ip_array.include? request.remote_ip %>
<%= link_to "Vote!", vote_user_path(#user) %>
<% else %>
You've already voted!
<% end %>
users_controller.rb
def vote
#user = User.find(params[:id])
#user.votes = #user.votes + 1
#user.save
end
But couldn't a user just directly go to www.my_website.com/users/:id/vote to bypass this? If so, how can I prevent this?
The way you prevent it is by placing the validation inside the controller action, rather than in (or in addition to) the view.
before_action :ensure_not_voted
def vote
#user = User.find(params[:id])
#user.votes = #user.votes + 1
#user.save
end
protected
def ensure_not_voted
# perform the check and stop on failure
# already_voted is a fake function, replace it with your real check
if already_voted
halt(403)
end
end
For simpler solution, you can add a session token to each user, and check if the ip contains the specific token, like
add a before_filter :auth, :only => [:vote]
def vote
#user = User.find(params[:id])
#user.votes = #user.votes + 1
#user.save
session[:token] = request.remote_ip
end
private
def auth
#ip = session[:token].to_s
if #ip != nil
redirect_to :back
flash[:notice] = "You have already voted"
return false
else
return true
end
end
the user can remove cookies to vote again(few people can), for that case you can save the ip in the db and check against it

Passing parameters into model

Rails 3.0.3
ruby 1.9.2p0
The Problem:
I have a Users table which has many items, the item(s) in turn therefore belongs to the Users.
In my model item.rb i attempt to save the item along with the value for the user.id so i have:
self.User_ID = #user.id
this however give me the error
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
this is causing some confusion that it can't find this as in the show.html.erb that 'wraps' this page <%= #user.id %> displays the correct ID on the page
Many thanks in advance
** EDIT **
The Shorten action is the action upon which i want to parameter to be passed
class ItemsController < ApplicationController
def redirect
#item = Item.find_by_shortened(params[:shortened])
if #item
#redirect_to #item.original
redirect_to #item.original
else
redirect_to :shorten
end
end
def shorten
#host = request.host_with_port
#user = current_user
You need to load the #user model in every action that will require access to it. Having it render properly in the show action will not guarantee it is loaded in the update action.
Usually you need to have something like this in your controller:
class UsersController < ApplicationController
before_filter :load_user, :except => [ :index, :new, :create ]
# ...
protected
def load_user
#user = User.find(params[:user_id] || params[:id])
rescue ActiveRecord::RecordNotFound
render(:text => 'Record not found')
end
end

Resources